• 【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

  • 相关阅读:
    Hibernate save, saveOrUpdate, persist, merge, update 区别
    Eclipse下maven使用嵌入式(Embedded)Neo4j创建Hello World项目
    Neo4j批量插入(Batch Insertion)
    嵌入式(Embedded)Neo4j数据库访问方法
    Neo4j 查询已经创建的索引与约束
    Neo4j 两种索引Legacy Index与Schema Index区别
    spring data jpa hibernate jpa 三者之间的关系
    maven web project打包为war包,目录结构的变化
    创建一个maven web project
    Linux下部署solrCloud
  • 原文地址:https://www.cnblogs.com/tangyouwei/p/15677603.html
Copyright © 2020-2023  润新知