CGLIB动态代理实现原理

前言

Spring代码实例:https://github.com/yihonglei/Spring-Study

一 CGLIB介绍

CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,

它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。

CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP为他们提供

方法的interception(拦截)。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。

除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成java的字节码。当然不鼓励直接使用ASM,

因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

二 CGLIB动态代理实例

实现一个业务类,注意,这个业务类并没有实现任何接口:


 
 
  1. package com.lanhuigu.spring.proxy.cglib;
  2. public class HelloService {
  3. public HelloService() {
  4. System.out.println( "HelloService构造");
  5. }
  6. /**
  7. * 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
  8. */
  9. final public String sayOthers(String name) {
  10. System.out.println( "HelloService:sayOthers>>"+name);
  11. return null;
  12. }
  13. public void sayHello() {
  14. System.out.println( "HelloService:sayHello");
  15. }
  16. }

自定义MethodInterceptor:


 
 
  1. package com.lanhuigu.spring.proxy.cglib;
  2. import net.sf.cglib.proxy.MethodInterceptor;
  3. import net.sf.cglib.proxy.MethodProxy;
  4. import java.lang.reflect.Method;
  5. /**
  6. * 自定义MethodInterceptor
  7. */
  8. public class MyMethodInterceptor implements MethodInterceptor{
  9. /**
  10. * sub:cglib生成的代理对象
  11. * method:被代理对象方法
  12. * objects:方法入参
  13. * methodProxy: 代理方法
  14. */
  15. @Override
  16. public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
  17. System.out.println( "======插入前置通知======");
  18. Object object = methodProxy.invokeSuper(sub, objects);
  19. System.out.println( "======插入后者通知======");
  20. return object;
  21. }
  22. }

生成CGLIB代理对象调用目标方法:


 
 
  1. package com.lanhuigu.spring.proxy.cglib;
  2. import net.sf.cglib.core.DebuggingClassWriter;
  3. import net.sf.cglib.proxy.Enhancer;
  4. public class Client {
  5. public static void main(String[] args) {
  6. // 代理类class文件存入本地磁盘方便我们反编译查看源码
  7. System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
  8. // 通过CGLIB动态代理获取代理对象的过程
  9. Enhancer enhancer = new Enhancer();
  10. // 设置enhancer对象的父类
  11. enhancer.setSuperclass(HelloService.class);
  12. // 设置enhancer的回调对象
  13. enhancer.setCallback( new MyMethodInterceptor());
  14. // 创建代理对象
  15. HelloService proxy= (HelloService)enhancer.create();
  16. // 通过代理对象调用目标方法
  17. proxy.sayHello();
  18. }
  19. }

运行结果:

三 CGLIB动态代理源码分析

实现CGLIB动态代理必须实现MethodInterceptor(方法拦截器)接口,源码如下:


 
 
  1. /*
  2. * Copyright 2002,2003 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package net.sf.cglib.proxy;
  17. /**
  18. * General-purpose {@link Enhancer} callback which provides for "around advice".
  19. * @author Juozas Baliuka <a href="mailto:baliuka@mwm.lt">baliuka@mwm.lt</a>
  20. * @version $Id: MethodInterceptor.java,v 1.8 2004/06/24 21:15:20 herbyderby Exp $
  21. */
  22. public interface MethodInterceptor
  23. extends Callback
  24. {
  25. /**
  26. * All generated proxied methods call this method instead of the original method.
  27. * The original method may either be invoked by normal reflection using the Method object,
  28. * or by using the MethodProxy (faster).
  29. * @param obj "this", the enhanced object
  30. * @param method intercepted Method
  31. * @param args argument array; primitive types are wrapped
  32. * @param proxy used to invoke super (non-intercepted method); may be called
  33. * as many times as needed
  34. * @throws Throwable any exception may be thrown; if so, super method will not be invoked
  35. * @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.
  36. * @see MethodProxy
  37. */
  38. public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
  39. MethodProxy proxy) throws Throwable;
  40. }

这个接口只有一个intercept()方法,这个方法有4个参数:

1)obj表示增强的对象,即实现这个接口类的一个对象;

2)method表示要被拦截的方法;

3)args表示要被拦截方法的参数;

4)proxy表示要触发父类的方法对象;

在上面的Client代码中,通过Enhancer.create()方法创建代理对象,create()方法的源码:


 
 
  1. /**
  2. * Generate a new class if necessary and uses the specified
  3. * callbacks (if any) to create a new object instance.
  4. * Uses the no-arg constructor of the superclass.
  5. * @return a new instance
  6. */
  7. public Object create() {
  8. classOnly = false;
  9. argumentTypes = null;
  10. return createHelper();
  11. }

