动态代理 (CGLIB 动态代理)

﹏ヽ暗。殇╰゛Y 2022-02-01 08:21 482阅读 0赞

动态代理 代理类在程序运行时被创建,这种代理方式称为动态代理

动态代理实现有两种方式,JDK 动态代理和 CGlib 动态代理,本文介绍 CGlib 动态代理

CGLib 动态代理:采用底层的字节码技术,可以为一个类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用,并在调用中添加横切逻辑

CGLib 动态代理示例代码

创建一个普通 maven 工程,引入 CGLib 依赖

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  2. <modelVersion>4.0.0</modelVersion>
  3. <groupId>com.cglibdynamicproxy</groupId>
  4. <artifactId>cglibdynamicproxy</artifactId>
  5. <version>0.0.1-SNAPSHOT</version>
  6. <name>cglibdynamicproxy</name>
  7. <dependencies>
  8. <!-- 引入cglib依赖 -->
  9. <dependency>
  10. <groupId>cglib</groupId>
  11. <artifactId>cglib</artifactId>
  12. <version>3.2.5</version>
  13. </dependency>
  14. </dependencies>
  15. <build>
  16. <plugins>
  17. <plugin>
  18. <artifactId>maven-compiler-plugin</artifactId>
  19. <configuration>
  20. <source>1.8</source>
  21. <target>1.8</target>
  22. </configuration>
  23. </plugin>
  24. </plugins>
  25. </build>
  26. </project>

创建被代理类

  1. package com.cglibdynamicproxy.service;
  2. /**
  3. * 被代理类
  4. * @author Administrator
  5. */
  6. public class AgentTarget {
  7. public void proxyMethod() {
  8. System.out.println("被代理的方法执行了");;
  9. }
  10. }

创建 CglibMethodInterceptor 类,实现 MethodInterceptor

  1. package com.cglibdynamicproxy.cglib;
  2. import java.lang.reflect.Method;
  3. import net.sf.cglib.proxy.MethodInterceptor;
  4. import net.sf.cglib.proxy.MethodProxy;
  5. public class CglibMethodInterceptor implements MethodInterceptor{
  6. /**
  7. * 拦截父类所有方法的调用
  8. */
  9. @Override
  10. public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
  11. //obj 目标类的实例
  12. //method 目标类方法的反射对象
  13. //args 方法的动态入参
  14. //proxy 代理类实例
  15. System.out.println("before");
  16. Object res = null;
  17. try{
  18. //反射调用目标对象方法
  19. res = proxy.invokeSuper(obj, args);
  20. }catch (Exception e){
  21. System.out.println("e:" + e.getMessage());
  22. throw e;
  23. }finally {
  24. System.out.println("after");
  25. }
  26. return res;
  27. }
  28. }

测试类

  1. package com.cglibdynamicproxy;
  2. import com.cglibdynamicproxy.cglib.CglibMethodInterceptor;
  3. import com.cglibdynamicproxy.service.AgentTarget;
  4. import net.sf.cglib.core.DebuggingClassWriter;
  5. import net.sf.cglib.proxy.Enhancer;
  6. public class CglibDynamicProxyMain {
  7. public static void main(String[] args) {
  8. //将生成的class文件保存到指定目录,这里是项目目录
  9. System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\workspace\\cglibdynamicproxy");
  10. Enhancer enhancer = new Enhancer();
  11. //设置父类
  12. enhancer.setSuperclass(AgentTarget.class);
  13. //设置回调函数
  14. enhancer.setCallback(new CglibMethodInterceptor());
  15. //创建AgentTarget.class的子类
  16. AgentTarget childAgentTarget = (AgentTarget) enhancer.create();
  17. //调用方法
  18. childAgentTarget.proxyMethod();
  19. }
  20. }

运行如下

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dzanp6Y2Jx_size_16_color_FFFFFF_t_70

生成的 class 文件

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dzanp6Y2Jx_size_16_color_FFFFFF_t_70 1

重点看生成的这个文件 AgentTargetEnhancerByCGLIB303de0ca.class

