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 

二、代码实现

1package com.fy.spring.proxy; 2 3public interface UserManager { 4 public void addUser(String id, String password); 5 public void delUser(String id); 6} 7 8package com.fy.spring.proxy; 9 10public class UserManagerImpl implements UserManager { 11 12 public void addUser(String id, String password) { 13 System.out.println(".: 掉用了UserManagerImpl.addUser()方法! "); 14 15 } 16 17 public void delUser(String id) { 18 System.out.println(".: 掉用了UserManagerImpl.delUser()方法! "); 19 20 } 21}

JDK动态代理类

1package com.fy.spring.proxy; 2import java.lang.reflect.InvocationHandler; 3import java.lang.reflect.Method; 4import java.lang.reflect.Proxy; 5/** 6 * 7 * JDK动态代理类 8 * 9 * 10 */ 11public 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动态代理类

1package com.fy.spring.proxy; 2 3import java.lang.reflect.Method; 4 5import net.sf.cglib.proxy.Enhancer; 6import net.sf.cglib.proxy.MethodInterceptor; 7import net.sf.cglib.proxy.MethodProxy; 8 9/** 10 * CGLibProxy动态代理类的实例 11 * 12 * 13 */ 14public 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}

测试类:

1public 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}

运行结果:

1-----------CGLibProxy------------- 2检查权限 checkPopedom()! 3掉用了UserManagerImpl.addUser()方法! 4-----------JDKProxy------------- 5检查权限 checkPopedom()! 6掉用了UserManagerImpl.addUser()方法!

cglib动态代理

1、 CGlib是一个强大的,高性能,高质量的Code生成类库,CGLib 必须依赖于CGLib的类库。它可以在运行期扩展Java类与实现Java接口。 
2、 用CGlib生成代理类是目标类的子类。 
3、 用CGlib生成 代理类不需要接口 
4、 用CGLib生成的代理类重写了父类的各个方法。 
5、 拦截器中的intercept方法内容正好就是代理类中的方法体

JDK代理是不需要以来第三方的库,只要要JDK环境就可以进行代理,它有几个要求
* 实现InvocationHandler 
* 使用Proxy.newProxyInstance产生代理对象
* 被代理的对象必须要实现接口

spring两种代理方式

  1. 若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。 
    优点:因为有接口,所以使系统更加松耦合 
    缺点:为每一个目标类创建接口
  2. 若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。 
    优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。 
    缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

JDK动态代理和Cglib的动态代理

最简单的是静态代理方法,即代理模式,这里就不多啰嗦了。。重点说一下JDK的动态代理和Cglib的动态代理吧先说JDK的,需要被代理的类需要有接口,否则无法实现package proxy.dynamic;public interface IBook {void add();}实现接口

CGLIB介绍与原理(通过继承的动态代理)

一、什么是CGLIB?CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。二、CGLIB原理CGLIB原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的

Spring的Aop调用当前类的两种方法

我们知道Spring对于AOP实现有两种方法,如果类是接口实现类,则采用JDK动态代理实现AOP。如果类没有实现接口,则采用cglib生成子类做增强,以实现代理类的目的,其实运行时找到的是这个代理类,而不是原类。所以在一个代理类中调用内部的方法,是不是再走AOP逻辑的,那有什么好的方法可以解决这种问题吗?基于上面的思路有两种解决办法方法一:直接从