• 关于spring的IOC和AOP


    简述

    谈这个首先要明白什么是IOC IOC(IoC Inversion of Control (控制反转/反转控制)),注意它是⼀个技术思想,不是⼀个技术实现
    描述的事情: Java开发领域对象的创建,管理的问题

    所要实现的事情就是我们可以不自己去new对象来使用 而是通过IOC容器去创建对象然后我们直接去IOC容器中取来使用

    说到这里还有一个概念需要提及 DI:Dependancy Injection(依赖注⼊)

    IOC和DI其实本质上说的是同一件事情,只不过角度不同,IOC是站在被注入对象的角度上 讲述这个对象被控制反转。而DI是站在容器的角度上 讲述这个容器将对象进行依赖注入。

    然后就是AOP

    AOP: Aspect oriented Programming ⾯向切⾯编程/⾯向⽅⾯编程
    AOP是OOP的一个延续,或者说延伸

    使代码在不改变原有逻辑的情况下 增强横切逻辑代码 根本上解藕 避免横切逻辑代码重复

    下面来具体说明下关于Spring的IOC AOP的实现

    首先 基于java的三层架构 我们想要在servlet中获取并使用或者service中获取并使用dao 那么我们最简单的方法便是new一个具体的实例来进行操作

    但是这样的话 一直的new对象 又无法保证该对象会被按时回收 首先堆中会不断堆积 影响到jvm的具体性能 还有这样的代码耦合性太强 java的特点就是要考虑具体的解耦问题

    那么 我们就需要考虑通过其他方式使该对象注入并能够使用

    在这个情况下 我们就考虑到通过xml文件的方式去解决

      首先通过xml文件将具体的class文件进行定义 确定其路径以及id 之后通过工厂的方式生产其对象

    1 <bean>
    2     <bean id="AccountDao" class="com/lagou/edu/dao/AccountDao.java"/>
    3 </bean>
    1 // 实例化bean对象
    2 for (int i = 0; i < list.size(); i++) {
    3    Element element = list.get(i);
    4    String id = element.attributeValue("id");
    5    String clazz = element.attributeValue("class");
    6    Class<?> aClass = Class.forName(clazz);
    7    Object o = aClass.newInstance();
    8    map.put(id, o);
    9 }

    通过工厂类将其实例化同时还要维护他的具体依赖关系 这个可以通过循环来处理他的property元素 之后  我们在将其放在map中以供之后方便使用

    这样 我们就可以通过工厂类的方法来创建实力对象 解决代码的耦合问题

    但是通过Spring框架我们可以知道这样并不是最简便的

    毕竟还要在每一个里面通过BeanFactory.getBean("transferService")获取对象实例

    但是直接写 private AccountDao accountDao 得到的实例对象其实是null

    我们可以通过set方法来给他赋值 但这样我们首先要将bean对象的值进行下处理 使其set到对应的name中

     1 // 维护bean之间的依赖关系
     2 List<Element> propertyNodes =
     3         rootElement.selectNodes("//property");
     4 for (int i = 0; i < propertyNodes.size(); i++) {
     5     Element element = propertyNodes.get(i);
     6     // 处理property元素
     7     String name = element.attributeValue("name");
     8     String ref = element.attributeValue("ref");
     9     String parentId =
    10             element.getParent().attributeValue("id");
    11     Object parentObject = map.get(parentId);
    12     Method[] methods = parentObject.getClass().getMethods();
    13     for (int j = 0; j < methods.length; j++) {
    14         Method method = methods[j];
    15         if (("set" + name).equalsIgnoreCase(method.getName())) {
    16             // bean之间的依赖关系(注⼊bean)
    17             Object propertyObject = map.get(ref);
    18             method.invoke(parentObject, propertyObject);
    19         }
    20     }
    21     // 维护依赖关系后重新将bean放⼊map中
    22     map.put(parentId, parentObject);

    这样当我们通过

    1     private AccountDao accountDao;
    2 
    3     public void setAccountDao(AccountDao accountDao){
    4         this.accountDao = accountDao;
    5     }

    的方式才能使accountDao的值不为null

    处于实际问题 我们还要考虑关于事务的控制

    如何保证事务的控制 那就要保证多次的commit操作使用的是同一个connection连接 方法 可以获取当前线程中的connection

     1     public Connection getCurrentThreadConn() throws SQLException {
     2         //判断当前线程中是否绑定连接 没有 从连接池获取一个绑定到当前线程
     3         Connection connection = threadLocal.get();
     4         if (threadLocal.get() == null) {
     5 //            connection = DruidUtils.getInstance().getConnection();
     6             //从连接吃那连接并绑定到线程
     7             connection = dataSource.getConnection();
     8             //绑定当前线程
     9             threadLocal.set(connection);
    10         }
    11         return connection;
    12     }

    这样的话 其实就算是基本还原了

    不过 如果有大量的涉及到事务的操作时 我们就需要进行大量的重复操作

     1     try {
     2             TransactionManager.getInstance().beginTransaction();
     3 
     4             Account from = accountDao.queryAccountByCardNo(fromCardNo);
     5             Account to = accountDao.queryAccountByCardNo(toCardNo);
     6             from.setMoney(from.getMoney()-money);
     7             to.setMoney(to.getMoney()+money);
     8             accountDao.updateAccountByCardNo(from);
     9             accountDao.updateAccountByCardNo(to);
    10 
    11             TransactionManager.getInstance().commit();
    12         } catch (Exception e){
    13             e.printStackTrace();
    14             TransactionManager.getInstance().rollback();
    15             throw e;
    16         }

    其中的开启事务 提交事务 包括捕获异常后的事务回滚我们都要大量的重复书写 这里就涉及到了动态代理模式的使用

    代理模式

      代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。

    其中还分为动态代理和静态代理

    静态代理总结

    优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。

      缺点:我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。

    相对于静态代理来说 动态代理教完美的解决了这一问题 为什么说较完美呢 因为jdk的动态代理还是摆脱不了对于interface的依赖 对应的就是我们需要创建同数量的接口

    这也是很大的工程

     1     @CallerSensitive
     2     public static Object newProxyInstance(ClassLoader loader,
     3                                           Class<?>[] interfaces,
     4                                           InvocationHandler h) {
     5         Objects.requireNonNull(h);
     6 
     7         final Class<?> caller = System.getSecurityManager() == null
     8                                     ? null
     9                                     : Reflection.getCallerClass();
    10 
    11         /*
    12          * Look up or generate the designated proxy class and its constructor.
    13          */
    14         Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
    15 
    16         return newProxyInstance(caller, cons, h);
    17     }

    于是 更加方便的cjlib动态代理就应需产生了

    1     public static Object create(Class type, Callback callback) {
    2         Enhancer e = new Enhancer();
    3         e.setSuperclass(type);
    4         e.setCallback(callback);
    5         return e.create();
    6     }

    可以跳过接口直接通过class来代理对象

    所以 我们使用动态代理将大量的重复事务操作进行抽取 使代码不再臃肿

     1     public Object getCglibProxy(Object obj) {
     2         return Enhancer.create(obj.getClass(), new MethodInterceptor() {
     3             @Override
     4             public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
     5                 Object result = null;
     6                 try{
     7                     transactionManager.beginTransaction();
     8 
     9                     result = method.invoke(obj, objects);
    10 
    11                     transactionManager.commit();
    12                 }catch (Exception e) {
    13                     e.printStackTrace();
    14 
    15                     transactionManager.rollback();
    16 
    17                     throw e;
    18                 }
    19 
    20                 return result;
    21             }
    22         });
    23     }

    这样 我们就可以直接书写业务模块了

  • 相关阅读:
    可重入函数
    epoll源码深度剖析
    数据结构学习之基本概念
    机器学习算法原理与编程实践之朴素贝叶斯分类
    机器学习算法与编程实践之中文文本分类
    ElasticSearch常用结构化搜索
    linux几种常见的文件内容查找和替换命令
    List遍历时删除遇到的问题
    初学ElasticSeacher
    从jar中读取资源文件的问题
  • 原文地址:https://www.cnblogs.com/yuztmt/p/14238767.html
Copyright © 2020-2023  润新知