代码如下

  1. package com.cglibdynamicproxy.service;
  2. import java.lang.reflect.Method;
  3. import net.sf.cglib.core.ReflectUtils;
  4. import net.sf.cglib.core.Signature;
  5. import net.sf.cglib.proxy.Callback;
  6. import net.sf.cglib.proxy.Factory;
  7. import net.sf.cglib.proxy.MethodInterceptor;
  8. import net.sf.cglib.proxy.MethodProxy;
  9. public class AgentTarget$$EnhancerByCGLIB$$303de0ca extends AgentTarget implements Factory {
  10. private boolean CGLIB$BOUND;
  11. public static Object CGLIB$FACTORY_DATA;
  12. private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
  13. private static final Callback[] CGLIB$STATIC_CALLBACKS;
  14. private MethodInterceptor CGLIB$CALLBACK_0;
  15. private static Object CGLIB$CALLBACK_FILTER;
  16. private static final Method CGLIB$proxyMethod$0$Method;
  17. private static final MethodProxy CGLIB$proxyMethod$0$Proxy;
  18. private static final Object[] CGLIB$emptyArgs;
  19. private static final Method CGLIB$equals$1$Method;
  20. private static final MethodProxy CGLIB$equals$1$Proxy;
  21. private static final Method CGLIB$toString$2$Method;
  22. private static final MethodProxy CGLIB$toString$2$Proxy;
  23. private static final Method CGLIB$hashCode$3$Method;
  24. private static final MethodProxy CGLIB$hashCode$3$Proxy;
  25. private static final Method CGLIB$clone$4$Method;
  26. private static final MethodProxy CGLIB$clone$4$Proxy;
  27. static void CGLIB$STATICHOOK1() {
  28. CGLIB$THREAD_CALLBACKS = new ThreadLocal();
  29. CGLIB$emptyArgs = new Object[0];
  30. Class var0 = Class.forName("com.cglibdynamicproxy.service.AgentTarget$$EnhancerByCGLIB$$303de0ca");
  31. Class var1;
  32. CGLIB$proxyMethod$0$Method = ReflectUtils.findMethods(new String[]{"proxyMethod", "()V"},
  33. (var1 = Class.forName("com.cglibdynamicproxy.service.AgentTarget")).getDeclaredMethods())[0];
  34. CGLIB$proxyMethod$0$Proxy = MethodProxy.create(var1, var0, "()V", "proxyMethod", "CGLIB$proxyMethod$0");
  35. Method[] var10000 = ReflectUtils.findMethods(
  36. new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I",
  37. "clone", "()Ljava/lang/Object;"},
  38. (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
  39. CGLIB$equals$1$Method = var10000[0];
  40. CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
  41. CGLIB$toString$2$Method = var10000[1];
  42. CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
  43. CGLIB$hashCode$3$Method = var10000[2];
  44. CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
  45. CGLIB$clone$4$Method = var10000[3];
  46. CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
  47. }
  48. final void CGLIB$proxyMethod$0() {
  49. super.proxyMethod();
  50. }
  51. public final void proxyMethod() {
  52. MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
  53. if (this.CGLIB$CALLBACK_0 == null) {
  54. CGLIB$BIND_CALLBACKS(this);
  55. var10000 = this.CGLIB$CALLBACK_0;
  56. }
  57. if (var10000 != null) {
  58. var10000.intercept(this, CGLIB$proxyMethod$0$Method, CGLIB$emptyArgs, CGLIB$proxyMethod$0$Proxy);
  59. } else {
  60. super.proxyMethod();
  61. }
  62. }
  63. final boolean CGLIB$equals$1(Object var1) {
  64. return super.equals(var1);
  65. }
  66. public final boolean equals(Object var1) {
  67. MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
  68. if (this.CGLIB$CALLBACK_0 == null) {
  69. CGLIB$BIND_CALLBACKS(this);
  70. var10000 = this.CGLIB$CALLBACK_0;
  71. }
  72. if (var10000 != null) {
  73. Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
  74. return var2 == null ? false : (Boolean) var2;
  75. } else {
  76. return super.equals(var1);
  77. }
  78. }
  79. final String CGLIB$toString$2() {
  80. return super.toString();
  81. }
  82. public final String toString() {
  83. MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
  84. if (this.CGLIB$CALLBACK_0 == null) {
  85. CGLIB$BIND_CALLBACKS(this);
  86. var10000 = this.CGLIB$CALLBACK_0;
  87. }
  88. return var10000 != null
  89. ? (String) var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy)
  90. : super.toString();
  91. }
  92. final int CGLIB$hashCode$3() {
  93. return super.hashCode();
  94. }
  95. public final int hashCode() {
  96. MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
  97. if (this.CGLIB$CALLBACK_0 == null) {
  98. CGLIB$BIND_CALLBACKS(this);
  99. var10000 = this.CGLIB$CALLBACK_0;
  100. }
  101. if (var10000 != null) {
  102. Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
  103. return var1 == null ? 0 : ((Number) var1).intValue();
  104. } else {
  105. return super.hashCode();
  106. }
  107. }
  108. final Object CGLIB$clone$4() throws CloneNotSupportedException {
  109. return super.clone();
  110. }
  111. protected final Object clone() throws CloneNotSupportedException {
  112. MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
  113. if (this.CGLIB$CALLBACK_0 == null) {
  114. CGLIB$BIND_CALLBACKS(this);
  115. var10000 = this.CGLIB$CALLBACK_0;
  116. }
  117. return var10000 != null
  118. ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy)
  119. : super.clone();
  120. }
  121. public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
  122. String var10000 = var0.toString();
  123. switch (var10000.hashCode()) {
  124. case -508378822 :
  125. if (var10000.equals("clone()Ljava/lang/Object;")) {
  126. return CGLIB$clone$4$Proxy;
  127. }
  128. break;
  129. case -472693722 :
  130. if (var10000.equals("proxyMethod()V")) {
  131. return CGLIB$proxyMethod$0$Proxy;
  132. }
  133. break;
  134. case 1826985398 :
  135. if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
  136. return CGLIB$equals$1$Proxy;
  137. }
  138. break;
  139. case 1913648695 :
  140. if (var10000.equals("toString()Ljava/lang/String;")) {
  141. return CGLIB$toString$2$Proxy;
  142. }
  143. break;
  144. case 1984935277 :
  145. if (var10000.equals("hashCode()I")) {
  146. return CGLIB$hashCode$3$Proxy;
  147. }
  148. }
  149. return null;
  150. }
  151. public AgentTarget$$EnhancerByCGLIB$$303de0ca() {
  152. CGLIB$BIND_CALLBACKS(this);
  153. }
  154. public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
  155. CGLIB$THREAD_CALLBACKS.set(var0);
  156. }
  157. public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
  158. CGLIB$STATIC_CALLBACKS = var0;
  159. }
  160. private static final void CGLIB$BIND_CALLBACKS(Object var0) {
  161. AgentTarget$$EnhancerByCGLIB$$303de0ca var1 = (AgentTarget$$EnhancerByCGLIB$$303de0ca) var0;
  162. if (!var1.CGLIB$BOUND) {
  163. var1.CGLIB$BOUND = true;
  164. Object var10000 = CGLIB$THREAD_CALLBACKS.get();
  165. if (var10000 == null) {
  166. var10000 = CGLIB$STATIC_CALLBACKS;
  167. if (CGLIB$STATIC_CALLBACKS == null) {
  168. return;
  169. }
  170. }
  171. var1.CGLIB$CALLBACK_0 = (MethodInterceptor) ((Callback[]) var10000)[0];
  172. }
  173. }
  174. public Object newInstance(Callback[] var1) {
  175. CGLIB$SET_THREAD_CALLBACKS(var1);
  176. AgentTarget$$EnhancerByCGLIB$$303de0ca var10000 = new AgentTarget$$EnhancerByCGLIB$$303de0ca();
  177. CGLIB$SET_THREAD_CALLBACKS((Callback[]) null);
  178. return var10000;
  179. }
  180. public Object newInstance(Callback var1) {
  181. CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
  182. AgentTarget$$EnhancerByCGLIB$$303de0ca var10000 = new AgentTarget$$EnhancerByCGLIB$$303de0ca();
  183. CGLIB$SET_THREAD_CALLBACKS((Callback[]) null);
  184. return var10000;
  185. }
  186. public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
  187. CGLIB$SET_THREAD_CALLBACKS(var3);
  188. AgentTarget$$EnhancerByCGLIB$$303de0ca var10000 = new AgentTarget$$EnhancerByCGLIB$$303de0ca;
  189. switch(var1.length) {
  190. case 0:
  191. var10000.<init>();
  192. CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
  193. return var10000;
  194. default:
  195. throw new IllegalArgumentException("Constructor not found");
  196. }
  197. }
  198. public Callback getCallback(int var1) {
  199. CGLIB$BIND_CALLBACKS(this);
  200. MethodInterceptor var10000;
  201. switch (var1) {
  202. case 0 :
  203. var10000 = this.CGLIB$CALLBACK_0;
  204. break;
  205. default :
  206. var10000 = null;
  207. }
  208. return var10000;
  209. }
  210. public void setCallback(int var1, Callback var2) {
  211. switch (var1) {
  212. case 0 :
  213. this.CGLIB$CALLBACK_0 = (MethodInterceptor) var2;
  214. default :
  215. }
  216. }
  217. public Callback[] getCallbacks() {
  218. CGLIB$BIND_CALLBACKS(this);
  219. return new Callback[]{this.CGLIB$CALLBACK_0};
  220. }
  221. public void setCallbacks(Callback[] var1) {
  222. this.CGLIB$CALLBACK_0 = (MethodInterceptor) var1[0];
  223. }
  224. static {
  225. CGLIB$STATICHOOK1();
  226. }
  227. }

其中,这段代码为核心内容

  1. public final void proxyMethod() {
  2. MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
  3. if (this.CGLIB$CALLBACK_0 == null) {
  4. CGLIB$BIND_CALLBACKS(this);
  5. var10000 = this.CGLIB$CALLBACK_0;
  6. }
  7. if (var10000 != null) {
  8. var10000.intercept(this, CGLIB$proxyMethod$0$Method, CGLIB$emptyArgs, CGLIB$proxyMethod$0$Proxy);
  9. } else {
  10. super.proxyMethod();
  11. }
  12. }

程序运行流程:代理对象继承父类 AgentTarget,重写 proxyMethod 方法,拦截器调用 intercept 方法,intercept 方法由自定义的 CglibMethodInterceptor 实现,当调用 MyMethodInterceptor 中的 intercept 方法时,通过反射调用目标对象方法,从而完成了由代理对象访问到目标对象的动态代理

发表评论

表情:
评论列表 (有 0 条评论,482人围观)

还没有评论,来说两句吧...

相关阅读

    相关 CGLIB动态代理

    一 说明 使用火车站卖票,使用CGLIB代理实现。 如果没有定义SellTickets接口,只定义了TrainStation(火车站类)。很显然JDK代理是无法使用了