zoukankan      html  css  js  c++  java
  • Spring AOP 编程

    1. 静态代理设计模式(手动)

    为什么需要代理设计模式

    JavaEE分层开发中,最为重要的是Service层

    Service层中包含了哪些代码?

    Service层中 = 核⼼功能(⼏⼗⾏ 上百代 码) + 额外功能(附加功能)

    1. 核⼼功能

      • 业务运算
      • DAO调⽤
    2. 额外功能 不属于业务 可有可⽆ 代码量很⼩

      • 事务、⽇志、性能
    额外功能书写在Service层中好不好?

    Service层的调⽤者的⻆度(Controller):需要在Service层书写额外功能。

    软件设计者:Service 层不需要额外功能

    解决方式:引入一个代理(中介)类,完成额外功能,并调用目标类(原始类)的核心功能

    代理设计模式

    通过代理类,为原始类(⽬标)增加额外的功能

    好处:利于原始类(⽬标)的维护

    ⽬标类 原始类

    指的是 业务类 (核⼼功能 --业务运算 DAO调⽤)

    ⽬标⽅法,原始⽅法

    ⽬标类(原始类)中的⽅法 就是⽬标⽅法 (原始⽅法)

    额外功能 (附加功能)

    ⽇志,事务,性能

    代理开发的核⼼要素

    代理类 = ⽬标类(原始类) + 额外功能 + 原始类(⽬标类)实现相同的接⼝

    /**
     * 代理类
     * 1. 与被代理类实现相同接口
     * 2. 必须原始对象
     * 3. 实现额外功能
     *
     * @author duniqb <duniqb@qq.com>
     * @version v1.0.0
     * @date 2020/7/1 10:52
     * @since 1.8
     */
    public class UserServiceProxy implements UserService {
        /**
         * 原始对象
         */
        private UserServiceImpl userService = new UserServiceImpl();
    
        @Override
        public void register(User user) {
            // 额外功能
            System.out.println("----log-----");
            userService.register(user);
        }
    
        @Override
        public boolean login(String name, String password) {
    
            System.out.println("----log-----");
            return userService.login(name, password);
        }
    }
    

    静态代理存在的问题

    静态类⽂件数量过多,不利于项⽬管理

    UserServiceImpl

    UserServiceProxy

    额外功能维护性差

    代理类中 额外功能修改复杂(麻烦)

    2. Spring的动态代理开发

    Spring动态代理的概念

    概念:通过代理类为原始类(⽬标类)增加额外功能(与静态代理一样)

    好处:利于原始类(⽬标类)的维护

    步骤

    1. 创建原始对象(⽬标对象)
    public class UserServiceImpl implements UserService {
        @Override
        public void register(User user) {
            System.out.println("UserServiceImpl.register 业务运算 + DAO ");
        }
    
        @Override
        public boolean login(String name, String password) {
            System.out.println("UserServiceImpl.login");
            return true;
        }
    }
    
    <bean id="userService" class="cn.duniqb.aop.proxy.UserServiceImpl"/>
    
    2. 额外功能 MethodBeforeAdvice接⼝

    额外的功能书写在接⼝的实现中,运⾏在原始⽅法执⾏之前运⾏额外功能。

    public class Before implements MethodBeforeAdvice {
        /**
         * 作用:需要把运行在原始方法执行之前运行的额外功能,书写在before方法中
         */
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("-----method before advice log------");
        }
    }
    
    <bean id="before" class="cn.duniqb.aop.proxy.dynamic.Before"/>
    
    3. 定义切⼊点

    切⼊点:额外功能加⼊的位置

    ⽬的:由程序员根据⾃⼰的需要,决定额外功能加⼊给那个原始⽅法

    <aop:config proxy-target-class="true">
        <!-- 所有的方法,都作为切入点 -->
        <aop:pointcut id="all" expression="execution(* *(..))"/>
    </aop:config>
    
    4. 组装 (2 3整合)

    表达的含义:所有的⽅法 都加⼊ before的额外功能

    <aop:config proxy-target-class="true">
        <!-- 所有的方法,都作为切入点,加入额外功能 login register -->
        <aop:pointcut id="all" expression="execution(* *(..))"/>
        <!-- 组装:目的把切入点与额外功能进行整合 -->
        <aop:advisor advice-ref="before" pointcut-ref="all"/>
    </aop:config>
    
    5. 调⽤

    ⽬的:获得Spring⼯⼚创建的动态代理对象,并进⾏调⽤

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    

    注意:

    1. Spring的⼯⼚通过原始对象的 id值获得的是代理对象

    2. 获得代理对象后,可以通过声明接⼝类型,进⾏对象的存储

    UserService userService = (UserService) ctx.getBean("user Service");
    userService.login("") 
    userService.register()
    

    动态代理细节分析

    Spring创建的动态代理类在哪⾥?

    Spring框架在运⾏时,通过动态字节码技术,在JVM创建的,运⾏在JVM内部,等程序结束后,会和JVM⼀起消失

    什么叫动态字节码技术

    通过第三方动态字节码框架,在JVM中创建对应类的字节码,进⽽创建对象,当虚拟机结束,动态字节码跟着消失。

    结论

    动态代理不需要定义类⽂件,都是JVM运⾏过程中动态创建的,所以不会造成静态代理,类⽂件数量过多,影响项⽬管理的问题。

    动态代理编程简化代理的开发

    在额外功能不改变的前提下,创建其他⽬标类(原始类)的代理对象时,只需要指定原始(⽬标)对象即可。

    动态代理额外功能的维护性⼤⼤增强

    3. Spring动态代理详解

    额外功能的详解

    MethodBeforeAdvice分析

    MethodBeforeAdvice接⼝作⽤:额外功能运⾏在原始⽅法执⾏之前,进⾏额外功能操作。

    public class Before1 implements MethodBeforeAdvice {
        /**
         * 需要把运行在原始方法执行之前运行的额外功能,书写在before方法中
         *
         * @param method 额外功能所增加给的那个原始方法 login方法
         * @param args   额外功能所增加给的那个原始方法的参数。String name,String password,User
         * @param target 额外功能所增加给的那个原始对象  UserServiceImpl
         */
        @Override
        public void before(Method method, Object[] args, Object target) {
            System.out.println("-----new method before advice log------");
        }
    }
    
    MethodInterceptor(⽅法拦截器)

    MethodInterceptor 接⼝:额外功能可以根据需要运⾏在原始⽅法执⾏ 前、后、前后。

    public class Around implements MethodInterceptor {
        /**
         * 作用:额外功能书写在invoke
         * 额外功能  原始方法之前
         * 原始方法之后
         * 原始方法执行之前 之后
         *
         * @param invocation 额外功能所增加给的那个原始方法
         * @return 原始方法的返回值
         * @throws Throwable
         */
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("------log-----");
            return invocation.proceed();
        }
    }
    

    4. AOP 编程

    概念

    AOP (Aspect Oriented Programing)

    ⾯向切⾯编程 = Spring动态代理开发

    以切⾯为基本单位的程序开发,通过切⾯间的彼此协同,相互调⽤,完成程序的构建

    切⾯ = 切⼊点 + 额外功能

    OOP (Object Oritened Programing)

    ⾯向对象编程 Java

    以对象为基本单位的程序开发,通过对象间的彼此协同,相互调⽤,完成程序的构建

    POP (Producer Oriented Programing)

    ⾯向过程(⽅法、函数)编程 C

    以过程为基本单位的程序开发,通过过程间的彼此协同,相互调⽤,完成程序的构建

    AOP的概念:

    本质就是Spring得动态代理开发,通过代理类为原始类增加额外功能。

    好处:利于原始类的维护

    注意:AOP编程不可能取代OOP,OOP编程有意补充。

    AOP编程的开发步骤

    1. 原始对象

    2. 额外功能 (MethodInterceptor)

    3. 切⼊点

    4. 组装切⾯ (额外功能+切⼊点)

    切⾯的名词解释

    切⾯ = 切⼊点 + 额外功能

    ⼏何学 ⾯ = 点 + 相同的性质

    5. AOP的底层实现原理

    核⼼问题

    AOP如何创建动态代理类

    动态字节码技术

    Spring⼯⼚如何加⼯创建代理对象

    通过原始对象的id值,获得的是代理对象

    动态代理类的创建

    JDK的动态代理
    Proxy.newProxyInstance(classloader, interfaces, invocationHandler);
    

    代理创建三要素:

    1. 原始对象

      classloader,借用一个类加载器,创建代理类的Class 对象,进而可以创建代理对象

    2. 额外功能

      invocationHandler

    3. interfaces

      代理对象和原始对象实现相同的接口

      userService.getClass().getInterfaces();
      
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("------proxy  log --------");
                // 原始方法运行
                return method.invoke(userService, args);
            }
        };
    
        // 借用类加载器加载原始对象, 代理对象和原始对象实现相同的接口, 额外功能
        UserService userServiceProxy = (UserService) Proxy.newProxyInstance(TestJDKProxy.class.getClassLoader(), userService.getClass().getInterfaces(), handler);
        userServiceProxy.login("duniqb", "123456");
        userServiceProxy.register(new User());
    }
    
    CGlib的动态代理

    CGlib创建动态代理的原理:⽗⼦继承关系创建代理对象,原始类作为⽗类,代理类作为⼦类,这样既可以保证l两者⽅法⼀致,同时在代理类中提供新的实现(额外功能+原始⽅法)

    public class TestCglib {
        public static void main(String[] args) {
            // 创建原始对象
            UserService userService = new UserService();
    
            // 通过cglib方式创建动态代理对象
            Enhancer enhancer = new Enhancer();
            enhancer.setClassLoader(TestCglib.class.getClassLoader());
            enhancer.setSuperclass(userService.getClass());
    
            MethodInterceptor interceptor = new MethodInterceptor() {
                // 等同于 InvocationHandler --- invoke
                @Override
                public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                    System.out.println("---cglib log----");
    
                    return method.invoke(userService, args);
                }
            };
    
            enhancer.setCallback(interceptor);
    
            UserService userServiceProxy = (UserService) enhancer.create();
            userServiceProxy.login("suns", "123345");
            userServiceProxy.register(new User());
        }
    }
    
    

    动态代理总结

    1. JDK 动态代理

      Proxy.newProxyInstance() 通过接⼝ 创建代理的实现类

    2. Cglib 动态代理

      Enhancer 通过继承⽗类创建的代理类

    Spring⼯⼚如何加⼯原始对象

    6. 基于注解的AOP编程

    基于注解的AOP编程的开发步骤

    原始对象

    额外功能

    切⼊点

    组装切⾯

    没有修不好的电脑
  • 相关阅读:
    spring原理
    架构师和数学
    项目经理需要注意的地方
    如何快速掌握一门新技术
    项目管理要做啥
    编程原则
    架构设计的常用思想
    聊聊编程范式
    程序员与哲学家
    IT人员如何有效规划自己时间
  • 原文地址:https://www.cnblogs.com/duniqb/p/13274720.html
Copyright © 2011-2022 走看看