Spring AOP底层实现原理

Spring AOP底层实现原理

Aop底层使用动态代理实现:有两种情况动态代理

第一种:有接口情况,使用jdk动态代理

第二种:没有接口情况,使用cglib动态代理

1、使用jdk动态代理

创建接口实现类的代理对象,增强类的方法

(1)声明接口:

public interface TargetInteface {
    void method1();
    void method2();
    int method3(Integer i);
}

(2)创建接口的实现类:

public class Target implements TargetInteface {
    @Override
    public void method1() {
        System.out.println("method1 running ...");
    }

    @Override
    public void method2() {
        System.out.println("method2 running ...");
    }

    @Override
    public int method3(Integer i) {
        System.out.println("method3 running ...");
        return i;
    }
}

在这里,我们需要创建代理,从这三个方法切入,执行操作

(4)创建代理对象(核心类)

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

public class TargetProxy {
    public static  <T> Object getTarget(T t) {
        return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。
                        //比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。
                        System.out.println("执行方法前...");
                        Object invoke = method.invoke(t, args);
                        System.out.println("执行方法后...");
                        return invoke;
            }
        });
    }
}

Proxy.newProxyInstance()三个参数:

ClassLoader loader用来指明生成代理对象使用的类加载器;

Class[ ] interfaces 用来指明目标类实现的所有接口;

InvocationHandler h 用来指明产生的这个代理对象要做的事情。

实现InvocationHandler接口后需要重写invoke方法,代理类调用的所有方法实际上都是通过invoke方法调用的目标方法,invoke方法内部实现了两个逻辑:一个是增强逻辑,一个是执行目标方法。通过method.getName()获取当前调用的是代理对象的哪个方法,如果该方法是要被增强的方法,则进行增强,否则直接执行。

此时我们就已经创建好了代理对象:(同时呢我们也可以自定义一个类,写上我们想要切面的方法,可以自定义在执行方法前和执行方法后去调用我们想要测试的方法)

(4)创建测试类

public class TargetUser {

    public static void main(String[] args) {
        TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());
        target.method1();
        System.out.println("-----------------------------");
        target.method2();
        System.out.println("-----------------------------");
        System.out.println(target.method3(3));
        System.out.println("----------------");
    }
}

(5)测试结果

Spring AOP底层实现原理_第1张图片

此时:我们用jdk创建动态代理就ok了,主要还是利用Proxy.newProxyInstance()对象,此时需要重写Object invoke方法

2、使用cglib动态代理

创建子类的代理对象,增强类中的方法。

CGLib代理不要求目标类一定要实现了接口,它采用非常底层的字节码技术,可以为一个类创建子类,从而解决无接口代理问题。

(1)创建目标类,要增强的类

public class Target {
    public void method1() {
        System.out.println("method1 running ...");
}

    public void method2() {
        System.out.println("method2 running ...");
    }

    public int method3(Integer i) {
        System.out.println("method3 running ...");
        return i;
    }
}

(2)创建代理对象 (核心类)

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class TargetProxy {

    public static <T> Object getProxy(T t) {
        Enhancer en = new Enhancer(); //帮我们生成代理对象
        en.setSuperclass(t.getClass());//设置要代理的目标类
        en.setCallback(new MethodInterceptor() {//代理要做什么
            @Override
            public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("执行方法前。。。");
                //调用原有方法  
                Object invoke = methodProxy.invokeSuper(object, args);
                // Object invoke = method.invoke(t, args);// 作用等同与上面。
                System.out.println("执行方法后。。。");
                return invoke;
            }
        });
        return en.create();
    }
}

重写:Object intercept()方法

Enhancer en = new Enhancer(); //帮我们生成代理对象
en.setSuperclass(t.getClass());//设置要代理的目标类
en.setCallback(new MethodInterceptor() {//代理要做什么

return en.create(); 返回代理对象供调用

(3)创建测试类

public class TargetUser {

    public static void main(String[] args) {
        Target target = (Target) TargetProxy.getProxy(new Target());
        System.out.println(target.getClass().getName());
        target.method1();
    }
}

(4)执行结果

3、总结

  • Spring在运行期,生成动态代理对象,不需要特殊的编译器
  • Spring AOP的底层,是通过JDK动态代理 和 CGLib动态代理技术,为目标对象执行横向织入
  • Spring AOP非常智能,它可以根据目标对象是否实现了接口,自动选择使用哪种代理方式(默认使用JDK动态代理)
  • 如果目标对象实现了接口,Spring使用JDK的java.lang.reflect.Proxy类代理
  • 如果目标对象没有实现接口,Spring使用CGLib库生成目标对象的子类
  • 程序中应优先对接口创建代理,便于程序的解耦 和 维护
  • 标记为final的方法,不能被代理(因为方法被final修饰后,不能被重写)
  • JDK动态代理,是针对接口生成子类,接口中的方法不能被final修饰
  • CGLib代理,是针对目标类产生子类,因此类和方法不能使用final修饰
  • 如果目标对象没有实现接口,Spring使用CGLib库生成目标对象的子类
  • 程序中应优先对接口创建代理,便于程序的解耦 和 维护
  • 标记为final的方法,不能被代理(因为方法被final修饰后,不能被重写)
  • JDK动态代理,是针对接口生成子类,接口中的方法不能被final修饰
  • CGLib代理,是针对目标类产生子类,因此类和方法不能使用final修饰
  • Spring只支持方法的连接点,不提供属性的连接点,即Spring AOP仅对方法层面进行增强

你可能感兴趣的:(spring,java,后端)