zoukankan      html  css  js  c++  java
  • 【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

  • 相关阅读:
    搭建cdh单机版版本的hive所遇到的问题总汇
    CentOS下Java的安装与环境配置
    重新认识Maven
    spring boot 搭建web项目常见五种返回形式
    一段递归代码引发的对于传参以及关于基本类型的一点了解
    爬虫
    .NET简谈接口
    C# Dictionary用法总结
    select @@identity的用法 转
    DataSet用法详细 转
  • 原文地址:https://www.cnblogs.com/tangyouwei/p/15677603.html
Copyright © 2011-2022 走看看