该方法含义就是如果有必要就创建一个新类,并且用指定的回调对象创建一个新的对象实例,

使用的父类的参数的构造方法来实例化父类的部分。核心内容在createHelper()中,源码如下:


 
 
  1. private Object createHelper() {
  2. preValidate();
  3. Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
  4. ReflectUtils.getNames(interfaces),
  5. filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
  6. callbackTypes,
  7. useFactory,
  8. interceptDuringConstruction,
  9. serialVersionUID);
  10. this.currentKey = key;
  11. Object result = super.create(key);
  12. return result;
  13. }

preValidate()方法校验callbackTypes、filter是否为空,以及为空时的处理。

通过newInstance()方法创建EnhancerKey对象,作为Enhancer父类AbstractClassGenerator.create()方法

创建代理对象的参数。


 
 
  1. protected Object create(Object key) {
  2. try {
  3. ClassLoader loader = getClassLoader();
  4. Map<ClassLoader, ClassLoaderData> cache = CACHE;
  5. ClassLoaderData data = cache.get(loader);
  6. if (data == null) {
  7. synchronized (AbstractClassGenerator.class) {
  8. cache = CACHE;
  9. data = cache.get(loader);
  10. if (data == null) {
  11. Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
  12. data = new ClassLoaderData(loader);
  13. newCache.put(loader, data);
  14. CACHE = newCache;
  15. }
  16. }
  17. }
  18. this.key = key;
  19. Object obj = data.get( this, getUseCache());
  20. if (obj instanceof Class) {
  21. return firstInstance((Class) obj);
  22. }
  23. return nextInstance(obj);
  24. } catch (RuntimeException e) {
  25. throw e;
  26. } catch (Error e) {
  27. throw e;
  28. } catch (Exception e) {
  29. throw new CodeGenerationException(e);
  30. }
  31. }

真正创建代理对象方法在nextInstance()方法中,该方法为抽象类AbstractClassGenerator的一个方法,签名如下:

abstract protected Object nextInstance(Object instance) throws Exception;

在子类Enhancer中实现,实现源码如下:


 
 
  1. protected Object nextInstance(Object instance) {
  2. EnhancerFactoryData data = (EnhancerFactoryData) instance;
  3. if (classOnly) {
  4. return data.generatedClass;
  5. }
  6. Class[] argumentTypes = this.argumentTypes;
  7. Object[] arguments = this.arguments;
  8. if (argumentTypes == null) {
  9. argumentTypes = Constants.EMPTY_CLASS_ARRAY;
  10. arguments = null;
  11. }
  12. return data.newInstance(argumentTypes, arguments, callbacks);
  13. }

看看data.newInstance(argumentTypes, arguments, callbacks)方法,

第一个参数为代理对象的构成器类型,第二个为代理对象构造方法参数,第三个为对应回调对象。

最后根据这些参数,通过反射生成代理对象,源码如下:


 
 
  1. /**
  2. * Creates proxy instance for given argument types, and assigns the callbacks.
  3. * Ideally, for each proxy class, just one set of argument types should be used,
  4. * otherwise it would have to spend time on constructor lookup.
  5. * Technically, it is a re-implementation of {@link Enhancer#createUsingReflection(Class)},
  6. * with "cache {@link #setThreadCallbacks} and {@link #primaryConstructor}"
  7. *
  8. * @see #createUsingReflection(Class)
  9. * @param argumentTypes constructor argument types
  10. * @param arguments constructor arguments
  11. * @param callbacks callbacks to set for the new instance
  12. * @return newly created proxy
  13. */
  14. public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) {
  15. setThreadCallbacks(callbacks);
  16. try {
  17. // Explicit reference equality is added here just in case Arrays.equals does not have one
  18. if (primaryConstructorArgTypes == argumentTypes ||
  19. Arrays.equals(primaryConstructorArgTypes, argumentTypes)) {
  20. // If we have relevant Constructor instance at hand, just call it
  21. // This skips "get constructors" machinery
  22. return ReflectUtils.newInstance(primaryConstructor, arguments);
  23. }
  24. // Take a slow path if observing unexpected argument types
  25. return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments);
  26. } finally {
  27. // clear thread callbacks to allow them to be gc'd
  28. setThreadCallbacks( null);
  29. }
  30. }

