cglib代理使用ASM对字节码进行操作生成新的类,从而实现对对象方法的增强。我们都知道Java中自带了一个动态代理,那我们为什么不直接使用Java动态代理,而要使用cglib呢?因为cglib相比于JDK动态代理更加强大,JDK动态代理虽然简单易用,但是其有一个致命缺陷是,只能对接口进行代理。如果要代理的类为一个普通类、没有实现接口,那么Java动态代理就没法使用了。

cglib的使用

CallbackFilter

CglibCallbackFilter用来判断方法走那个Callback。

package com.morris.spring.demo.proxy.cglib;import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.CallbackFilter;import java.lang.reflect.Method;/*** CglibCallbackFilter用来判断方法走那个Callback*/
public class CglibCallbackFilter implements CallbackFilter {private final Callback[] callbacks;public CglibCallbackFilter(Callback[] callbacks) {this.callbacks = callbacks;Class<?>[] callbackTypes = new Class<?>[callbacks.length];for (int i = 0; i < callbacks.length; i++) {callbackTypes[i] = callbacks[i].getClass();}}@Overridepublic int accept(Method method) {for (int i = 0; i < this.callbacks.length; i++) {Callback callback = this.callbacks[i];if (!(callback instanceof ConditionalCallback) || ((ConditionalCallback) callback).isMatch(method)) {return i;}}throw new IllegalStateException("No callback available for method " + method.getName());}
}

ConditionalCallback

参考spring中的ConditionalCallback。

package com.morris.spring.demo.proxy.cglib;import org.springframework.cglib.proxy.Callback;import java.lang.reflect.Method;public interface ConditionalCallback extends Callback {boolean isMatch(Method candidateMethod);
}

InsertMethodInterceptor

InsertMethodInterceptor实现了MethodInterceptor接口,用来实现对方法的增强。

Insert开头的方法记录参数。

package com.morris.spring.demo.proxy.cglib;import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.lang.Nullable;import java.lang.reflect.Method;/*** Insert开头的方法记录参数*/
public class InsertMethodInterceptor implements MethodInterceptor, ConditionalCallback {@Override@Nullablepublic Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,MethodProxy cglibMethodProxy) throws Throwable {System.out.println("InsertMethodInterceptor " + beanMethod.getName() + " args: " + beanMethodArgs);Object result = cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);return result;}@Overridepublic boolean isMatch(Method method) {return method.getName().startsWith("insert");}
}

QueryMethodInterceptor

Query开头的方法记录返回值。

package com.morris.spring.demo.proxy.cglib;import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.lang.Nullable;import java.lang.reflect.Method;/*** Query开头的方法记录返回值*/
public class QueryMethodInterceptor implements MethodInterceptor, ConditionalCallback {@Override@Nullablepublic Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,MethodProxy cglibMethodProxy) throws Throwable {Object result = cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);System.out.println("QueryMethodInterceptor " + beanMethod.getName() + " result: " + result);return result;}@Overridepublic boolean isMatch(Method method) {return method.getName().startsWith("query");}
}

CglibProxyDemo

package com.morris.spring.demo.proxy.cglib;import com.morris.spring.service.UserService;
import com.morris.spring.service.UserServiceImpl;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.NoOp;/*** Cglib的使用*/
public class CglibProxyDemo {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserServiceImpl.class);Callback[] callback = new Callback[]{new InsertMethodInterceptor(),new QueryMethodInterceptor(),NoOp.INSTANCE};CglibCallbackFilter cglibCallbackFilter = new CglibCallbackFilter(callback);enhancer.setCallbackFilter(cglibCallbackFilter);enhancer.setCallbacks(callback);UserService o = (UserService) enhancer.create();o.query("hello");o.insert("hi");}
}

运行结果如下:

