动态代理

来源:互联网 发布:负面情绪 知乎 编辑:程序博客网 时间:2024/04/30 09:30
/** 方法的调用,这里调用的是代理的方法,代理给ArrayList中的方法增强,在ArrayList的方法的基本功能上,增加了新的方法,比如计算这个程序的运行时间。 * 通过代理类调用目标类的方法,比如用proxy调用目标类ArrayList的add方法, * 首先需要获取代理类的实例,实例需要三个参数,一个是目标类的类加载器,一个是目标类的所有已知接口,还有一个是InvocationHandler接口, * InvocationHandler接口使用匿名内部类的方式实现。 * new InvocationHandler(),实际上是在InvocationHandler接口中用构造器接收了handler参数,作为InvocationHandler的实际参数。 * 这个InvocationHandler中含有所有已知接口的所有方法,但是都没有方法体。 * 在内部类中写invoke方法,需要三个参数,第一个是这个动态代理类实例,第二个是当前调用的方法名称,第三个是调用这个方法需要的参数。 * 在内部类里可以改变这个借口的方法的本来的功能,也可以通过调用这个目标类的方法,通过在目标类的方法的前后加上别的功能,实现方法增强的目的。 * 写好以后,通过代理类proxy调用目标类的方法,调用的就是加强后的方法了。 * 调用过程:proxy调用add方法。通过目标类的类加载器加载,再将传入的所有接口的方法添加进InvocationHandler中,因为InvocationHandler中有一个成员变量 * handler,调用时会通过这个handler找到相应的方法,在调用内部类中的invoke方法,将当前代理this,调用的方法(通过反射获取),这个方法的参数传入。 * 调用这个invoke方法。例如:调用add时。void add(value) {return handler.invoke(this,this.getClass().getMethod(“add”),value);}调用size()时int size(){return handler.invoke(this,this.getClass().getMethod(“size”),value);} 可以看出,不管调用哪个方法,最后都会调用内部类中的invoke方法, */public class ProxyTest {@SuppressWarnings({ "rawtypes" })public static void main(String[] args) {final ArrayList target = new ArrayList();//在匿名内部类中使用到了这个变量,需要final化。Collection proxy = (Collection) getProxy(target,new MyAdvice());//给Collection中的方法增加Advice中的方法,实现方法增强的目的。proxy.add("xzm");//方法的调用int size = proxy.size();System.out.println(proxy+"++"+size);}private static Object getProxy(final Object target,final Advice advice) {Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {advice.beforeMethod(method);Object retVal = method.invoke(target,args);advice.afterMethod(method);return retVal;}});return proxy;}}interface Advice{void beforeMethod(Method method);void afterMethod(Method method);}class MyAdvice implements Advice {long beginTime = 0;public void afterMethod(Method method) {System.out.println("end");long endTime = System.currentTimeMillis();System.out.println(method.getName()+"running time of"+(endTime-beginTime));}public void beforeMethod(Method method) {System.out.println("begin");beginTime = System.currentTimeMillis();}}