一:背景
Spring主要有两大思想,一个是IoC,另一个就是AOP.而AOP的原理就是java的动态代理机制.
二:概念
动态代理其实就是java.lang.reflect.Proxy类动态的根据您指定的所有接口生成一个class BYTE,该class会继承Proxy类,并实现所有你指定的接口(您在参数中传入的接口数组);然后再利用您指定的classloader将 class BYTE加载进系统,最后生成这样一个类的对象,并初始化该对象的一些值,如invocationHandler,以即所有的接口对应的Method成员。 初始化之后将对象返回给调用的客户端
三:解析
在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。
InvocationHandler:
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个
Handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
我们看到这个方法一共接受三个参数,那么这三个参数分别代表什么呢?
proxy: 指代我们所代理的那个真实对象
method: 指代的是我们所要调用真实对象的某个方法的Method对象
args: 指代的是调用真实对象某个方法时接受的参数
Proxy:
Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
这个方法的作用就是得到一个动态的代理对象,其接收三个参数,我们来看看这三个参数所代表的含义:
loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
四:案例
业务接口:
-
public interface BusinessProcessor {
-
public void processBusiness();
-
}
业务实现:
-
public class BusinessProcessorImpl implements BusinessProcessor{
-
-
/* (non-Javadoc)
-
* @see com.enjoylink.gmap.mongodb.demo.BusinessProcessor#processBusiness()
-
*/
-
@Override
-
public void processBusiness() {
-
-
System.out.println("===========处理业务============");
-
}
-
-
}
业务代理:
-
public class BusinessProcessorHandler implements InvocationHandler {
-
-
private Object target = null;
-
-
BusinessProcessorHandler(Object target) {
-
this.target = target;
-
}
-
-
/*
-
* (non-Javadoc)
-
*
-
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
-
* java.lang.reflect.Method, java.lang.Object[])
-
*/
-
@Override
-
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-
-
System.out.println("=========业务处理------前的操作=========");
-
Object result=method.invoke(target, args);
-
System.out.println("=========业务处理------后的操作=========");
-
return result;
-
}
-
-
}
测试:
测试结果:
-
=========业务处理------前的操作=========
-
===========处理业务============
-
=========业务处理------后的操作=========
-
com.sun.proxy.$Proxy0
-
com.sun.proxy.$Proxy0 extends java.lang.reflect.Proxy implements com.enjoylink.gmap.mongodb.demo.BusinessProcessor
-
{
-
java.lang.reflect.Method m1;
-
java.lang.reflect.Method m2;
-
java.lang.reflect.Method m3;
-
java.lang.reflect.Method m0;
-
-
boolean equals(java.lang.Object);
-
java.lang.String toString();
-
int hashCode();
-
void processBusiness();
-
}
Proxy.newProxyInstance方法会做如下几件事:
1,根据传入的第二个参数interfaces动态生成一个类,实现interfaces中的接口,该例中即BusinessProcessor接口的processBusiness方法。并且继承了Proxy类,重写了hashcode,toString,equals等三个方法。具体实现可参看 ProxyGenerator.generateProxyClass(...); 该例中生成了$Proxy0类
2,通过传入的第一个参数classloder将刚生成的类加载到jvm中。即将$Proxy0类load
3,利用第三个参数,调用$Proxy0的$Proxy0(InvocationHandler)构造函数
创建$Proxy0的对象,并且用interfaces参数遍历其所有接口的方法,并生成Method对象初始化对象的几个Method成员变量
4,将$Proxy0的实例返回给客户端。
我们再看客户端怎么调就清楚了。
1,客户端拿到的是$Proxy0的实例对象,由于$Proxy0继承了BusinessProcessor,因此转化为BusinessProcessor没任何问题。
BusinessProcessor bp =
(BusinessProcessor)Proxy.newProxyInstance(....);
2,bp.processBusiness();
实际上调用的是$Proxy0.processBusiness();那么$Proxy0.processBusiness()的实现就是通过InvocationHandler去调用invoke方法。
五:总结
代理模式最大的特点就是代理类和实际业务类实现同一个接口(或继承同一父类),代理对象持有一个实际对象的引用,外部调用时操作的是代理对象,而在代理对象的内部实现中又会去调用实际对象的操作
Java动态代理其实内部也是通过Java反射机制来实现的,即已知的一个对象,然后在运行时动态调用其方法,这样在调用前后作一些相应的处理.
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/28624388/viewspace-2129828/
,如需转载,请注明出处,否则将追究法律责任。