【spring】Cglib动态代理的使用
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动态代理的使用相关推荐
- 浅谈Spring中JDK动态代理与CGLIB动态代理
前言 Spring是Java程序员基本不可能绕开的一个框架,它的核心思想是IOC(控制反转)和AOP(面向切面编程).在Spring中这两个核心思想都是基于设计模式实现的,IOC思想的实现基于工厂模式 ...
- spring框架中JDK和CGLIB动态代理区别
转载:https://blog.csdn.net/yhl_jxy/article/details/80635012 前言 JDK动态代理实现原理(jdk8):https://blog.csdn.net ...
- Spring的两种代理方式:JDK动态代理和CGLIB动态代理
代理模式 代理模式的英文叫做Proxy或Surrogate,中文都可译为"代理",所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者 ...
- Spring : Spring Aop CGLIB动态代理调用过程
1.美图 2.概述 CGLIB动态代理参考: CGLIB动态代理 CGLIB原理解析参考:CGLIB原理解析 3.分析 Spring AOP CGLIB动态代理调用过程分析,CGLIB动态代理调用过程 ...
- Spring : Spring Aop JDK和CGLIB动态代理调用过程
1.美图 2.概述 3.Spring Aop JDK动态代理调用过程 参考:Spring Aop JDK动态代理调用过程 4. Spring Aop CGLIB动态代理调用过程 参考:
- Spring : 静态代理模式和JDK、CGLIB动态代理
1.美图 2.概述 为了更好的分析分析Spring的另一个核心功能AOP,需要先温习一下动态代理的知识,如果对java的动态代理无所了解的话,那么对AOP源码的分析就无从谈起.代理模式可分为静态代理和 ...
- Spring 静态代理+JDK动态代理和CGLIB动态代理
代理分为两种:静态代理 动态代理 静态代理:本质上会在硬盘上创建一个真正的物理类 动态代理:本质上是在内存中构建出一个类. 如果多个类需要进行方法增强,静态代理则需要创建多个物理类,占用磁盘空间.而动 ...
- java中的静态、动态代理模式以及Spring中的CgLib动态代理解读(面试必问)
java中的静态.动态代理模式以及Spring中的CgLib动态代理解读(面试必问) 静态代理 动态代理 CgLib动态代理 基础知: 反射知识 代理(Proxy)是一种设计模式,提供了对目标 ...
- AOP、ASPECT、Spring AOP、JDK动态代理、CGLib动态代理
AOP.ASPECT.Spring AOP.JDK动态代理.CGLib动态代理 1 AOP介绍 1.1 基本定义 AOP(Aspect Oriented Programming)称为面向切面编程,它是 ...
- Spring AOP之---基于JDK动态代理和CGLib动态代理的AOP实现
AOP(面向切面编程)是OOP的有益补充,它只适合那些具有横切逻辑的应用场合,如性能监测,访问控制,事物管理,日志记录等.至于怎么理解横切逻辑,敲完实例代码也就明白了. 为什么要使用AOP,举个栗子: ...
最新文章
- 装上后这 14 个插件后,PyCharm 真的是无敌的存在
- Spec Explorer 工具学习
- 大规模图训练调优指南
- 精武风云全线公映,挂马欺诈网站同步上线
- 数据结构入门(一级)
- SCI/EI期刊投稿 Reply Letter 常用格式总结
- linux直播电视软件下载,周末了!通过Linux Mint开发的IPTV播放器观看海量国内外直播电视...
- 语音识别技术竟然发展如此迅速
- 转帖 美国 工程索引 收录中国科技论文的最新规定
- 简要介绍弱监督学习(by 周志华)
- chrome源码国内下载
- 记录一次Visual Studio运行webservice调用中控打卡机出现的问题
- 图片和文字对齐的方法
- adb不是内部或外部命令,AndroidStudio中ADB命令不能用的问题
- The source branch is being deleted
- SysML实践指南第二版(中文翻译:刘亚龙)第17章 OOSEM方法学
- MySQL 数据表优化设计(九):如何设计统计数据表?
- Direct2D入门
- Github已标星80,java语言自学教程
- 正则验证连续重复字符、连续递增递减数字
热门文章
- Jenkins在windows下的安装和部署
- office2010字体包_在Office 2010中使用高级字体连字
- 组合数学拉丁方是什么
- 求!微信语音是怎么转发给别人的原理
- 文档与文件比较工具简单汇总
- [528]attrib隐藏文件夹
- [渝粤教育] 中国地质大学 战略管理 复习题 (2)
- 大学生计算机高级应用实验一,计算机公共基础与MS Office 2016高级应用习题及实验指导--详细介绍...
- Java/Swing 图形界面范例
- 7-144 最矮的巨人