002 动态代理

一 . 概述

  我们知道AOP底层使用的就是动态代理,在JDK中支持接口级别的动态代理,

    这里我们进行一下演示,目的是方面后面看源代码时变得简单一些.


二 . 核心接口  

public interface InvocationHandler {

    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

上面的接口就是动态代理的核心接口,我们可以理解为一个方法级别的拦截.

  其中的参数,proxy表述代理对象,method表示被拦截的方法,args表示运行的方法的参数.

  这是一个回调的形式进行描述的.

public class Proxy implements java.io.Serializable 
  public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException

上面是Proxy的代理生成器,我们一般使用的核心方法newProxyInstance().

  这里我们需要介绍一下这些参数,loader 表示加载新动态生成字节码文件的类加载器.

  interfaces表示代理对象需要实现的接口,

  最后一个参数就是代理对象的回调的业务代码的实现.


三.简单的演示

接口:

public interface Subject {
    void exec();
}

实现类:  

public class RealSubject implements Subject {
    @Override
    public void exec() {
        System.out.println("do subjct");
    }
}

InvocationHandler : 

//自定义的处理方法
public class ProxyHandler implements InvocationHandler{

    private Object target ;
    //这里的构造方法表示对目标对象的一个强引用
    public ProxyHandler(Object target) {
        super();
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法运行执行拦截");
        //调用目标对象的方法
        method.invoke(target, args);
        System.out.println("方法运行之后进行拦截");
        System.out.println("看下我们新生成的代理对象的类型:==>" +proxy.getClass());
        return null;
    }

}

测试代码: 

public class MainTest {

    public static void main(String[] args) {
        //构造类加载器
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        //创建目标对象
        Subject subject = new RealSubject();
        Subject proxy = (Subject) Proxy.newProxyInstance(loader, subject.getClass().getInterfaces(), new ProxyHandler(subject));
        //调用代理对象
        proxy.exec();
    }
}

运行结果:  

方法运行执行拦截
do subjct
方法运行之后进行拦截
看下我们新生成的代理对象的类型:==>class com.sun.proxy.$Proxy0

我们发现了目标对象的功能被增强了,但是目标对象的代码是没有发生改变的.

  这就是动态代理带来的好处.


四 .局限性

  JDK动态代理底层也是重新生成一个class文件的,这个class文件被类加载器加载到JVM之中.

  由于实现了接口的原因,这个代理对象对外就表现为接口的形态.

但是,局限性就出现了,如果一个目标对象没有实现接口,那么应该怎么处理呢?

  无法处理,因此spring考虑使用cglib帮助实现类的代理.

  这里不像继续介绍cglib的代码,因为我们一般情况下是不会完成这样的底层代码的.

记住,无论是JDK动态代理还是cglib代理,底层做的事情都是创建一个字节码文件,根据目标对象对外的接口,创建其实现方法的接口.

  因为有拦截回调的功能,才能对目标对象的方法进行增强.

  这也就是spring只支持方法级别的AOP的原因.

原文地址:https://www.cnblogs.com/trekxu/p/9096064.html