SpringAOP推导

AOP的推导

假如有一个实现转账的案例

  • 持久层实现
@Repository
public class AccountDaoImpl implements AccountDao {

    @Autowired
    private QueryRunner queryRunner;

    @Autowired
    private TxManager txManager;

    @Override
    public Account findByName(String name) {
        try {
            return queryRunner.query(txManager.getConnection(), "select * from account where name = ?",
                    new BeanHandler<Account>(Account.class), name);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void update(Account account) {
        try {
            System.out.println(txManager.getConnection());
            queryRunner.update(txManager.getConnection(), "update account set balance = ? where name = ?",
                    account.getBalance(), account.getName());

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
  • 业务层实现
@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;

    @Autowired
    private TxManager txManager;

    @Override
    public void transfer(String sourceAccountName, String targetAccountName, Float amount) {
        try {
            //关闭自动提交
            txManager.begin();

            //查询
            Account sourceAccount = accountDao.findByName(sourceAccountName);
            Account targetAccount = accountDao.findByName(targetAccountName);

            //更改
            sourceAccount.setBalance(sourceAccount.getBalance() - amount);
            targetAccount.setBalance(targetAccount.getBalance() + amount);

            //更新
            accountDao.update(sourceAccount);
            int i = 1 / 0;
            accountDao.update(targetAccount);

            //手动提交
            txManager.commit();
        } catch (Exception e) {
            //事务回滚
            txManager.rollback();
        } finally {
            //事务关闭
            txManager.close();
        }
    }
}
  • 事务管理类的实现
//管理事务
@Component
public class TxManager {

    private ThreadLocal<Connection> th = new ThreadLocal<>();

    @Autowired
    private DataSource dataSource;

    //获取Connnection
    public Connection getConnection() throws SQLException {
        Connection connection = th.get();
        if (connection == null) {
            connection = dataSource.getConnection();
            th.set(connection);
        }
        return connection;
    }

    //开启
    public void begin() {
        try {
            getConnection().setAutoCommit(false);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    //提交
    public void commit() {
        try {
            getConnection().commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //回滚
    public void rollback() {
        try {
            getConnection().rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //关闭
    public void close() {
        try {
            getConnection().close();
            th.remove();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
  • 配置文件
<!--注解扫描-->
    <context:component-scan base-package="com.itheima"/>

    <!--dataSource-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///spring_109"/>
        <property name="username" value="root"/>
        <property name="password" value="adminadmin"/>
    </bean>

    <!--queryRunner-->
    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
        <constructor-arg name="ds" ref="dataSource"/>
    </bean>
</beans>
  • 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AccountServiceTest {

    @Autowired
    private AccountService accountService;

    @Test
    public void testTransfer() {
        accountService.transfer("B01", "B02", 1f);
    }
}
以上代码存在的问题

现在事务代码和业务代码严重耦合
我们希望在不改变源代码的基础上
给业务代码添加事务管理的功能

解决问题的方法

使用动态代理

  • 修改的业务层的代码
@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;


    @Override
    public void transfer(String sourceAccountName, String targetAccountName, Float amount) {

        //查询
        Account sourceAccount = accountDao.findByName(sourceAccountName);
        Account targetAccount = accountDao.findByName(targetAccountName);

        //更改
        sourceAccount.setBalance(sourceAccount.getBalance() - amount);
        targetAccount.setBalance(targetAccount.getBalance() + amount);

        //更新
        accountDao.update(sourceAccount);
        int i = 1 / 0;
        accountDao.update(targetAccount);
    }
}
  • 使用动态代理产生一个代理对象
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AccountServiceTest {

    @Autowired
    private AccountService accountService;

    @Autowired
    private TxManager txManager;

    @Test
    public void testTransfer() {

        //代理逻辑
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object obj = null;
                try {
                    //关闭自动提交
                    txManager.begin();
                    obj = method.invoke(accountService, args);
                    //手动提交
                    txManager.commit();
                } catch (Exception e) {
                    //事务回滚
                    txManager.rollback();
                } finally {
                    //事务关闭
                    txManager.close();
                }
                return obj;
            }
        };

        //产生代理对象
        AccountService instance = (AccountService) Proxy.newProxyInstance(
                accountService.getClass().getClassLoader(),
                accountService.getClass().getInterfaces(),
                invocationHandler
        );
        //转账
        instance.transfer("B01", "B02", 1f);
    }
}
动态代理的方式分为两种
  1. jdk动态代理
  2. cglib动态代理
两种种代理的选择

首先创建代理实现时,jdk的速度要高于cglib,所以选择的时候:
1. 当被代理类有接口的时候,选择jdk动态代理,因为他的效率高
2. 当被代理类没有接口的时候,选择cglib动态代理,因为没有办法

总结

在这里插入图片描述

  • 核心业务(转账)和增强业务(事务)同时出现的时候,我们在开发的时候可以分开开发,运行时再进行组装(使用动态代理)
  • 好处:
    1. 逻辑清晰,开发核心业务的时候,不必关注增强业务的代码
    2. 代码复用性高,增强代码不用重复书写

这就是一种AOP的思想
开发时分开开发 运行时组装运行

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值