第二部分 AOP面向切片编程
A. 代码冗余与装饰器模式(AOPTest)
一、代码冗余现象
-
为了保证数据库的一致性,我们添加了事务控制,但是这样使得每个数据库操作都要加上重复的事务控制的代码,如下:
@Override public Account findAccountById(Integer id) { try { //1.开启事务 transactionManager.beginTransaction(); //2.执行操作 Account account = accountDao.findAccountById(id); //3.提交事务 transactionManager.commit(); //4.返回结果 return account; }catch (Exception e){ //5.回滚操作 transactionManager.rollback(); }finally { //6.释放连接 transactionManager.release(); } return null; } @Override public void saveAccount(Account account) { try { //1.开启事务 transactionManager.beginTransaction(); //2.执行操作 accountDao.saveAccount(account); //3.提交事务 transactionManager.commit(); }catch (Exception e){ //5.回滚操作 transactionManager.rollback(); }finally { //6.释放连接 transactionManager.release(); } }
-
这会导致两个问题:
- 业务层方法变得臃肿了,里面充斥着很多重复代码(事务控制)
- 业务层方法和事务控制方法耦合高. 若提交,回滚,释放资源中任何一个方法名变更,都需要修改业务层的代码
二、动态代理解决方案
-
我们使用动态代理对上述Service进行改造,创建
BeanFactory
类作为service层对象工厂,通过其getAccountService
方法得到业务层对象/** * @author ajacker * 用于创建Service的代理对象的工厂 */ @Component public class BeanFactory { private final IAccountService accountService; private final TransactionManager transactionManager; public BeanFactory(TransactionManager transactionManager, IAccountService accountService) { this.transactionManager = transactionManager; this.accountService = accountService; } @Bean("proxyAccountService") public IAccountService getAccountService(){ return (IAccountService) Proxy.newProxyInstance(accountService.getClass().getClassLoader(), accountService.getClass().getInterfaces(), (proxy, method, args) -> { Object rtValue; try { //1.开启事务 transactionManager.beginTransaction(); //2.执行操作 rtValue = method.invoke(accountService, args); //3.提交事务 transactionManager.commit(); //4.返回结果 return rtValue; }catch (Exception e){ //5.回滚操作 transactionManager.rollback(); throw new RuntimeException(e); }finally { //6.释放连接 transactionManager.release(); } }); } }
-
将业务层代码恢复到之前没有事务控制的情况:
@Override public List