【一步一步学习spring】spring aop 底层实现

1. JDK的动态代理

注意一下:该动态代理只能对实现了接口的类进行代理!

使用动态代理的五大步骤

  • 通过实现InvocationHandler接口来自定义自己的InvocationHandler;
  • 通过Proxy.getProxyClass获得动态代理类
  • 通过反射机制获得代理类的构造方法,方法签名为getConstructor(InvocationHandler.class)
  • 通过构造函数获得代理对象并将自定义的InvocationHandler实例对象传为参数传入
  • 通过代理对象调用目标方法

DEMO

package com.aop.demo1;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest {
    public interface IHello {
        void sayHello();
    }

    static class Hello implements IHello {
        public void sayHello() {
            System.out.println("Hello world!!");
        }
    }

    // 自定义InvocationHandler
    static class HWInvocationHandler implements InvocationHandler {
        // 目标对象
        private Object target;

        public HWInvocationHandler(Object target) {
            this.target = target;
        }

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("------插入前置通知代码-------------");
            // 执行相应的目标方法
            Object rs = method.invoke(target, args);
            System.out.println("------插入后置处理代码-------------");
            return rs;
        }
    }

    public static void main(String[] args)
            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        IHello ihello = (IHello) Proxy.newProxyInstance(Hello.class.getClassLoader(), Hello.class.getInterfaces(), // 一组接口
                new HWInvocationHandler(new Hello())); // 自定义的InvocationHandler
        ihello.sayHello();
    }
}

2. CGLIB生成代理

  • 对于不使用接口的业务类,无法使用JDK动态代理
  • CGLIB采用非常底层字节码技术,可以为一个类创建子类,解决无接口的代理问题

使用CGlib代理的四大步骤

  • 创建Enhancer核心类
  • 设置父类为目标类
  • 设置回调,其中实现具体要增强的逻辑
  • 生成代理

DEMO

package com.aop.demo1;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class CglibTest {
    public void test(){
        System.out.println("hello world");
    }

    public static void main(String[] args) {
        // 1.创建核心类
        Enhancer enhancer = new Enhancer();
        // 2.设置父类
        enhancer.setSuperclass(CglibTest.class);
        // 3.设置回调
        enhancer.setCallback(new MethodInterceptor() {
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                System.out.println("before method run...");
                Object result = proxy.invokeSuper(obj, args);
                System.out.println("after method run...");
                return result;
            }
        });
        // 4.生成代理
        CglibTest sample = (CglibTest) enhancer.create();
        sample.test();
    }
}

3. 总结

  • spring在运行期,生成动态代理对象,不需要特殊的编译器
  • spring aop的底层就是通过jdk动态代理或cglib动态代理技术为目标Bean执行横向织入
    • 若目标对象实现了接口,spring使用jdk的java.lang.reflect.Proxy类代理
    • 若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
  • 应该优先对接口创建代理,便于程序解耦维护
  • 标记为final的方法不能被代理。
  • spring只支持方法连接点,不提供属性连接点
  • 优缺点:
    • CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,
    • 但是CGLib在创建代理对象时所花费的时间却比JDK多得多,
    • 所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。

猜你喜欢

转载自www.cnblogs.com/xxxuwentao/p/9593856.html
今日推荐