【Java高级工程师蜕变之路】009 手写IOC和AOP

传统开发方式的问题分析

image

new关键字耦合问题解决

image

new关键字耦合问题代码实现

beans.xml定义

<?xml version="1.0" encoding="utf-8" ?>
<!-- 配置bean子标签,每一个bean子标签都代表一个类的配置 -->
<beans>
    <!-- id标识对象,class代表类的全路径-->
    <bean id="accountDao" class="com.test.transfer.dao.impl.JdbcAccountDaoImpl"></bean>
    <bean id="transferService" class="com.test.transfer.service.impl.TransferServiceImpl">
        <property name="AccountDao" ref="accountDao"></property>
    </bean>
</beans>

TransferServlet使用

private TransferService transferService = (TransferService) BeanFactory.getBean("transferService");

TransferServiceImpl定义

// 最佳状态
private AccountDao accountDao;

// 构造函数传值/set方法传值
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}

核心的BeanFactory实现

public class BeanFactory {
  /**
       * 任务一:读取并解析xml,通过反射实例化对象并存储,用map结构存储
       * 任务二:对外提供根据ID获取对象的接口
       */
  private static Map<String, Object> map = new HashMap<>();

  static {
    // 任务一:读取并解析xml,通过反射实例化对象并存储,用map结构存储
    // 加载xml
    InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
    // 解析xml
    SAXReader saxReader = new SAXReader();
    try {
      Document document = saxReader.read(resourceAsStream);
      Element rootElement = document.getRootElement();

      List<Element> beanList = rootElement.selectNodes("//bean");

      for (int i = 0; i < beanList.size(); i++) {
        Element element = beanList.get(i);
        // 通过bean元素,获取id和class
        String id = element.attributeValue("id");
        String clazz = element.attributeValue("class");

        // 通过反射实例化对象
        Class<?> aClass = Class.forName(clazz);
        Object o = aClass.newInstance();
        map.put(id, o);
      }

      // 维护对象的依赖关系
      // 找到有property子元素的bean
      List<Element> propertyList = rootElement.selectNodes("//property");
      for (int j = 0; j < propertyList.size(); j++) {
        Element element = propertyList.get(j);
        String name = element.attributeValue("name");
        String ref = element.attributeValue("ref");

        // 找到有property的bean
        Element parent = element.getParent();

        // 父元素反射赋值
        String parentId = parent.attributeValue("id");
        Object parentObject = map.get(parentId);

        Method[] methods = parentObject.getClass().getMethods();
        for (int i = 0; i < methods.length; i++) {
          Method method = methods[i];
          if (method.getName().equals("set" + name)) {
            method.invoke(parentObject, map.get(ref));
          }
        }

        // 重新赋值
        map.put(parentId, parentObject);
      }

    } catch (DocumentException | ClassNotFoundException e) {
      e.printStackTrace();
    } catch (InstantiationException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    } catch (InvocationTargetException e) {
      e.printStackTrace();
    }
  }

  /**
       * 任务二:对外提供根据ID获取对象的接口
       *
       * @param id
       * @return
       */
  public static Object getBean(String id) {
    return map.get(id);
  }
}

Service层未添加事务解决

问题分析:

数据库事务是Connection的事务

connection.commit();//提交事务

Connection.rollback();//回滚事务

image

解决思路:

1)两次update使用同一个conenction链接

两次update属于同一个线程的执行调用,从同一个线程中拿到

2)把事务控制在service层

代码实现

/*try{
  // 开启事务(关闭事务的自动提交)
  TransactionManager.getInstance().beginTransaction();*/

Account from = accountDao.queryAccountByCardNo(fromCardNo);
Account to = accountDao.queryAccountByCardNo(toCardNo);

from.setMoney(from.getMoney()-money);
to.setMoney(to.getMoney()+money);

accountDao.updateAccountByCardNo(to);
// int c = 1/0;
accountDao.updateAccountByCardNo(from);

/*    // 提交事务

TransactionManager.getInstance().commit();
}catch (Exception e) {
  e.printStackTrace();
  // 回滚事务
  TransactionManager.getInstance().rollback();

  // 抛出异常便于上层servlet捕获
  throw e;

}*/

动态代理改造Service

image

定义代理工厂类

/**
 * @author: terwer
 * @date: 2021/12/14 22:58
 * @description: 代理对象工厂,主要用于生产对象
 */
public class ProxyFactory {
    private TransactionManager transactionManager;

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

    /**
     * Jdk动态代理
     * @param obj  委托对象
     * @return   代理对象
     */
    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) {
                            e.printStackTrace();
                            // 回滚事务
                            transactionManager.rollback();

                            // 抛出异常便于上层servlet捕获
                            throw e;

                        }

                        return result;
                    }
                });

    }


    /**
     * 使用cglib动态代理生成代理对象
     * @param obj 委托对象
     * @return
     */
    public Object getCglibProxy(Object obj) {
        return  Enhancer.create(obj.getClass(), new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                Object result = null;
                try{
                    // 开启事务(关闭事务的自动提交)
                    transactionManager.beginTransaction();

                    result = method.invoke(obj,objects);

                    // 提交事务

                    transactionManager.commit();
                }catch (Exception e) {
                    e.printStackTrace();
                    // 回滚事务
                    transactionManager.rollback();

                    // 抛出异常便于上层servlet捕获
                    throw e;

                }
                return result;
            }
        });
    }
}

代码

https://github.com/terwer/transfer-test

posted @ 2021-12-12 20:03  灯塔下的守望者  阅读(65)  评论(0编辑  收藏  举报