Spring的两种代理JDK和CGLIB的区别浅谈

来源:互联网 发布:mac打开远程桌面 编辑:程序博客网 时间:2024/06/05 14:18

Spring的两种代理JDK和CGLIB的区别浅谈


一、原理区别:

Java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 

3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

如何强制使用CGLIB实现AOP?
 (1)添加CGLIB库,SPRING_HOME/cglib/*.jar
 (2)在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>

JDK动态代理和CGLIB字节码生成的区别?
 (1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类
 (2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
   因为是继承,所以该类或方法最好不要声明成final 

二、代码实现

[html] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. package com.fy.spring.proxy;    
  2.     
  3. public interface UserManager {    
  4.     public void addUser(String id, String password);    
  5.     public void delUser(String id);    
  6. }   

[html] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. package com.fy.spring.proxy;    
  2.     
  3. public class UserManagerImpl implements UserManager {    
  4.     
  5.     public void addUser(String id, String password) {    
  6.         System.out.println(".: 掉用了UserManagerImpl.addUser()方法! ");    
  7.     
  8.     }    
  9.     
  10.     public void delUser(String id) {    
  11.         System.out.println(".: 掉用了UserManagerImpl.delUser()方法! ");    
  12.     
  13.     }    
  14. }   
JDK动态代理类

[html] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. package com.fy.spring.proxy;    
  2. import java.lang.reflect.InvocationHandler;    
  3. import java.lang.reflect.Method;    
  4. import java.lang.reflect.Proxy;    
  5. /**   
  6.  *    
  7.  * JDK动态代理类   
  8.  *    
  9.  *   
  10.  */    
  11. public class JDKProxy implements InvocationHandler {    
  12.     
  13.     private Object targetObject;//需要代理的目标对象    
  14.     
  15.     public Object newProxy(Object targetObject) {//将目标对象传入进行代理    
  16.         this.targetObject = targetObject;     
  17.         return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),    
  18.                 targetObject.getClass().getInterfaces(), this);//返回代理对象    
  19.     }    
  20.     
  21.     public Object invoke(Object proxy, Method method, Object[] args)//invoke方法    
  22.             throws Throwable {    
  23.         checkPopedom();//一般我们进行逻辑处理的函数比如这个地方是模拟检查权限    
  24.         Object ret = null;      // 设置方法的返回值    
  25.         ret  = method.invoke(targetObject, args);       //调用invoke方法,ret存储该方法的返回值    
  26.         return ret;    
  27.     }    
  28.     
  29.     private void checkPopedom() {//模拟检查权限的例子    
  30.         System.out.println(".:检查权限  checkPopedom()!");    
  31.     }    
  32. }    
CGLibProxy动态代理类

[html] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. package com.fy.spring.proxy;    
  2.     
  3. import java.lang.reflect.Method;    
  4.     
  5. import net.sf.cglib.proxy.Enhancer;    
  6. import net.sf.cglib.proxy.MethodInterceptor;    
  7. import net.sf.cglib.proxy.MethodProxy;    
  8.     
  9. /**   
  10.  * CGLibProxy动态代理类的实例   
  11.  *     
  12.  *    
  13.  */    
  14. public class CGLibProxy implements MethodInterceptor {    
  15.     
  16.     private Object targetObject;// CGLib需要代理的目标对象    
  17.     
  18.     public Object createProxyObject(Object obj) {    
  19.         this.targetObject = obj;    
  20.         Enhancer enhancer = new Enhancer();    
  21.         enhancer.setSuperclass(obj.getClass());    
  22.         enhancer.setCallback(this);    
  23.         Object proxyObj = enhancer.create();    
  24.         return proxyObj;// 返回代理对象    
  25.     }    
  26.     
  27.     public Object intercept(Object proxy, Method method, Object[] args,    
  28.             MethodProxy methodProxy) throws Throwable {    
  29.         Object obj = null;    
  30.         if ("addUser".equals(method.getName())) {// 过滤方法    
  31.             checkPopedom();// 检查权限    
  32.         }    
  33.         obj = method.invoke(targetObject, args);    
  34.         return obj;    
  35.     }    
  36.     
  37.     private void checkPopedom() {    
  38.         System.out.println(".:检查权限  checkPopedom()!");    
  39.     }    
  40. }    
测试类:

[html] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. public class Client {    
  2.     
  3.     public static void main(String[] args) {    
  4.     
  5.         UserManager userManager = (UserManager) new CGLibProxy()    
  6.                 .createProxyObject(new UserManagerImpl());    
  7.         System.out.println("-----------CGLibProxy-------------");    
  8.         userManager.addUser("tom", "root");    
  9.         System.out.println("-----------JDKProxy-------------");    
  10.         JDKProxy jdkPrpxy = new JDKProxy();    
  11.         UserManager userManagerJDK = (UserManager) jdkPrpxy    
  12.                 .newProxy(new UserManagerImpl());    
  13.         userManagerJDK.addUser("tom", "root");    
  14.     }    
  15.     
  16. }   
运行结果:

[html] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. -----------CGLibProxy-------------    
  2. 检查权限  checkPopedom()!    
  3. 掉用了UserManagerImpl.addUser()方法!     
  4. -----------JDKProxy-------------    
  5. 检查权限  checkPopedom()!    
  6. 掉用了UserManagerImpl.addUser()方法!  

JDK代理是不需要以来第三方的库,只要要JDK环境就可以进行代理,它有几个要求
* 实现InvocationHandler 
* 使用Proxy.newProxyInstance产生代理对象
* 被代理的对象必须要实现接口
CGLib 必须依赖于CGLib的类库,但是它需要类来实现任何接口代理的是指定的类生成一个子类,覆盖其中的方法,是一种继承但是针对接口编程的环境下推荐使用JDK的代理
在Hibernate中的拦截器其实现考虑到不需要其他接口的条件Hibernate中的相关代理采用的是CGLib来执行。
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 注册消防工程师考试难度 一级消防工程师考试题型 注册二级消防工程师 注册消防工程师论坛 一级注册消防工程师教材 注册消防工程师报名 二级消防工程师考试科目 消防工程师报考条件二级 二级注册消防工程师报考条件 一级注册消防工程师论坛 二级消防工程师好考吗 一级注册消防工程师招聘 注册消防工程师难考吗 考一级消防工程师有用吗 消防工程师难度 一消防工程师 一级消防工程师考试难度 一级消防工程师好考吗 消防工程师待遇 注册消防工程师一级二级区别 一级注册消防工程师好考吗 注册消防工程师好不好考 一级消防工程师难度 二级注册消防工程师考试科目 二级消防考试时间 一级消防工程师招聘 陕西二级消防工程师报名时间 2017消防工程师考试时间 消防工程师代报名 消防技术综合能力 一级注册消防工程师报考条件 河北二级消防工程师报名时间 二级消防工程师报名条件 消防员考试报考条件 消防技术实务 一级注册消防工程师报名时间 消防安全工程师考试时间 消防注册工程师报考条件 2017一级消防工程师报名时间 二级消防考试科目 辽宁消防工程师报名时间