动态代理回顾完成之后,我们就知道如何在不修改Service层代码的情况下增强其函数的功能,这里的增强就是给函数添加事物管理的功能。

1.还原业务层代码

首先,将所有添加上事务管理的业务层函数都还原为不加事务管理的状态:

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;
    private TransactionManager transactionManager;

    public void setTransactionManager(TransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    public void setAccountDao(AccountDao accountDao){
        this.accountDao = accountDao;
    }

    public List<Account> findAllAccount() {
        return accountDao.findAllAccount();
    }

    public Account findAccountById(Integer id) {
        return accountDao.findAccountById(id);
    }

    public void saveAccount(Account account) {
        accountDao.saveAccount(account);
    }

    public void updateAccount(Account account) {
        accountDao.updateAccount(account);
    }

    public void deleteAccount(Integer id) {
        accountDao.deleteAccount(id);
    }

    //转账方法
    public void transfer(String sourceName, String targetName, Float money) {
        //2.执行操作
        //2.1.根据原账户名查询转出账户
        Account sourceAccount  = accountDao.findAccountByName(sourceName);
        //2.2.根据目的账户名查询转入账户
        Account targetAccount  = accountDao.findAccountByName(targetName);
        //2.3.原账户减钱
        sourceAccount.setMoney(sourceAccount.getMoney() - money);
        //2.4.目的账户加钱
        targetAccount.setMoney(targetAccount.getMoney() + money);
        //2.5.更新原账户
        accountDao.updateAccount(sourceAccount);
        int a = 1/0;
        //6.更新目的账户
        accountDao.updateAccount(targetAccount);
        //3.提交事务
        transactionManager.commit();
    }
}

2.创建代理工厂类

factory包下创建一个名为BeanFactory的类,该类的作用是提供service实现类的代理对象,使用该对象调用service层的代码都会被增强,也就是加上事务管理。

public class BeanFactory {
    private AccountService accountService;
    private TransactionManager transactionManager;

    public final void setTransactionManager(TransactionManager transactionManager){
        this.transactionManager = transactionManager;
    }

    public void setAccountService(AccountService accountService){
        this.accountService = accountService;
    }

    /**
     * 获取service代理对象
     * @return
     */
    public AccountService getAccountService(){
        return (AccountService) Proxy.newProxyInstance(accountService.getClass().getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object rtValue = null;
                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();
                }
            }
        });
    }
}

此时AccountService实现类中的TransactionManager就可以删掉了。

3.改造xml文件

<!--配置service代理对象-->
<bean id="proxyAccountService" factory-bean="beanFactory" factory-method="getAccountService"></bean>

<!--配置BeanFactory-->
<bean id="beanFactory" class="com.eastnotes.factory.BeanFactory">
    <property name="accountService" ref="accountService"></property>
    <property name="transactionManager" ref="transactionManager"></property>
</bean>

<!--配置service对象-->
<bean id="accountService" class="com.eastnotes.service.impl.AccountServiceImpl">
    <!--使用set注入dao-->
    <property name="accountDao" ref="accountDao"></property>
</bean>

此时,容器中就有两个类型一样的AccountService了,一个是纯正的不加事务控制的,另一个是动态代理对象的。这样,我们在测试的时候,就不能使用@Autowired注解自动按类型注入了。还需要使用@Qualifier注解,指定id

4.测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class AccountServiceTest {
    @Autowired
    @Qualifier("proxyAccountService")
    private AccountService accountService;

    @Test
    public void testTransfer(){
        accountService.transfer("wangwu","xiangdong",100f);
    }
}

此时,我们就发现所有业务层的代码被事务管理了。遇到异常会回滚。

5.总结

由此,我们就使用动态代理增强了业务层的代码,使其都加上了事务控制,但是可以看出来配置十分的繁琐,有没有什么更好的办法呢?那就是需要用到Spring的AOP了。