UserServiceImpl query hello
QueryMethodInterceptor query result: hello hello
InsertMethodInterceptor insert args: [Ljava.lang.Object;@18e5cde
UserServiceImpl insert hi

spring中的cglib与net.sf.cglib的区别

细心的你肯定发现了上面例子中cglib的API类都是位于org.springframework.cglib下,而不是net.sf.cglib,正常来说,使用cglib应该在pom.xml中引入下面的坐标:

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.2.2</version>
</dependency>

这是为什么呢?

这种方式这称为重新打包,项目不是使用某个库作为依赖项,而是将依赖项的副本作为其自己项目的一部分,并将其放在不同的包中。这样做的原因是使用Spring的项目可能想要使用cglib本身。如果Spring将特定版本的cglib作为依赖项,那么使用Spring的项目就不可能选择不同的版本。但是如果Spring使用不同包中的重新打包的cglib,则没有版本冲突,如果他们喜欢,项目可以使用任何版本的cglib。

我们可以在源码spring-core.gradle中发现重新打包的脚本:

task cglibRepackJar(type: ShadowJar) {baseName = 'spring-cglib-repack'version = cglibVersionconfigurations = [project.configurations.cglib]relocate 'net.sf.cglib', 'org.springframework.cglib'relocate 'org.objectweb.asm', 'org.springframework.asm'
}task objenesisRepackJar(type: ShadowJar) {baseName = 'spring-objenesis-repack'version = objenesisVersionconfigurations = [project.configurations.objenesis]relocate 'org.objenesis', 'org.springframework.objenesis'
}

查看cglib动态生成的类

可以通过设置属性System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "target/cglib")来查看cglib动态生成的类,当然也可以使用arthas工具。

cglib生成了多个类,其中最重要的是UserServiceImplEnhancerByCGLIBEnhancerByCGLIBEnhancerByCGLIBc09a6558,他会继承目标类UserServiceImpl。

