赞
踩
接口
public interface IProducer {
void saleProduct(float money);
void afterService(float money);
}
实现类
public class Producer implements IProducer{
public void saleProduct(float money){
System.out.println("厂家销售产品,并拿到钱:" + money);
}
public void afterService(float money){
System.out.println("厂家提供售后服务,并拿到钱:" + money);
}
}
测试方法
/** * @auther Mr.Liao * * 动态代理: * 1、特点:字节码随用随创建,随用随加载 * 2、作用:不修改源码的基础上对方法增强 * 3、分类: * 1.基于接口的动态代理 * 2.基于子类的动态代理 * 4、基于接口的动态代理: * 涉及的类:Proxy * 提供者:JDK官方 * 如何创建代理对象:使用Proxy类中的newProxyInstance方法 * 创建代理对象的要求:被代理类最少实现一个接口,如果没有则不能使用 * * newProxyInstance方法的参数: * 1、ClassLoader:类加载器 * 它是用于加载代理对象字节码的,和被代理对象使用相同的类加载器,固定写法。 * 2、Class[]:字节码数组 * 它是用于让代理对象和被代理对象有相同方法,固定写法 (实现相同的接口) * 3、InvocationHandler:用于提供增强的代码 * 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。 * 此接口的实现类都是谁用谁写。 */ public class Client { public static void main(final String[] args) { // 模拟直接从厂家购买电脑 System.out.println("直接从生产厂家购买电脑"); final Producer producer = new Producer(); producer.saleProduct(10000f); System.out.println("从代理商处购买电脑"); // 使用动态代理创建一个producer对象 IProducer proxyProducer = (IProducer)Proxy.newProxyInstance( producer.getClass().getClassLoader(), producer.getClass().getInterfaces(), new InvocationHandler() { /** * invoke()方法作用:执行被代理类对象所实现的接口里的方法时,都会先执行此方法 * @param object 代理对象的引用 * @param method 当前执行的方法 * @param args 当前执行方法所需的参数 * @return 返回值 和被代理对象要执行的方法有相同的返回值 * @throws Throwable * * method.invoke()方法参数: * 1、被代理对象 * 2、执行被代理对象方法的参数 */ public Object invoke(Object object, Method method, Object[] args) throws Throwable { // 提供增强的方法 Object res = null; //1、获取方法执行的参数 Float money = (Float)args[0]; //2、判断当前方法是不是销售 if ("saleProduct".equals(method.getName())){ res = method.invoke(producer,money*0.8f); } return res; } }); proxyProducer.saleProduct(10000f); } }
执行结果:
"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" "-javaagent:C:\Program
直接从生产厂家购买电脑
厂家销售产品,并拿到钱:10000.0
从代理商处购买电脑
厂家销售产品,并拿到钱:8000.0
Process finished with exit code 0
导入依赖
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_3</version>
</dependency>
</dependencies>
public class Producer { /** * 销售 * @param money */ public void saleProduct(float money){ System.out.println("厂家销售产品,并拿到钱:" + money); } /** * 售后 * @param money */ public void afterService(float money){ System.out.println("厂家提供售后服务,并拿到钱:" + money); } }
/** * @auther Mr.Liao * * 动态代理: * 特点:字节码随用随创建,随用随加载 * 作用:不修改源码的基础上对方法增强 * 分类: * 基于接口的动态代理 * 基于子类的动态代理 * 基于子类的动态代理: * 涉及的类:Enhancer * 提供者:第三方cglib库 * 如何创建代理对象: * 使用Enhancer类中的create方法 * 创建代理对象的要求: * 被代理类不能是最终类 * create方法的参数: * 1、Class:字节码,它是用于指定被代理对象的字节码。 * 2、Callback:用于提供增强的代码 * 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。 * 此接口的实现类都是谁用谁写。 * 我们一般写的都是该接口的子接口实现类:MethodInterceptor */ public class Client { public static void main(String[] args) { final Producer producer = new Producer(); Producer cglibProducer = (Producer)Enhancer.create( producer.getClass(), new MethodInterceptor() { /** * 执行被代理对象的任何方法都会先执行此方法 * @param object * @param method * @param objects * @param methodProxy 当前执行方法的代理对象 * @return * @throws Throwable */ public Object intercept(Object object, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { // 提供增强的方法 Object res = null; //1、获取方法执行的参数 Float money = (Float) objects[0]; //2、判断当前方法是不是销售 if ("saleProduct".equals(method.getName())) { res = method.invoke(producer, money * 0.8f); } return res; } }); cglibProducer.saleProduct(12000f); } }
增加工厂类,负责生产代理对象,对代理对象中的方法进行增强,达到控制事务的目的
/** * @auther Mr.Liao * 用于创建Service的代理对象的工厂 */ public class BeanFactory { private IAccountService accountService; private TransactionManager txManager; public void setTxManager(TransactionManager txManager) { this.txManager = txManager; } public final void setAccountService(IAccountService accountService) { this.accountService = accountService; } /** * 获取Service代理对象 * @return */ public IAccountService getAccountService() { return (IAccountService) Proxy.newProxyInstance(accountService.getClass().getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() { /** * 添加事务的支持 * @param proxy * @param method * @param args * @return * @throws Throwable * method.invoke()方法参数:1、被代理对象,2、被代理对象方法的参数 */ // 整个的invoke方法在执行就是环绕通知 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // test方法没有事物的支持 if("test".equals(method.getName())){ return method.invoke(accountService,args); } Object rtValue; try { //1.开启事务 txManager.beginTransaction(); // 前置通知 //2.执行操作 rtValue = method.invoke(accountService, args);// 在环绕通知中有明确的切入点方法调用 //3.提交事务 txManager.commit(); // 后置通知 //4.返回结果 return rtValue; } catch (Exception e) { //5.回滚操作 txManager.rollback(); // 异常通知 throw new RuntimeException(e); } finally { //6.释放连接 txManager.release(); // 最终通知 } } }); } }
在bean.xml
中配置代理对象proxyAccountService
和工厂类
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--配置代理的service--> <bean id="proxyAccountService" factory-bean="beanFactory" factory-method="getAccountService"></bean> <!--配置beanFactory--> <bean id="beanFactory" class="com.liaoxiang.factory.BeanFactory"> <!-- 注入service --> <property name="accountService" ref="accountService"></property> <!-- 注入事务管理器 --> <property name="txManager" ref="txManager"></property> </bean> <!-- 配置Service --> <bean id="accountService" class="com.liaoxiang.service.impl.AccountServiceImpl"> <!-- 注入dao --> <property name="accountDao" ref="accountDao"></property> </bean> <!--配置Dao对象--> <bean id="accountDao" class="com.liaoxiang.dao.impl.AccountDaoImpl"> <!-- 注入QueryRunner --> <property name="runner" ref="runner"></property> <!-- 注入ConnectionUtils --> <property name="connectionUtils" ref="connectionUtils"></property> </bean> <!--配置QueryRunner--> <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype"></bean> <!-- 配置数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!--连接数据库的必备信息--> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring"></property> <property name="user" value="root"></property> <property name="password" value="123456"></property> </bean> <!-- 配置Connection的工具类 ConnectionUtils --> <bean id="connectionUtils" class="com.liaoxiang.utils.ConnectionUtils"> <!-- 注入数据源--> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事务管理器--> <bean id="txManager" class="com.liaoxiang.utils.TransactionManager"> <!-- 注入ConnectionUtils --> <property name="connectionUtils" ref="connectionUtils"></property> </bean> </beans>
修改AccountServiceImpl
中的多余代码
/** * @auther Mr.Liao */ public class AccountServiceImpl implements IAccountService { private IAccountDao accountDao; public void setAccountDao(IAccountDao accountDao) { this.accountDao = accountDao; } /** * 更新账户 * @param account */ public void updateAccount(Account account) { accountDao.updateAccount(account); } /** * 转账 * @param sourceName 转出账户名称 * @param targetName 转入账户名称 * @param money 转账金额 * 为了防止异常前面方法的执行成功,异常后面的没有执行,下面操作数据库的方法应该只公用一个connection对象 * 需要使用ThreadLocal对象把Connection和当前线程绑定,从而使一个线程中只有一个能控制事务的对象 */ public void transfer(String sourceName, String targetName, Float money) { //1、根据名称查询转出账户 Account source = accountDao.findAccountByName(sourceName); //2、根据名称查询转入账户 Account target = accountDao.findAccountByName(targetName); //3、转出账户减钱 source.setMoney(source.getMoney()-money); //4、转入账户加钱 target.setMoney(target.getMoney()+money); //5、更新转出账户 accountDao.updateAccount(source); // 制造异常 //int i=1/0; //6、更新转入账户 accountDao.updateAccount(target); } }
测试类,使用的是通过工厂方式生产的代理类对象来实现转账功能
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class AccountServiceTest {
@Autowired
@Qualifier("proxyAccountService")
private IAccountService accountService;
@Test
public void testTransfer(){
accountService.transfer("aaa","bbb",100f);
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。