动态代理
Posted guoDaXia的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态代理相关的知识,希望对你有一定的参考价值。
增强的手段
1、继承
*被增强对象不能变
*增强内容不能变
2.装饰者模式
*被增强对象可变
*但增强内容不可变
3.动态代理
*被增强对象可变
*增强内容可变
首先一个方法:
Proxy.newProxyInstance(ClassLoader classLoader,Class[] interfaces,invocationHandler h);
1、方法作用:动态创建实现了interfaces数组中所有指定接口的实现类对象!
参数:
1、ClassLoader:类加载器
它是用来加载类的,把.class文件加载到内存形成Class对象!
2、Class[] interfaces:指定要执行的接口
3、invocationHandler:代理对象的所有方法(个别方法不执行)都会调用InvocationHandler的invoke方法
第一个测试类:
package com.itcast.demo1; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.junit.Test; public class Demo1 { @Test public void fun1(){ /* * 三大参数 * 1.ClassLoader * 方法需要动态生成一个类,这个类实现了A、B接口,然后创建这个类的对象! * 需要生成一个类,这个类也需要加载到方法区中,谁来加载,当然是ClassLoader * * 2.Class[] interfaces * 它是要实现的接口们 * * 3.InvocationHandler * 它是调用处理器 * 敷衍它 * * 代理对象的所有方法都是调用invocationHandler的invoke方法 */ ClassLoader loader=this.getClass().getClassLoader(); InvocationHandler h=new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("你好,动态代理!"); return null; } }; //使用三大参数创建代理对象 Object o=Proxy.newProxyInstance(loader, new Class[]{A.class,B.class}, h); //强转成A和B类型,成功了! A a=(A) o; B b=(B) o; a.a(); b.b(); a.aa(); b.bb(); System.out.println(a.getClass().getName()); } } interface A{ public void a(); public void aa(); } interface B{ public void b(); public void bb(); }
证实几点:
1、该方法生成了实现指定接口的代理对象。
2、代理类的几乎所有方法的执行都是调用invocation的invoke方法。
3、类加载器使用this.getClass().getClassLoader()得到。
动态代理的作用
最终是学习AOP(面向切面编程),它与装饰者模式有点相似,它比装饰者模式还要灵活!
方法:
public Object invoke(Object proxy,Method method,Object[] args)
这个invoke方法什么时候被调用!
1、在代理对象呗创建时?错误的
2、在调用代理对象所实现接口中的方法时?正确的!
*Object proxy:当前对象,即代理对象!在调用谁的方法!
*Method method:当前被调用的方法(目标方法)
*Object[] args:实参!
实现
(*被增强对象可变*但增强内容不可变):
package com.itcast.demo2; //服务员 public interface Waiter { //服务 public void server(); } package com.itcast.demo2; public class ManWaiter implements Waiter { @Override public void server() { System.out.println("服务中!"); } } package com.itcast.demo2; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.junit.Test; /** * 我们必须要掌握的是当前这个案例! * @author Administrator * */ public class Demo2 { @Test public void fun1(){ Waiter manWaiter=new ManWaiter(); /* * 给出三个参数,来调用方法得到代理对象 */ ClassLoader loader=this.getClass().getClassLoader(); Class[] interfaces={Waiter.class}; InvocationHandler h=new WaitInvocationHanlder(manWaiter); //被增强的目标对象 Waiter waiter=(Waiter) Proxy.newProxyInstance(loader, interfaces, h); waiter.server();//前面加你好,后面加再见 } } class WaitInvocationHanlder implements InvocationHandler{ private Waiter waiter;//目标对象 public WaitInvocationHanlder(Waiter waiter){ this.setWaiter(waiter); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("你好!"); this.waiter.server();//调用目标对象的方法 System.out.println("再见!"); return null;//return 的值是执行的方法的返回值,这个方法的proxy表示的是本代理对象,所以不能使用method.invoke(proxy,args).这样会走死循环。 } public void setWaiter(Waiter waiter) { this.waiter = waiter; } public Waiter getWaiter() { return waiter; } }
使用工厂模式,实现增强内容也可变。
目标对象:被增强的对象
代理对象:需要增强的对象,
目标:
执行前增强
执行后增强
package com.itcast.demo3; /** * 前置增强 */ public interface BeforeAdvice { public void before(); } package com.itcast.demo3; /* * 后置增强 */ public interface AfterAdvice { public void after(); } package com.itcast.demo3; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 它用来生成代理对象 * 它需要所有的参数 * *目标对象 * *增强 */ /** * 1、创建代理工厂 * 2、改工厂设置三样东西: * *目标对象setTargetObject * *前置增强:setBeforeAdvice * *后置增强:setAfterAdvice * 3、调用createProxy()得到代理对象 * *执行代理对象方法时: * 执行BeforeAdvice的before() * 目标对象的目标方法 * 执行AfterAdvice的after() */ public class ProxyFactory { private Object targetObject;//目标对象 private BeforeAdvice beforeAdvice;//前置增强 private AfterAdvice afterAdvice;//后置增强 public Object getTargetObject() { return targetObject; } /** * 用来生成代理对象 * @return */ public Object createProxy(){ /* * 给出三大参数 */ ClassLoader loader=this.getClass().getClassLoader(); Class[] interfaces=targetObject.getClass().getInterfaces(); InvocationHandler h=new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /* * 在调用代理对象的方法时,执行这里的内容 */ //执行前置增强 if(beforeAdvice!=null){ beforeAdvice.before(); } Object result=method.invoke(targetObject, args);//执行目标对象的目标方法 //执行后置增强 if(afterAdvice!=null){ afterAdvice.after(); } //返回目标对象中的返回值 return result; } }; //得到代理对象 Object obj=Proxy.newProxyInstance(loader, interfaces, h); //返回代理 return obj; } public void setTargetObject(Object targetObject) { this.targetObject = targetObject; } public BeforeAdvice getBeforeAdvice() { return beforeAdvice; } public void setBeforeAdvice(BeforeAdvice beforeAdvice) { this.beforeAdvice = beforeAdvice; } public AfterAdvice getAfterAdvice() { return afterAdvice; } public void setAfterAdvice(AfterAdvice afterAdvice) { this.afterAdvice = afterAdvice; } }
主要代码就这些:
这里实现增强内容可变的方法是代理对象的执行体令它是可变的,所以使用工厂进行创建,进行了一些包装操作。我们必须透彻理解如何进行的增强,增强的步骤等。
难点在于:
1、思路。明确知道自己需要什么怎么办。
2、proxy中的invoke方法的书写。
以上是关于动态代理的主要内容,如果未能解决你的问题,请参考以下文章