package com.morris.spring.service;import java.lang.reflect.Method;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;public class UserServiceImpl$$EnhancerByCGLIB$$c09a6558 extends UserServiceImpl implements Factory {private boolean CGLIB$BOUND;public static Object CGLIB$FACTORY_DATA;private static final ThreadLocal CGLIB$THREAD_CALLBACKS;private static final Callback[] CGLIB$STATIC_CALLBACKS;private MethodInterceptor CGLIB$CALLBACK_0;private MethodInterceptor CGLIB$CALLBACK_1;private NoOp CGLIB$CALLBACK_2;private static Object CGLIB$CALLBACK_FILTER;private static final Method CGLIB$insert$0$Method;private static final MethodProxy CGLIB$insert$0$Proxy;private static final Object[] CGLIB$emptyArgs;private static final Method CGLIB$query$1$Method;private static final MethodProxy CGLIB$query$1$Proxy;static void CGLIB$STATICHOOK1() {CGLIB$THREAD_CALLBACKS = new ThreadLocal();CGLIB$emptyArgs = new Object[0];Class var0 = Class.forName("com.morris.spring.service.UserServiceImpl$$EnhancerByCGLIB$$c09a6558");Class var1;Method[] var10000 = ReflectUtils.findMethods(new String[]{"insert", "(Ljava/lang/String;)V", "query", "(Ljava/lang/String;)Ljava/lang/String;"}, (var1 = Class.forName("com.morris.spring.service.UserServiceImpl")).getDeclaredMethods());CGLIB$insert$0$Method = var10000[0];CGLIB$insert$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)V", "insert", "CGLIB$insert$0");CGLIB$query$1$Method = var10000[1];CGLIB$query$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "query", "CGLIB$query$1");}final void CGLIB$insert$0(String var1) {super.insert(var1);}public final void insert(String var1) {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}if (var10000 != null) {var10000.intercept(this, CGLIB$insert$0$Method, new Object[]{var1}, CGLIB$insert$0$Proxy);} else {super.insert(var1);}}final String CGLIB$query$1(String var1) {return super.query(var1);}public final String query(String var1) {MethodInterceptor var10000 = this.CGLIB$CALLBACK_1;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_1;}return var10000 != null ? (String)var10000.intercept(this, CGLIB$query$1$Method, new Object[]{var1}, CGLIB$query$1$Proxy) : super.query(var1);}public static MethodProxy CGLIB$findMethodProxy(Signature var0) {String var10000 = var0.toString();switch(var10000.hashCode()) {case -997399735:if (var10000.equals("query(Ljava/lang/String;)Ljava/lang/String;")) {return CGLIB$query$1$Proxy;}break;case -982250266:if (var10000.equals("insert(Ljava/lang/String;)V")) {return CGLIB$insert$0$Proxy;}}return null;}public UserServiceImpl$$EnhancerByCGLIB$$c09a6558() {CGLIB$BIND_CALLBACKS(this);}public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {CGLIB$THREAD_CALLBACKS.set(var0);}public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {CGLIB$STATIC_CALLBACKS = var0;}private static final void CGLIB$BIND_CALLBACKS(Object var0) {UserServiceImpl$$EnhancerByCGLIB$$c09a6558 var1 = (UserServiceImpl$$EnhancerByCGLIB$$c09a6558)var0;if (!var1.CGLIB$BOUND) {var1.CGLIB$BOUND = true;Object var10000 = CGLIB$THREAD_CALLBACKS.get();if (var10000 == null) {var10000 = CGLIB$STATIC_CALLBACKS;if (var10000 == null) {return;}}Callback[] var10001 = (Callback[])var10000;var1.CGLIB$CALLBACK_2 = (NoOp)((Callback[])var10000)[2];var1.CGLIB$CALLBACK_1 = (MethodInterceptor)var10001[1];var1.CGLIB$CALLBACK_0 = (MethodInterceptor)var10001[0];}}public Object newInstance(Callback[] var1) {CGLIB$SET_THREAD_CALLBACKS(var1);UserServiceImpl$$EnhancerByCGLIB$$c09a6558 var10000 = new UserServiceImpl$$EnhancerByCGLIB$$c09a6558();CGLIB$SET_THREAD_CALLBACKS((Callback[])null);return var10000;}public Object newInstance(Callback var1) {throw new IllegalStateException("More than one callback object required");}public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {CGLIB$SET_THREAD_CALLBACKS(var3);UserServiceImpl$$EnhancerByCGLIB$$c09a6558 var10000 = new UserServiceImpl$$EnhancerByCGLIB$$c09a6558;switch(var1.length) {case 0:var10000.<init>();CGLIB$SET_THREAD_CALLBACKS((Callback[])null);return var10000;default:throw new IllegalArgumentException("Constructor not found");}}public Callback getCallback(int var1) {CGLIB$BIND_CALLBACKS(this);Object var10000;switch(var1) {case 0:var10000 = this.CGLIB$CALLBACK_0;break;case 1:var10000 = this.CGLIB$CALLBACK_1;break;case 2:var10000 = this.CGLIB$CALLBACK_2;break;default:var10000 = null;}return (Callback)var10000;}public void setCallback(int var1, Callback var2) {switch(var1) {case 0:this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;break;case 1:this.CGLIB$CALLBACK_1 = (MethodInterceptor)var2;break;case 2:this.CGLIB$CALLBACK_2 = (NoOp)var2;}}public Callback[] getCallbacks() {CGLIB$BIND_CALLBACKS(this);return new Callback[]{this.CGLIB$CALLBACK_0, this.CGLIB$CALLBACK_1, this.CGLIB$CALLBACK_2};}public void setCallbacks(Callback[] var1) {this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];this.CGLIB$CALLBACK_1 = (MethodInterceptor)var1[1];this.CGLIB$CALLBACK_2 = (NoOp)var1[2];}static {CGLIB$STATICHOOK1();}
}