最后生成代理对象:

 

将其反编译后代码如下:

 


 
 
  1. package com.lanhuigu.spring.proxy.cglib;
  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.*;
  6. public class HelloService$$EnhancerByCGLIB$$4da4ebaf extends HelloService
  7. implements Factory
  8. {
  9. private boolean CGLIB$BOUND;
  10. public static Object CGLIB$FACTORY_DATA;
  11. private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
  12. private static final Callback CGLIB$STATIC_CALLBACKS[];
  13. private MethodInterceptor CGLIB$CALLBACK_0; // 拦截器
  14. private static Object CGLIB$CALLBACK_FILTER;
  15. private static final Method CGLIB$sayHello$ 0$Method; // 被代理方法
  16. private static final MethodProxy CGLIB$sayHello$ 0$Proxy; // 代理方法
  17. private static final Object CGLIB$emptyArgs[];
  18. private static final Method CGLIB$equals$ 1$Method;
  19. private static final MethodProxy CGLIB$equals$ 1$Proxy;
  20. private static final Method CGLIB$toString$ 2$Method;
  21. private static final MethodProxy CGLIB$toString$ 2$Proxy;
  22. private static final Method CGLIB$hashCode$ 3$Method;
  23. private static final MethodProxy CGLIB$hashCode$ 3$Proxy;
  24. private static final Method CGLIB$clone$ 4$Method;
  25. private static final MethodProxy CGLIB$clone$ 4$Proxy;
  26. static void CGLIB$STATICHOOK1()
  27. {
  28. Method amethod[];
  29. Method amethod1[];
  30. CGLIB$THREAD_CALLBACKS = new ThreadLocal();
  31. CGLIB$emptyArgs = new Object[ 0];
  32. // 代理类
  33. Class class1 = Class.forName( "com.lanhuigu.spring.proxy.cglib.HelloService$$EnhancerByCGLIB$$4da4ebaf");
  34. // 被代理类
  35. Class class2;
  36. amethod = ReflectUtils.findMethods( new String[] {
  37. "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"
  38. }, (class2 = Class.forName( "java.lang.Object")).getDeclaredMethods());
  39. Method[] = amethod;
  40. CGLIB$equals$ 1$Method = amethod[ 0];
  41. CGLIB$equals$ 1$Proxy = MethodProxy.create(class2, class1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
  42. CGLIB$toString$ 2$Method = amethod[ 1];
  43. CGLIB$toString$ 2$Proxy = MethodProxy.create(class2, class1, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
  44. CGLIB$hashCode$ 3$Method = amethod[ 2];
  45. CGLIB$hashCode$ 3$Proxy = MethodProxy.create(class2, class1, "()I", "hashCode", "CGLIB$hashCode$3");
  46. CGLIB$clone$ 4$Method = amethod[ 3];
  47. CGLIB$clone$ 4$Proxy = MethodProxy.create(class2, class1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
  48. amethod1 = ReflectUtils.findMethods( new String[] {
  49. "sayHello", "()V"
  50. }, (class2 = Class.forName( "com.lanhuigu.spring.proxy.cglib.HelloService")).getDeclaredMethods());
  51. Method[] 1 = amethod1;
  52. CGLIB$sayHello$ 0$Method = amethod1[ 0];
  53. CGLIB$sayHello$ 0$Proxy = MethodProxy.create(class2, class1, "()V", "sayHello", "CGLIB$sayHello$0");
  54. }
  55. final void CGLIB$sayHello$ 0()
  56. {
  57. super.sayHello();
  58. }
  59. public final void sayHello()
  60. {
  61. MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
  62. if( this.CGLIB$CALLBACK_0 == null) {
  63. CGLIB$BIND_CALLBACKS( this);
  64. var10000 = this.CGLIB$CALLBACK_0;
  65. }
  66. if(var10000 != null) {
  67. // 调用拦截器
  68. var10000.intercept( this, CGLIB$setPerson$ 0$Method, CGLIB$emptyArgs, CGLIB$setPerson$ 0$Proxy);
  69. } else {
  70. super.sayHello();
  71. }
  72. }
  73. ......
  74. ......
  75. }

从代理对象反编译源码可以知道,代理对象继承于HelloService,拦截器调用intercept()方法,

intercept()方法由自定义MyMethodInterceptor实现,所以,最后调用MyMethodInterceptor中

的intercept()方法,从而完成了由代理对象访问到目标对象的动态代理实现。

JDK动态代理实现原理(jdk8)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值