1.简介
基于父类的动态代理技术,动态生成一个要代理的子类,子类重写要代理的类的所有非final修饰的方法。在子类中采用方法拦截技术拦截所有的父类方法的调用,顺势织入横切逻辑,对方法进行增强。
2.生成代理对象
在项目目录“/src/main/java/com/steven/proxy”目录下新建CGLIBProxyFactory类,在类中提供一个创建CGLIB代理对象的方法createCGLIBProxyObject,具体代码如下。
public class CGLIBProxyFactory {
@Autowired
private IAccountService accountService;
@Autowired
private TransactionManager transactionManager;
public IAccountService createCGLIBProxyObject() {
/**
* 采用CGLIB动态代理技术生成目标类的代理对象
* class 代理类的字节码对象,借助被代理类获取
* callback 动作类,当代理对象调用代理对象中原方法时,会执行intercept方法
*/
IAccountService accountServiceProxy = (IAccountService) Enhancer.create(accountService.getClass(), new MethodInterceptor() {
/**
* @param o 生成的代理对象
* @param method 被代理类方法的引用
* @param objects 被代理类方法的入参
* @param methodProxy 代理方法
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
try {
//手动开启事务
transactionManager.beginTransaction();
System.out.println("被代理类对象方法将要被执行");
//让被代理对象的原方法执行
method.invoke(accountService, objects);
System.out.println("被代理类对象方法已经被执行");
//手动提交事务
transactionManager.commit();
} catch (Exception e) {
e.printStackTrace();
//手动回滚事务
transactionManager.rollback();
} finally {
//手动释放资源
transactionManager.release();
}
return null;
}
}
);
return accountServiceProxy;
}
}
3.修改业务层代码
在转账工程基础上,删除业务层的事务控制代码,具体代码如下。
@Service
public class AccountServiceImpl implements IAccountService {
@Autowired
private IAccountDao accountDao;
public void transfer(String outUser, String inUser, Double money) {
accountDao.out(outUser, money);
int i = 1 / 0;
accountDao.in(inUser, money);
}
}
4.将CGLIBProxyFactory交给Spring容器管理
在applicationContext.xml文件中添加如下bean标签。
<bean id="cglibProxyFactory" class="com.steven.proxy.CGLIBProxyFactory"/>
5.编写测试类
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
CGLIBProxyFactory cglibProxyFactory = (CGLIBProxyFactory) context.getBean("cglibProxyFactory");
IAccountService accountService = cglibProxyFactory.createCGLIBProxyObject();
accountService.transfer("steven", "sherry", 100d);
}
}
程序执行成功,查看数据库数据,steven和sherry的10000元数额未发生变化。