本文只是简单的对Java中的jdk代理进行记录,不做过于详细的原理分析(如需要,请移步其他)。
一、动态代理过程
在进行动态代理时,我们可以调用 java.lang.reflect.Proxy 包的 newProxyInstance() 方法。
为某些接口创建代理实例Foo的简略步骤如下:
InvocationHandler handler = new MyInvocationHandler(...);
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class<?>[] { Foo.class },
handler);
二、newProxyInstance() 介绍
newProxyInstance方法签名
public static Object newProxyInstance(
ClassLoader loader,
Class <?>[] interfaces,
InvocationHandler h
);
loader:定义代理类的类加载器。类加载器(将Class文件字节码内容加载到内存中,生成类对象)
interfaces:代理类要实现的接口列表。即这个代理类长什么样
h:将方法调用分派到的调用处理程序
三、InvocationHandler 介绍
InvocationHandler 是一个接口,需要实现下面的方法。
Object invoke(Object proxy, Method method, Object [] args);
new InvocationHandler() {
//第一个参数:代理对象
//第二个参数:需要重写目标对象的方法
//第三个参数:method方法里面参数
@Override
public Object invoke(Object proxy,
Method method,
Object[] args) throws Throwable {
//调用目标的方法
Object result = method.invoke(target, args);
return result;
}
};
proxy :调用该方法的代理实例
method:与在代理实例上调用的接口方法对应的 Method 实例。 Method 对象的声明类将是声明该方法的接口,它可能是代理类通过其继承该方法的代理接口的超接口。
args:包含在代理实例的方法调用中传递的参数值的对象数组,或者 null 如果接口方法不带参数。原始类型的参数包装在适当的原始包装类的实例中,例如 java.lang.Integer 或 java.lang.Boolean 。
其实这个proxy就是通过动态代理生成的对象,method是通过动态代理调用的方法,args是方法的参数。那就可以这个简单的理解proxy.method(args);
当然只是这么理解而已,调用过程并不是这样子。
四、具体使用实例
下面的例子,使用代理模式。使用上面提到的内容。
public class ProxyFactory {
//目标对象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
//返回代理对象
public Object getProxy() {
/**
* Proxy.newProxyInstance()方法
* 有三个参数
* 第一个参数:ClassLoader: 加载动态生成代理类的来加载器
* 第二个参数: Class[] interfaces:目录对象实现的所有接口的class类型数组
* 第三个参数:InvocationHandler:设置代理对象实现目标对象方法的过程
*/
//第一个参数:ClassLoader: 加载动态生成代理类的来加载器
ClassLoader classLoader = target.getClass().getClassLoader();
//第二个参数: Class[] interfaces:目录对象实现的所有接口的class类型数组
Class<?>[] interfaces = target.getClass().getInterfaces();
//第三个参数:InvocationHandler:设置代理对象实现目标对象方法的过程
InvocationHandler invocationHandler =new InvocationHandler() {
//第一个参数:代理对象
//第二个参数:需要重写目标对象的方法
//第三个参数:method方法里面参数
@Override
public Object invoke(Object proxy,
Method method,
Object[] args) throws Throwable {
//方法调用之前输出
System.out.println("[动态代理][日志] "+method.getName()+",参数:"+ Arrays.toString(args));
//调用目标的方法
Object result = method.invoke(target, args);
//方法调用之后输出
System.out.println("[动态代理][日志] "+method.getName()+",结果:"+ result);
return result;
}
};
return Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
}
}