java使用反射生成JDK动态代理
一、基本简介 在java的java.lang.reflect包下提供了一个Proxy类和InvocationHandler接口,通过使用这个类和接口可以生成JDK动态代理类或动态代理对象。
Proxy类提供了两个方法:
- static Class< ? > getProxyClass( ClassLoader loader,Class< ? > … interfaces) : 创建一个动态代理类所对应的Class对象,该代理类将实现interfaces所指定的多个接口。 第一个参数指定生成动态代理类的类加载器。
- static Object newProxyInstance( ClassLoader loader,Class< ? >[] interfaces,InvocationHandler h): 直接创建一个动态代理对象,该代理对象的实现类实现了Interfaces指定的系列接口,执行代理对象的每个方法都会被替换成InvocationHandler对象的invoke方法。
实际上,即使采用第一种方法生成动态代理类之后,如果程序需要通过该代理类来创建代理对象,还是需要传入一个InvocationHandler实例。
代码示例:
try {
//创建一个InvocationHandler对象
InvocationHandler invocationHandler = new MyInvocationHandler();
//使用Proxy生成一个动态代理类proxyClass
Class proxyClass= Proxy.getProxyClass(Foo.class.getClassLoader(),Foo.class);
//获取一个proxyClass类带InvocationHandler参数的构造器
Constructor constructor = proxyClass.getConstructor(InvocationHandler.class);
//调用constructor的newInstance方法生成动态代理实例
Foo foo = (Foo) constructor.newInstance(invocationHandler);
} catch (Exception e) {
e.printStackTrace();
}
以上的代码可以简化为下面的代码
InvocationHandler invocationHandler = new MyInvocationHandler();
Foo foo= (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[]{Foo.class},invocationHandler);
二、实践操作
public interface Person {
void sleep();
}
public class Man implements Person {
@Override public void sleep() {
System.out.println("开始睡觉了");
}
}
public class LogUtil {
public void filter1(){
System.out.println("在代理对象的方法执行之前,进行拦截做点什么");
}
public void filter2(){
System.out.println("在代理对象的方法执行之后,进行拦截做点什么");
}
}
生成代理对象
public class MyProxyFactory {
public static Object getProxy(Object target){
MyInvocationHandler handler = new MyInvocationHandler();
handler.setTarget(target);
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),handler);
}
}
public class MyInvocationHandler implements InvocationHandler {
//需要被代理的对象
private Object target;
public void setTarget(Object target){
this.target=target;
}
//1.proxy代表动态代理的对象
//2.method代表正在执行的方法
//3.args代表调用目标方法时传入的实参
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
LogUtil log = new LogUtil();
log.filter1();
//通过反射执行动态代理对象的所有方法
Object obj=method.invoke(target,args);
log.filter2();
return obj;
}
}
public static void main(String[] args){
Person target = new Man();
Person man= (Person) MyProxyFactory.getProxy(target);
man.sleep();
}
运行结果:
三、总结 一般普通编程无需用到动态代理,但在编写框架或底层代码时,它的作用就非常大了。还有就是使用动态代理可以非常灵活的实现解耦。
参考《疯狂java讲义》
