昨天说到了静态代理,静态代理是在事先知道真实对象的情况下产生的代理类,一个代理对象对应一个真实对象(代理对象持有对真实对象的引用),如果有很多真实对象需要进行代理,我们就要产生出很多代理对象,这样,会形成代理对象冗余;或者我们根本不知道代理对象是什么,那这样又要如何处理呢?
前面说过反射可以在运行时确定一个类的类型信息,所以我们可以通过反射来动态代理对象,JDK已经提供了相应的API,下面就可以通过API来实现动态代理.
JDK动态代理的API存放在java.lang.reflect包下,主要涉及到:
(1)InvocationHandler接口
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
该接口只有一个invoke方法,此方法用来处理代理对象上的方法调用,即代理对象上相关方法的调用会通过此方法来对真实对象
目标方法的调用
(2)Proxy类
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) { throw new NullPointerException(); } //通过类加载器得到代理类的Class对象 Class cl = getProxyClass(loader, interfaces); try { //得到代理对象的构造方法 Constructor cons = cl.getConstructor(constructorParams); //返回该代理对象 return (Object) cons.newInstance(new Object[] { h }); } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } catch (IllegalAccessException e) { throw new InternalError(e.toString()); } catch (InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { throw new InternalError(e.toString()); } }
该方法为Proxy的最主要方法,用于动态产生我们需要的代理对象,而不必再像静态代理那样需要事先知道真实对象.
到底什么是动态代理?
在动态代理中,代理会在运行时根据你传入的一组接口动态生成,默认生成的代理类可以作为该组接口中任何一个实现类来使用,这个类仅仅是一个代理类,它不会完成真正的代理操作,所以在该类生成时会传入一个实现了InvocationHandler接口的实现类,他会完成真正的代理操作,即相关方法的调用;下面看一个实例:
public interface Subject { public void doSth(); }
public class RealSubject implements Subject {
@Override
public void doSth() {
System.out.println("RealSubject-->doSth");
}
}
public class DynamicProxySubject implements InvocationHandler {
private Object sub;
public DynamicProxySubject(Object sub) {
this.sub = sub;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("before calling:");
Object res = method.invoke(sub,args);
System.out.println("after calling:");
return res;
}
}
public class Client {
public static void main(String[] args) {
RealSubject rs = new RealSubject();
InvocationHandler dynamic = new DynamicProxySubject(rs);
Subject subject = (Subject)Proxy.newProxyInstance(dynamic.getClass().getClassLoader(),rs.getClass().getInterfaces(),dynamic);
subject.doSth();//当执行这个方法调用时其实是执行的invocationhandler接口实现类的invoke方法
}
}
这就是动态代理实现的helloword代码,后面的struts2、spring中用到了很多动态代理模式,学好动态代理对理解这些框架的原理非常有用