Spring AOP(2)动态代理
2015-08-08 17:41
393 查看
上篇文章使用了静态代理机制,其实这样并不好,会造成代码冗余。例如日志代理,很多地方都需要用到日志代理,但是静态代理,需要有真实类(目标类target)的引用,就把代理和目标类绑定了。即,产品的日志代理只能在产品类中使用,不能在工厂类中使用。为了解决这一问题,就用到动态代理机制。动态代理有很多方法,如JDK动态代理Cglib动态代理,今天就JDK以JDK动态代理为例。
JDK动态代理的原理,是代理类实现InvocationHandler接口,有Proxy来完成代理类的创建。当调用目标类的方法,就会调用代理类的invoke方法在invoke方法中加入增强
代码如下:
目标类的接口
目标类的实现
代理类,校验代理:
测试类:
JDK动态代理也是面向接口的,也支持多重代理
日志代理代码:
测试代码如下
利用代理代理学生类:
学生类接口:
实现:
测试:
当然,看到这个例子,你们可能有疑问,当代理类调用方法时,是如何调用invoke方法的,如果只是应用的话,上面的注释够用了,如果是底层,我觉得是通过某种机制,通知了代理类的invoke方法,因为代理类的实例中有this参数即是代理。具体怎么实现我目前尚不太清楚
使用JDK动态代理时可能遇到的问题,当你用下面的测试方式:
测试代码:
源代码下载地址http://download.csdn.net/detail/growing_it_bird/8978017
JDK动态代理的原理,是代理类实现InvocationHandler接口,有Proxy来完成代理类的创建。当调用目标类的方法,就会调用代理类的invoke方法在invoke方法中加入增强
代码如下:
目标类的接口
package com.yc.biz; public interface ProductBiz { public void addProduct(); }
目标类的实现
package com.yc.biz.impl; import com.yc.biz.ProductBiz; public class ProductBizImpl implements ProductBiz { public void addProduct() { System.out.println("**********************************"); System.out.println("添加产品"); System.out.println("**********************************"); } }
代理类,校验代理:
package com.yc.advice; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //这个类是切面,完成的功能是向目标方法加入功能(增强) public class RightAdvice implements InvocationHandler{ private Object obj; public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { check(); Object object=method.invoke(obj, args); System.out.println(object); return object; } public Object createInstance(Object targetObject){ this.obj=targetObject; //目标对象生成代理对象 //生成的代理对象,是根据目标对象的借口生成的 return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this); //客户端调用createInstance得到一个代理对象,再调用这个代理对象的方法。-》自动加载调用(this)-》invoke } private void check(){ System.out.println("*****************************"); } }
测试类:
package com.yc.test; import com.yc.advice.LogAdvice; import com.yc.advice.RightAdvice; import com.yc.biz.ProductBiz; import com.yc.biz.StudentBiz; import com.yc.biz.impl.ProductBizImpl; import com.yc.biz.impl.StudentBizImpl; public class Test2 { /** * @param args */ public static void main(String[] args) { RightAdvice ra=new RightAdvice(); ProductBiz pb=new ProductBizImpl(); ProductBiz productBizProxy=(ProductBiz) ra.createInstance(pb); productBizProxy.addProduct(); } } 测试结果 权限 ***************************** ********************************** 添加产品 **********************************
JDK动态代理也是面向接口的,也支持多重代理
日志代理代码:
package com.yc.advice; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Date; public class LogAdvice implements InvocationHandler { private Object obj; /*public RightAdvice(Object targetObject){ this.obj=targetObject; }*/ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object object=method.invoke(obj, args); log(obj, method, args); return object; } public Object createInstance(Object targetObject){ this.obj=targetObject; //目标对象生成代理对象 //生成的代理对象,是根据目标对象的借口生成的 return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this); //客户端调用createInstance得到一个代理对象,再调用这个代理对象的方法。-》自动加载调用(this)-》invoke } private void log(Object obj, Method method, Object[] args){ System.out.println("*****************************"); System.out.println("操作时间:"+new Date()); System.out.println("调用的目标类是:"+obj.getClass().getName()); System.out.println("调用的方法是:"+method.getName()); System.out.println("参数值:+"); if(args!=null){ for(Object arg:args){ System.out.println(arg); } } System.out.println("*****************************"); } }
测试代码如下
package com.yc.test; import com.yc.advice.LogAdvice; import com.yc.advice.RightAdvice; import com.yc.biz.ProductBiz; import com.yc.biz.StudentBiz; import com.yc.biz.impl.ProductBizImpl; import com.yc.biz.impl.StudentBizImpl; public class Test2 { /** * @param args */ public static void main(String[] args) { RightAdvice ra=new RightAdvice(); ProductBiz pb=new ProductBizImpl(); ProductBiz productBizProxy=(ProductBiz) ra.createInstance(pb); LogAdvice la=new LogAdvice(); //代理了校验代理类 ProductBiz productBizProxy2=(ProductBiz) la.createInstance(productBizProxy); productBizProxy2.addProduct(); } }
利用代理代理学生类:
学生类接口:
package com.yc.biz; public interface StudentBiz { public void findAll(); }
实现:
package com.yc.biz.impl; import com.yc.biz.StudentBiz; public class StudentBizImpl implements StudentBiz { public void findAll() { System.out.println("查找所有学生"); } }
测试:
package com.yc.test; import com.yc.advice.LogAdvice; import com.yc.advice.RightAdvice; import com.yc.biz.ProductBiz; import com.yc.biz.StudentBiz; import com.yc.biz.impl.ProductBizImpl; import com.yc.biz.impl.StudentBizImpl; public class Test2 { /** * @param args */ public static void main(String[] args) { RightAdvice ra=new RightAdvice(); ProductBiz pb=new ProductBizImpl(); ProductBiz productBizProxy=(ProductBiz) ra.createInstance(pb); //productBizProxy.addProduct(); LogAdvice la=new LogAdvice(); ProductBiz productBizProxy2=(ProductBiz) la.createInstance(productBizProxy); productBizProxy2.addProduct(); StudentBiz sb=new StudentBizImpl(); StudentBiz studentBizRightProxy=(StudentBiz) ra.createInstance(sb); studentBizRightProxy.findAll(); } }
当然,看到这个例子,你们可能有疑问,当代理类调用方法时,是如何调用invoke方法的,如果只是应用的话,上面的注释够用了,如果是底层,我觉得是通过某种机制,通知了代理类的invoke方法,因为代理类的实例中有this参数即是代理。具体怎么实现我目前尚不太清楚
使用JDK动态代理时可能遇到的问题,当你用下面的测试方式:
测试代码:
package com.yc.test; import com.yc.advice.LogAdvice; import com.yc.advice.RightAdvice; import com.yc.biz.ProductBiz; import com.yc.biz.StudentBiz; import com.yc.biz.impl.ProductBizImpl; import com.yc.biz.impl.StudentBizImpl; public class Test2 { /** * @param args */ public static void main(String[] args) { RightAdvice ra=new RightAdvice(); ProductBiz pb=new ProductBizImpl(); ProductBiz productBizProxy=(ProductBiz) ra.createInstance(pb); //productBizProxy.addProduct(); LogAdvice la=new LogAdvice(); ProductBiz productBizProxy2=(ProductBiz) la.createInstance(productBizProxy); productBizProxy2.addProduct(); StudentBiz sb=new StudentBizImpl(); StudentBiz studentBizRightProxy=(StudentBiz) ra.createInstance(sb); studentBizRightProxy.findAll(); ProductBiz productBizProxy3=(ProductBiz) la.createInstance(productBizProxy); productBizProxy3.addProduct(); } } 会报错 Exception in thread "main" java.lang.reflect.UndeclaredThrowableException(简单引用) 这是因为,代理也是引用机制,同一个代理,代理不同的目标类,只有一个代理引用,所以当ra代理过StudentBIz后,再用ProductBiz productBizProxy3=(ProductBiz) la.createInstance(productBizProxy);时出错,解决方法就是,不要再用引用,重新new一个代理即可修改如下 ProductBiz productBizLogProxy=(ProductBiz) la.createInstance(ra.createInstance(pb));
源代码下载地址http://download.csdn.net/detail/growing_it_bird/8978017
相关文章推荐
- [笔记][Java7并发编程实战手册]2.4在同步代码中使用条件-生产者与消费者
- Java生成和操作Excel文件
- 利用Java反射机制和泛型,全自动解析json
- java命令行运行main时jar及其配置
- Java串口通信 ----> 扫描标签获取数据存入数据库
- javaweb中利用filter进行修改字符集
- Spring AOP 实现原理
- java char 和 int 向上转型
- [Java]如何避免啰嗦的代码风格
- 在eclipse 中运行 需sudo root权限执行的程序
- java 集合框架 泛型--15
- java生成csv格式的文件
- spring中scope作用域(转)
- Java加密与解密的艺术-读书笔记1-2章
- Java反射机制之类类型
- JAVA学习笔记(五)
- java i++ 和 ++i 深度解析
- 学习笔记——ajax传值数组对象中遇到的问题
- 2014届华为校园招聘机试题(java实现)
- Java:谈谈protected访问权限