静态代理的话,一共有三个部分,两个类和一个接口,其中两个类分别是代理类和被代理类,其中接口是用来定义代理类和被代理类中公共的方法,代理类中的方法,是对被代理类中的方法的增强和补充。
举个例子,假设有人卖车,在saleCar这个接口中定义了一个salecar的方法。
需要代理类和被代理类都去继承这个接口,但是在被代理类中,salecar方法只是简单的定义了"卖车"这一个步骤。
但是在卖车之前要生产车,卖车之后要对车进行包装,因此,就要定义一个代理类,对于salecar()方法进行增强。
在代理类中,将被代理对象注入,并且在sale方法中对其进行增强,下面是测试的结果:
结果:
可见,通过静态代理,可以对原本的方法进行增强,但是这种方法耦合度太高了,如果要卖表的话,需要在代理类中,将saleWatch这个被代理类的对象注入(重点),并且将生产和包装的增强逻辑再写一遍。
写卖表的接口:
卖表的被代理类:
在代理类中注入被代理类的对象,并且对salewatch进行增强。
测试结果:
然后,静态代理的话,如果一个代理对象对多个被代理对象进行同样的增强和补充,就需要在代理对象中对这些被代理对象的方法分别进行增强,耦合度太高了,因此就有了动态代理。
在讲动态代理之前,需要介绍一个类和一个接口。
Proxy主要是通过newProxyInstance方法,返回一个代理对象。
ClassLoader loader:这个参数代表的是被代理类的类加载器,
Class>[] interfaces:被代理类实现的接口数组。
InvocationHandler h:实现InvocationHandler这个接口的类的对象,直接传入this。
proxy:代理对象
method:要增强的方法
args:参数列表
修改代理类为如下:
package springAOP.Impl; import springAOP.saleCar; import springAOP.saleWatch; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Objects; //代理类 public class proxySaleCar implements InvocationHandler { Object factory; public Object getFactory() { return factory; } public void setFactory(Object factory) { this.factory = factory; } //根据传入的被代理对象返回一个代理对象 public Object getProxyInstance(){ return Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(),this); } //方法增强的逻辑 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { doBeforeSale(); Object invoke = method.invoke(factory, args); doAfterSale(); return invoke; } public void doBeforeSale(){ System.out.println("生产"); } public void doAfterSale(){ System.out.println("包装"); } }
测试:
结果:
首先我们探究一下invoke方法中的参数proxy和我们创建的代理对象的关系:
输出参数proxy对象的字节码文件的名字。
输出生成代理对象的字节码的名称。
结果:
可以发现这两个其实是一个实例。
public static Object newProxyInstance(ClassLoader loader,Class>[] interfaces, InvocationHandler h)
在该方法的内部,首先是通过下面代码:
Class> cl = getProxyClass0(loader, intfs);
调用了getProxyClass0方法, 该方法需要传入两个参数, 一个是类加载器,一个是接口数组,在方法getProxyClass0中会创建出一个类$Proxy0 ,并且创建出这个内部类的引用返回。这个就是代理实例。
这个代理实例的类继承了Proxy类,并且实现了传入的接口数组中的接口,对其中的方法进行了重写,继而进行增强。
{ try { super.h.invoke(this, m3, null); return; } catch (Error ) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } }
在该方法中:super代表父类Proxy,h代表父类中的变量,也就是我们传进来的InvocationHandler接口实例,然后又调用了实例中的invoke方法,这个时候是不是就一目了然,这就是 InvocationHandler中的invoke方法会自动运行的原因,这是因为在代理类中的接口中方法内容重新定义了。