【spring】Cglib动态代理的使用相关推荐

  1. 浅谈Spring中JDK动态代理与CGLIB动态代理

    前言 Spring是Java程序员基本不可能绕开的一个框架,它的核心思想是IOC(控制反转)和AOP(面向切面编程).在Spring中这两个核心思想都是基于设计模式实现的,IOC思想的实现基于工厂模式 ...

  2. spring框架中JDK和CGLIB动态代理区别

    转载:https://blog.csdn.net/yhl_jxy/article/details/80635012 前言 JDK动态代理实现原理(jdk8):https://blog.csdn.net ...

  3. Spring的两种代理方式:JDK动态代理和CGLIB动态代理

    代理模式 代理模式的英文叫做Proxy或Surrogate,中文都可译为"代理",所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者 ...

  4. Spring : Spring Aop CGLIB动态代理调用过程

    1.美图 2.概述 CGLIB动态代理参考: CGLIB动态代理 CGLIB原理解析参考:CGLIB原理解析 3.分析 Spring AOP CGLIB动态代理调用过程分析,CGLIB动态代理调用过程 ...

  5. Spring : Spring Aop JDK和CGLIB动态代理调用过程

    1.美图 2.概述 3.Spring Aop JDK动态代理调用过程 参考:Spring Aop JDK动态代理调用过程 4. Spring Aop CGLIB动态代理调用过程 参考:

  6. Spring : 静态代理模式和JDK、CGLIB动态代理

    1.美图 2.概述 为了更好的分析分析Spring的另一个核心功能AOP,需要先温习一下动态代理的知识,如果对java的动态代理无所了解的话,那么对AOP源码的分析就无从谈起.代理模式可分为静态代理和 ...

  7. Spring 静态代理+JDK动态代理和CGLIB动态代理

    代理分为两种:静态代理 动态代理 静态代理:本质上会在硬盘上创建一个真正的物理类 动态代理:本质上是在内存中构建出一个类. 如果多个类需要进行方法增强,静态代理则需要创建多个物理类,占用磁盘空间.而动 ...

  8. java中的静态、动态代理模式以及Spring中的CgLib动态代理解读(面试必问)

    java中的静态.动态代理模式以及Spring中的CgLib动态代理解读(面试必问) 静态代理 动态代理 CgLib动态代理     基础知: 反射知识 代理(Proxy)是一种设计模式,提供了对目标 ...

  9. AOP、ASPECT、Spring AOP、JDK动态代理、CGLib动态代理

    AOP.ASPECT.Spring AOP.JDK动态代理.CGLib动态代理 1 AOP介绍 1.1 基本定义 AOP(Aspect Oriented Programming)称为面向切面编程,它是 ...

  10. Spring AOP之---基于JDK动态代理和CGLib动态代理的AOP实现

    AOP(面向切面编程)是OOP的有益补充,它只适合那些具有横切逻辑的应用场合,如性能监测,访问控制,事物管理,日志记录等.至于怎么理解横切逻辑,敲完实例代码也就明白了. 为什么要使用AOP,举个栗子: ...

最新文章

  1. 装上后这 14 个插件后,PyCharm 真的是无敌的存在
  2. Spec Explorer 工具学习
  3. 大规模图训练调优指南
  4. 精武风云全线公映,挂马欺诈网站同步上线
  5. 数据结构入门(一级)
  6. SCI/EI期刊投稿 Reply Letter 常用格式总结
  7. linux直播电视软件下载,周末了!通过Linux Mint开发的IPTV播放器观看海量国内外直播电视...
  8. 语音识别技术竟然发展如此迅速
  9. 转帖 美国 工程索引 收录中国科技论文的最新规定
  10. 简要介绍弱监督学习(by 周志华)
  11. chrome源码国内下载
  12. 记录一次Visual Studio运行webservice调用中控打卡机出现的问题
  13. 图片和文字对齐的方法
  14. adb不是内部或外部命令,AndroidStudio中ADB命令不能用的问题
  15. The source branch is being deleted
  16. SysML实践指南第二版(中文翻译:刘亚龙)第17章 OOSEM方法学
  17. MySQL 数据表优化设计(九):如何设计统计数据表?
  18. Direct2D入门
  19. Github已标星80,java语言自学教程
  20. 正则验证连续重复字符、连续递增递减数字

热门文章

  1. Jenkins在windows下的安装和部署
  2. office2010字体包_在Office 2010中使用高级字体连字
  3. 组合数学拉丁方是什么
  4. 求!微信语音是怎么转发给别人的原理
  5. 文档与文件比较工具简单汇总
  6. [528]attrib隐藏文件夹
  7. [渝粤教育] 中国地质大学 战略管理 复习题 (2)
  8. 大学生计算机高级应用实验一,计算机公共基础与MS Office 2016高级应用习题及实验指导--详细介绍...
  9. Java/Swing 图形界面范例
  10. 7-144 最矮的巨人