1、什么是动态代理
所谓Dynamic Proxy是这样一种class,它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。
但是它不会替你完成任何实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
2、动态代理的作用
动态代理可以截获类调用,添加一些额外的功能。动态代理可以实现AOP,而AOP经常在Web等应用服务器中使用,额外添加安全,事物,日志等功能。
3、相关的类和接口
1)java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
方法 1: 该方法用于获取指定代理对象所关联的调用处理器
static InvocationHandler getInvocationHandler(Object proxy)
方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces)
方法 3:该方法用于判断指定类对象是否是一个动态代理类
static boolean isProxyClass(Class cl)
方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
2)java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。
该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行Object invoke(Object proxy, Method method, Object[] args)
每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象(参见 Proxy 静态方法 4 的第三个参数)。
java.lang.ClassLoader:这是类装载器类,负责将类的字节码装载到Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。
Proxy 静态方法生成动态代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。每次生成动态代理类对象时都需要指定一个类装载器对象(参见 Proxy 静态方法 4 的第一个参数)
4、实现代码
package com.dynamicproxy.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy {
public static void main(String args[]) {
HelloAImpl a = new HelloAImpl();
IHello pa = (IHello)BeanHelloContainer.getBean(a);
pa.Say();
HelloBImpl b = new HelloBImpl();
IHello pb = (IHello)BeanHelloContainer.getBean(b);
pb.Say();
}
}
interface IHello {
void Say();
}
class HelloAImpl implements IHello {
public void Say() {
System.out.println("HelloAImpl say hello");
}
}
class HelloBImpl implements IHello {
public void Say() {
System.out.println("HelloBImpl say hello");
}
}
class HelloHandler implements InvocationHandler {
private Object proxy;
HelloHandler(Object obj) {
this.proxy = obj;
}
public Object invoke(Object proxy, Method method, Object[] arg) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Object ret;
System.out.println("Begin Say");
ret = method.invoke(this.proxy, arg);
System.out.println("End Say");
return ret;
}
}
class BeanHelloContainer {
public static Object getBean(Object obj) {
InvocationHandler h = new HelloHandler(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), h);
}
}