zoukankan      html  css  js  c++  java
  • Spring AOP的实现原理

    一、介绍

    AOP(Aspect Orient Programming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。

    AOP代理主要分为静态代理和动态代理:

    • 静态代理:以AspectJ为代表,在编译阶段生成AOP代理类---修改字节码
    • 动态代理:以Spring AOP为代表。不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

    二、Spring AOP的原理

    Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。

    1. JDK动态代理

    • 通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。
    • JDK动态代理的核心是InvocationHandler接口和Proxy类。

    2. CGLIB动态代理

    • CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,
    • CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

    3. Spring AOP的实现

    • 如果目标对象是接口类,就使用JDK动态代理;
    • 否则,Spring会使用CGLIB动态代理。

    三、JDK动态代理的使用

    1. 创建目标对象的接口及实现类

    /**
     * 目标对象实现的接口,用JDK来生成代理对象一定要实现一个接口
     */
    public interface UserService {
    
        /**
         * 目标方法 
         */
        public void add();
    
    }

    2. 创建目标对象

    /**
     * 目标对象
     */
    public class UserServiceImpl implements UserService {
    
        public void add() {
            System.out.println("--------------------add---------------");
        }
    }

    3. 实现自己的InvocationHandler

    /**
     * 实现自己的InvocationHandler
     */
    public class MyInvocationHandler implements InvocationHandler {
        
        // 目标对象 
        private Object target;
        
        /**
         * 构造方法
         * @param target 目标对象 
         */
        public MyInvocationHandler(Object target) {
            super();
            this.target = target;
        }
    
    
        /**
         * 执行目标对象的方法
         */
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            
            // 在目标对象的方法执行之前简单的打印一下
            System.out.println("------------------before------------------");
            
            // 执行目标对象的方法
            Object result = method.invoke(target, args);
            
            // 在目标对象的方法执行之后简单的打印一下
            System.out.println("-------------------after------------------");
            
            return result;
        }
    
        /**
         * 获取目标对象的代理对象
         * @return 代理对象
         */
        public Object getProxy() {
            return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), 
                    target.getClass().getInterfaces(), this);
        }
    }

    4. 测试

    /**
     * 动态代理测试类
     */
    public class ProxyTest {
    
        public static void main(String[] args) {
            // 实例化目标对象
            UserService userService = new UserServiceImpl();
    
            // 实例化InvocationHandler
            MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
    
            // 根据目标对象生成代理对象
            UserService proxy = (UserService) invocationHandler.getProxy();
    
            // 调用代理对象的方法
            proxy.add();
        }
    
    }

    结果:

    ------------------before------------------
    --------------------add---------------
    -------------------after------------------

    四、Cglib动态代理的使用

     1. 创建目标对象

    //被代理类
    public class InfoDemo {
        public void welcome (String person){
            System.out.println("welcome :" + person);
        }
    }

    2. 实现自己的MethodInterceptor

    public class MyCglibInterceptor implements MethodInterceptor {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("before...");
            Object result = methodProxy.invokeSuper(obj, args);
            System.out.println("after...");
            return result;
        }
    
        public static Object getProxy(Class cls, MethodInterceptor interceptor){
            Enhancer enhancer = new Enhancer();
            //生成指定类的子类,也就是重写类中的业务方法
            enhancer.setSuperclass(cls);
            //设置回调函数,加入intercept()方法
            enhancer.setCallback(interceptor);
            return enhancer.create();
        }
    
        public static void main(String[] args) {
            InfoDemo infoDemo = (InfoDemo)getProxy(InfoDemo.class, new MyCglibInterceptor());
            infoDemo.welcome("ketty");
        }
    }

     3. 测试结果

    before...
    welcome :ketty
    after...
  • 相关阅读:
    [Codeforces 339D] Xenia and Bit Operations
    [Codeforces 459D] Pashmak and Parmida's problem
    [Codeforces 460C] Present
    [Codeforces 466C] Number of Ways
    [Codeforces 650A] Watchmen
    Linux系统中‘dmesg’命令处理故障和收集系统信息的7种用法
    select函数详解
    都是stm32的JTAG引脚惹的祸
    uboot中的快捷菜单的制作说明
    卷积的本质及物理意义(全面理解卷积)
  • 原文地址:https://www.cnblogs.com/wslook/p/9163858.html
Copyright © 2011-2022 走看看