自定义IOC和AOP的实现思路

本文探讨了如何解决对象耦合问题,通过使用IoC(控制反转)和面向接口编程,实现了Service层与Dao层的解耦。在XML配置中管理Bean并利用工厂方法设计模式创建对象,降低了代码的依赖性。接着,文章详细阐述了如何在Service层添加事务控制以确保数据一致性,通过ThreadLocal维护连接并使用动态代理实现事务管理。动态代理使得事务处理代码与业务逻辑分离,提高了代码的可维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、对象之间耦合的问题

假设代码如下实现,service内部调dao层实现。

public class TransferServiceImpl implements TransferService {
    private AccountDao accountDao = new JdbcAccountDaoImpl();
}

在Service层调上面语句,显然存在对象耦合问题,不符合面向接口编程的规则。假设Dao层接口有了新的实现方式,必须修改service层代码。

如果不用new对象,则需要用反射创建Class.forName。反射需要全限定类名,如果写在上面的代码中,也是耦合。因此要将全限定类名,拿到xml中,或者通过注解来获取。

<bean id="accountDao" class="com.lzp.edu.dao.impl.JdbcTemplateDaoImpl"></bean>
<bean id="transferService" class="com.lzp.edu.service.impl.TransferServiceImpl">
    <property name="AccountDao" ref="accountDao"></property>
</bean>

使用工厂方法设计模式来生成对象。通过全限定类名生成对象,存在BeanFactory工厂对象的Map集合中,以此保证单例。此时需要下面几个操作:

  1. 解析xml
  2. 创建出所有的bean对象,存到map中(反射)
  3. 对有property标签的对象,做属性注入(也是反射)。

做完上面的工作,也就实现基本实现了IOC。

public class TransferServiceImpl implements TransferService {
    //private AccountDao accountDao = new JdbcAccountDaoImpl();
    // private AccountDao accountDao = (AccountDao) BeanFactory.getBean("accountDao");
    // 最佳状态
    private AccountDao accountDao;
}

2、切面逻辑的实现–添加事务控制

假设service层方法有这样两句代码

public void transfer(String fromCardNo, String toCardNo, int money) {
    accountDao.updateAccountByCardNo(to); // A
    int c = 1/0; // 数学异常
    accountDao.updateAccountByCardNo(from); // B
}

如果不加额外的事务控制,必然导致A执行了更新了数据,而B没有执行到,前后数据不一致。原因是A和B两个操作,分别去获取JDBC连接,分别执行数据库操作,然后各自提交了。

通过上面分析,解决事务问题只要当前线程获取同一个连接,关闭自动提交,再所有Service方法所有操作完成后提交事务即可。

对于线程管理连接,使用ThreadLocal作为容器。

private ThreadLocal<Connection> threadLocal = new ThreadLocal<>(); // 存储当前线程的连接

此时就可以在A前面和B后面添加事务控制语句,解决事务控制问题。

public void transfer(String fromCardNo, String toCardNo, int money) throws Exception {
    connectionUtils.getCurrentThreadConn().setAutoCommit(false); // 开启事务(关闭事务的自动提交)
    accountDao.updateAccountByCardNo(to);
    int c = 1/0;
    accountDao.updateAccountByCardNo(from);
    connectionUtils.getCurrentThreadConn().commit();
}

代码中,开启事务、提交事务的代码就是横向逻辑代码,与原来的转账业务没有关系。事务控制用动态代理实现,或是JDK动态代理,或者Cglib等。

给Service类创建代理对象,调用方法时增强。

public Object getJdkProxy(Object obj) {
    // 获取代理对象
    return  Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    Object result = null;
                    try{                     
                        transactionManager.beginTransaction(); // 开启事务(关闭事务的自动提交)
                        result = method.invoke(obj,args);
                        transactionManager.commit(); // 提交事务
                    }catch (Exception e) {                      
                        transactionManager.rollback(); // 回滚事务                 
                        throw e; // 抛出异常便于上层servlet捕获
                    }

                    return result;
                }
            });
}

此时,动态代理添加事务功能也就实现了。期间产生的几个类,也可以通过IOC的方式管理起来。

代码地址:https://gitee.com/dtyytop/devdemos/tree/master/spring/banktransfer/lagou-transfer
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值