一 . 概述
我们知道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的原因.