-
2020-05-10 21:13:55
本文分下面三个部分来分析cglib动态代理的原理。
- cglib 动态代理示例
- 代理类分析
- Fastclass 机制分析
一、cglib 动态代理示例
public class Target{ public void f(){ System.out.println("Target f()"); } public void g(){ System.out.println("Target g()"); } } public class Interceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("I am intercept begin"); //Note: 此处一定要使用proxy的invokeSuper方法来调用目标类的方法 proxy.invokeSuper(obj, args); System.out.println("I am intercept end"); return null; } } public class Test { public static void main(String[] args) { System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "F:\\code"); //实例化一个增强器,也就是cglib中的一个class generator Enhancer eh = new Enhancer(); //设置目标类 eh.setSuperclass(Target.class); // 设置拦截对象 eh.setCallback(new Interceptor()); // 生成代理类并返回一个实例 Target t = (Target) eh.create(); t.f(); t.g(); } }
运行结果为:
I am intercept begin Target f() I am intercept end I am intercept begin Target g() I am intercept end
与JDK动态代理相比,cglib可以实现对一般类的代理而无需实现接口。在上例中通过下列步骤来生成目标类Target的代理类:
- 创建Enhancer实例
- 通过setSuperclass方法来设置目标类
- 通过setCallback 方法来设置拦截对象
- create方法生成Target的代理类,并返回代理类的实例
二、代理类分析
在示例代码中我们通过设置DebuggingClassWriter.DEBUG_LOCATION_PROPERTY的属性值来获取cglib生成的代理类。通过之前分析的命名规则我们可以很容易的在F:\code下面找到生成的代理类
Target$$EnhancerByCGLIB$$788444a0.class
。使用jd-gui进行反编译(由于版本的问题,此处只能显示部分代码,可以结合javap的反编译结果来进行分析),由于cglib会代理Object中的finalize,equals, toString,hashCode,clone方法,为了清晰的展示代理类我们省略这部分代码,反编译的结果如下:
public class Target$$EnhancerByCGLIB$$788444a0 extends Target implements Factory { private boolean CGLIB$BOUND; private static final ThreadLocal CGLIB$THREAD_CALLBACKS; private static final Callback[] CGLIB$STATIC_CALLBACKS; private MethodInterceptor CGLIB$CALLBACK_0; private static final Method CGLIB$g$0$Method; private static final MethodProxy CGLIB$g$0$Proxy; private static final Object[] CGLIB$emptyArgs; private static final Method CGLIB$f$1$Method; private static final MethodProxy CGLIB$f$1$Proxy; static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; Class localClass1 = Class.forName("net.sf.cglib.test.Target$$EnhancerByCGLIB$$788444a0"); Class localClass2; Method[] tmp60_57 = ReflectUtils.findMethods(new String[] { "g", "()V", "f", "()V" }, (localClass2 = Class.forName("net.sf.cglib.test.Target")).getDeclaredMethods()); CGLIB$g$0$Method = tmp60_57[0]; CGLIB$g$0$Proxy = MethodProxy.create(localClass2, localClass1, "()V", "g", "CGLIB$g$0"); CGLIB$f$1$Method = tmp60_57[1]; CGLIB$f$1$Proxy = MethodProxy.create(localClass2, localClass1, "()V", "f", "CGLIB$f$1"); } final void CGLIB$g$0() { super.g(); } public final void g() { MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0; if (tmp4_1 == null) { CGLIB$BIND_CALLBACKS(this); tmp4_1 = this.CGLIB$CALLBACK_0; } if (this.CGLIB$CALLBACK_0 != null) { tmp4_1.intercept(this, CGLIB$g$0$Method, CGLIB$emptyArgs, CGLIB$g$0$Proxy); } else{ super.g(); } } }
代理类(
Target$$EnhancerByCGLIB$$788444a0
)继承了目标类(Target),至于代理类实现的factory接口与本文无关,残忍无视。代理类为每个目标类的方法生成两个方法,例如针对目标类中的每个非private方法,代理类会生成两个方法,以g方法为例:一个是@Override的g方法,一个是CGLIB$g$0
(CGLIB$g$0
相当于目标类的g方法)。我们在示例代码中调用目标类的方法t.g()时,实际上调用的是代理类中的g()方法。接下来我们着重分析代理类中的g方法,看看是怎么实现的代理功能。当调用代理类的g方法时,先判断是否已经存在实现了MethodInterceptor接口的拦截对象,如果没有的话就调用
CGLIB\$BIND_CALLBACKS
方法来获取拦截对象,CGLIB\$BIND_CALLBACKS
的反编译结果如下:private static final void CGLIB$BIND_CALLBACKS(java.lang.Object); Code: 0: aload_0 1: checkcast #2; //class net/sf/cglib/test/Target$$EnhancerByCGLIB$$788444a0 4: astore_1 5: aload_1 6: getfield #212; //Field CGLIB$BOUND:Z 9: ifne 52 12: aload_1 13: iconst_1 14: putfield #212; //Field CGLIB$BOUND:Z 17: getstatic #24; //Field CGLIB$THREAD_CALLBACKS:Ljava/lang/ThreadLocal; 20: invokevirtual #215; //Method java/lang/ThreadLocal.get:()Ljava/lang/Object; 23: dup 24: ifnonnull 39 27: pop 28: getstatic #210; //Field CGLIB$STATIC_CALLBACKS:[Lnet/sf/cglib/proxy/Callback; 31: dup 32: ifnonnull 39 35: pop 36: goto 52 39: checkcast #216; //class "[Lnet/sf/cglib/proxy/Callback;" 42: aload_1 43: swap 44: iconst_0 45: aaload
为了方便阅读,等价的代码如下:
private static final void CGLIB$BIND_CALLBACKS(Object o){ Target$$EnhancerByCGLIB$$788444a0 temp_1 = (Target$$EnhancerByCGLIB$$788444a0)o; Object temp_2; Callback[] temp_3 if(temp_1.CGLIB$BOUND == true){ return; } temp_1.CGLIB$BOUND = true; temp_2 = CGLIB$THREAD_CALLBACKS.get(); if(temp_2!=null){ temp_3 = (Callback[])temp_2; } else if(CGLIB$STATIC_CALLBACKS!=null){ temp_3 = CGLIB$STATIC_CALLBACKS; } else{ return; } temp_1.CGLIB$CALLBACK_0 = (MethodInterceptor)temp_3[0]; return; }
CGLIB$BIND_CALLBACKS
先从CGLIB$THREAD_CALLBACKS
中get拦截对象,如果获取不到的话,再从CGLIB$STATIC_CALLBACKS来获取,如果也没有则认为该方法不需要代理。那么拦截对象是如何设置到
CGLIB$THREAD_CALLBACKS
或者CGLIB$STATIC_CALLBACKS
中的呢?在Jdk动态代理中拦截对象是在实例化代理类时由构造函数传入的,在cglib中是调用Enhancer的firstInstance方法来生成代理类实例并设置拦截对象的。firstInstance的调用轨迹为:
- Enhancer:firstInstance
- Enhancer:createUsingReflection
- Enhancer:setThreadCallbacks
- Enhancer:setCallbacksHelper
Target$$EnhancerByCGLIB$$788444a0
: CGLIB$SET_THREAD_CALLBACKS
在第5步,调用了代理类的
CGLIB$SET_THREAD_CALLBACKS
来完成拦截对象的注入。下面我们看一下CGLIB$SET_THREAD_CALLBACKS
的反编译结果:public static void CGLIB$SET_THREAD_CALLBACKS(net.sf.cglib.proxy.Callback[]); Code: 0: getstatic #24; //Field CGLIB$THREAD_CALLBACKS:Ljava/lang/ThreadLocal; 3: aload_0 4: invokevirtual #207; //Method java/lang/ThreadLocal.set:(Ljava/lang/Object;)V 7: return
在
CGLIB$SET_THREAD_CALLBACKS
方法中调用了CGLIB$THREAD_CALLBACKS
的set方法来保存拦截对象,在CGLIB$BIND_CALLBACKS
方法中使用了CGLIB$THREAD_CALLBACKS
的get方法来获取拦截对象,并保存到CGLIB$CALLBACK_0
中。这样,在我们调用代理类的g方法时,就可以获取到我们设置的拦截对象,然后通过tmp4_1.intercept(this, CGLIB$g$0$Method, CGLIB$emptyArgs, CGLIB$g$0$Proxy)
来实现代理。这里来解释一下intercept方法的参数含义:@para1 obj :代理对象本身
@para2 method : 被拦截的方法对象
@para3 args:方法调用入参
@para4 proxy:用于调用被拦截方法的方法代理对象
这里会有一个疑问,为什么不直接反射调用代理类生成的(
CGLIB\$g\$0
)来间接调用目标类的被拦截方法,而使用proxy的invokeSuper方法呢?这里就涉及到了另外一个点— FastClass 。三、Fastclass 机制分析
Jdk动态代理的拦截对象是通过反射的机制来调用被拦截方法的,反射的效率比较低,所以cglib采用了FastClass的机制来实现对被拦截方法的调用。FastClass机制就是对一个类的方法建立索引,通过索引来直接调用相应的方法,下面用一个小例子来说明一下,这样比较直观:
public class test10 { public static void main(String[] args){ Test tt = new Test(); Test2 fc = new Test2(); int index = fc.getIndex("f()V"); fc.invoke(index, tt, null); } } class Test{ public void f(){ System.out.println("f method"); } public void g(){ System.out.println("g method"); } } class Test2{ public Object invoke(int index, Object o, Object[] ol){ Test t = (Test) o; switch(index){ case 1: t.f(); return null; case 2: t.g(); return null; } return null; } public int getIndex(String signature){ switch(signature.hashCode()){ case 3078479: return 1; case 3108270: return 2; } return -1; } }
上例中,Test2是Test的Fastclass,在Test2中有两个方法getIndex和invoke。在getIndex方法中对Test的每个方法建立索引,并根据入参(方法名+方法的描述符)来返回相应的索引。Invoke根据指定的索引,以ol为入参调用对象O的方法。这样就避免了反射调用,提高了效率。代理类(
Target$$EnhancerByCGLIB$$788444a0
)中与生成Fastclass相关的代码如下:Class localClass1 = Class.forName("net.sf.cglib.test.Target$$EnhancerByCGLIB$$788444a0"); localClass2 = Class.forName("net.sf.cglib.test.Target"); CGLIB$g$0$Proxy = MethodProxy.create(localClass2, localClass1, "()V", "g", "CGLIB$g$0");
MethodProxy中会对localClass1和localClass2进行分析并生成FastClass,然后再使用getIndex来获取方法g 和
CGLIB\$g\$0
的索引,具体的生成过程将在后续进行介绍,这里介绍一个关键的内部类:private static class FastClassInfo { FastClass f1; // net.sf.cglib.test.Target的fastclass FastClass f2; // Target$$EnhancerByCGLIB$$788444a0 的fastclass int i1; //方法g在f1中的索引 int i2; //方法CGLIB$g$0在f2中的索引 }
MethodProxy 中invokeSuper方法的代码如下:
FastClassInfo fci = fastClassInfo; return fci.f2.invoke(fci.i2, obj, args);
当调用invokeSuper方法时,实际上是调用代理类的
CGLIB$g$0
方法,CGLIB$g$0
直接调用了目标类的g方法。所以,在第一节示例代码中我们使用invokeSuper方法来调用被拦截的目标类方法。至此,我们已经了解cglib动态代理的工作原理,接下来会对cglib的相关源码进行分析。
更多相关内容 -
CGLIB源码分析
2021-07-19 14:34:13时序图 深入源码 回到Spring AOP的源码部分,AOP生成方式的选择是在DefaultAopProxyFactory中定义的。Spring 生成代理的方式有两种,一种是CGLIB一种是JDK动态代理。主要是通过代理类是否实现了接口来判断。 ...前言
前面已经走完了Spring AOP的解析处理逻辑流程部分,接下来进入到具体的代理对象的代码生成阶段,揭开代理对象的神秘面纱。
CGLIB动态代理
首先是一个CGLIB使用的demo,代码如下:
public class CglibEnhancerDemo { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(TestBeanA.class); enhancer.setCallback(new MyInterceptor()); TestBeanA testBeanA = (TestBeanA) enhancer.create(); String testStr = testBeanA.getTestStr(); System.out.println(testStr); } private static class MyInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("Before invoke method is: " + method); Object result = methodProxy.invokeSuper(o, objects); System.out.println("After invoke method is: " + method + " result is: " + result); return result; } } }
运行结果如下:
> Task :spring-demo:CglibEnhancerDemo.main() Before invoke method is: public java.lang.String com.chudichen.spring.aop.TestBeanA.getTestStr() After invoke method is: public java.lang.String com.chudichen.spring.aop.TestBeanA.getTestStr() result is: testStrA testStrA
可以看到执行的方法被自定义的Interceptor所拦截,并执行了增强的逻辑,CGLIB采用的是为代理的目标类生成子类的方式,具体的生成步骤是:
1. 生成代理类的二进制字节码文件
2. 加载二进制字节码,生成Class对象(例如使用Class.forName()方法)。
3. 通过反射获取构造器创建出代理对象。
时序图
深入源码
回到Spring AOP的源码部分,AOP生成方式的选择是在DefaultAopProxyFactory中定义的。Spring 生成代理的方式有两种,一种是CGLIB一种是JDK动态代理。主要是通过代理类是否实现了接口来判断。
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } /* * !!!!!!!!!!!!!!!!!!!!!!!!!! * 如果目标类是接口,则使用 JDK 动态代理,否则使用 CGLIB * !!!!!!!!!!!!!!!!!!!!!!!!!! */ if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }
CGLIB代理
进入到ObjenesisCglibAopProxy,可以看到它是继承自CglibAopProxy的,具体的准备增强器Enhancer以及设置拦截器链都是在CglibAopProxy中完成的。
public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource()); } try { // 获取目标代理类 Class<?> rootClass = this.advised.getTargetClass(); Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); Class<?> proxySuperClass = rootClass; if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) { proxySuperClass = rootClass.getSuperclass(); Class<?>[] additionalInterfaces = rootClass.getInterfaces(); for (Class<?> additionalInterface : additionalInterfaces) { this.advised.addInterface(additionalInterface); } } // 验证class // Validate the class, writing log messages as necessary. validateClassIfNecessary(proxySuperClass, classLoader); // 获取增强器 // Configure CGLIB Enhancer... Enhancer enhancer = createEnhancer(); // 为enhancer设置类加载器 if (classLoader != null) { enhancer.setClassLoader(classLoader); if (classLoader instanceof SmartClassLoader && ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } } // 设置代理类,很关键的一步 enhancer.setSuperclass(proxySuperClass); enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); // 设置strategy策略器 enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader)); Callback[] callbacks = getCallbacks(rootClass); Class<?>[] types = new Class<?>[callbacks.length]; for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } // 设置回调过滤器 // fixedInterceptorMap only populated at this point, after getCallbacks call above enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); enhancer.setCallbackTypes(types); // 创建代理类实例 // Generate the proxy class and create a proxy instance. return createProxyClassAndInstance(enhancer, callbacks); } catch (CodeGenerationException | IllegalArgumentException ex) { throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() + ": Common causes of this problem include using a final class or a non-visible class", ex); } catch (Throwable ex) { // TargetSource.getTarget() failed throw new AopConfigException("Unexpected AOP exception", ex); } }
其中比较重要的AOP逻辑都是在拦截器链中的,具体的过程是在getCallbacks()方法中,Callback的实现是由静态内部类DynamicAdvisedInterceptor完成的。
private Callback[] getCallbacks(Class<?> rootClass) throws Exception { // 获取expose-proxy属性设置 // Parameters used for optimization choices... boolean exposeProxy = this.advised.isExposeProxy(); boolean isFrozen = this.advised.isFrozen(); boolean isStatic = this.advised.getTargetSource().isStatic(); // 将AOP拦截器封装在DynamicAdvisedInterceptor中 // Choose an "aop" interceptor (used for AOP calls). Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised); // Choose a "straight to target" interceptor. (used for calls that are // unadvised but can return this). May be required to expose the proxy. Callback targetInterceptor; if (exposeProxy) { targetInterceptor = (isStatic ? new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) : new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource())); } else { targetInterceptor = (isStatic ? new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) : new DynamicUnadvisedInterceptor(this.advised.getTargetSource())); } // Choose a "direct to target" dispatcher (used for // unadvised calls to static targets that cannot return this). Callback targetDispatcher = (isStatic ? new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp()); // 添加主要的拦截器链 Callback[] mainCallbacks = new Callback[] { aopInterceptor, // for normal advice targetInterceptor, // invoke target without considering advice, if optimized new SerializableNoOp(), // no override for methods mapped to this targetDispatcher, this.advisedDispatcher, new EqualsInterceptor(this.advised), new HashCodeInterceptor(this.advised) }; Callback[] callbacks; // If the target is a static one and the advice chain is frozen, // then we can make some optimizations by sending the AOP calls // direct to the target using the fixed chain for that method. if (isStatic && isFrozen) { Method[] methods = rootClass.getMethods(); Callback[] fixedCallbacks = new Callback[methods.length]; this.fixedInterceptorMap = new HashMap<>(methods.length); // TODO: small memory optimization here (can skip creation for methods with no advice) for (int x = 0; x < methods.length; x++) { Method method = methods[x]; List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass); fixedCallbacks[x] = new FixedChainStaticTargetInterceptor( chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass()); this.fixedInterceptorMap.put(method, x); } // Now copy both the callbacks from mainCallbacks // and fixedCallbacks into the callbacks array. callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length]; System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length); System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length); this.fixedInterceptorOffset = mainCallbacks.length; } else { callbacks = mainCallbacks; } return callbacks; }
DynamicAdvisedInterceptor的作用
DynamicAdvisedInterceptor为CGLIB中回调的默认实现.
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Object target = null; // 要拦截的通知源 TargetSource targetSource = this.advised.getTargetSource(); try { if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool... target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null); // 获取拦截器链 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; // Check whether we only have one InvokerInterceptor: that is, // no real advice, but just reflective invocation of the target. if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { // We can skip creating a MethodInvocation: just invoke the target directly. // Note that the final invoker must be an InvokerInterceptor, so we know // it does nothing but a reflective operation on the target, and no hot // swapping or fancy proxying. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); // 如果拦截器链为空,则直接进入拦截器链 retVal = methodProxy.invoke(target, argsToUse); } else { // We need to create a method invocation... retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } retVal = processReturnType(proxy, target, method, retVal); return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } }
拦截器链是通过DefaultAdvisorChainFactory中的getInterceptorsAndDynamicInterceptionAdvice方法来获取的。它的主要工作是:
1. 先获取通知适配注册器
2. 将注册器包装为可用的拦截器
在这个过程中,DefaultAdvisorChainFactory是非常关键的角色。
public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, @Nullable Class<?> targetClass) { /* * 调用DefaultAdvisorAdapterRegistry构造方法获取通知适配器注册器,包括: * 1. MethodBeforeAdviceAdapter * 2. AfterReturningAdviceAdapter * 3. ThrowsAdviceAdapter * Adapter添加进List中的顺序就是上面的顺序。 */ // This is somewhat tricky... We have to process introductions first, // but we need to preserve order in the ultimate list. AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); // config也就是前面所说的ProxyFactory。从ProxyFactory中获取通知 Advisor[] advisors = config.getAdvisors(); List<Object> interceptorList = new ArrayList<>(advisors.length); Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); Boolean hasIntroductions = null; for (Advisor advisor : advisors) { // 切面型通知 if (advisor instanceof PointcutAdvisor) { // 将通知强转为切面 // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); boolean match; if (mm instanceof IntroductionAwareMethodMatcher) { if (hasIntroductions == null) { hasIntroductions = hasMatchingIntroductions(advisors, actualClass); } match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions); } else { match = mm.matches(method, actualClass); } if (match) { /* * 通过通知适配注册器获取方法拦截器,这里返回的是四种拦截器,分别为: * ExposeInvocationInterceptor、AspectJAfterAdvice、AspectJAroundAdvice、MethodBeforeAdviceInterceptor */ MethodInterceptor[] interceptors = registry.getInterceptors(advisor); if (mm.isRuntime()) { // Creating a new object instance in the getInterceptors() method // isn't a problem as we normally cache created chains. for (MethodInterceptor interceptor : interceptors) { interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); } } } } else if (advisor instanceof IntroductionAdvisor) { // 接口型通知 IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }
DefaultAdvisorAdapterRegistry的主要工作有:
1. 在构造方法中注册前置通知、后置通知和异常通知的适配器
2. 包装Advisor
3. 将Advisor包装为拦截器
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable { private final List<AdvisorAdapter> adapters = new ArrayList<>(3); /** * 在构造方法里注册前置通知、后置通知和异常通知的适配器 * * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters. */ public DefaultAdvisorAdapterRegistry() { registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); } @Override public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException { // 如果封装对象本身就是Advisor,则无需做任何处理 if (adviceObject instanceof Advisor) { return (Advisor) adviceObject; } // 如果不是Advice类型,则不能进行封装 if (!(adviceObject instanceof Advice)) { throw new UnknownAdviceTypeException(adviceObject); } Advice advice = (Advice) adviceObject; if (advice instanceof MethodInterceptor) { // So well-known it doesn't even need an adapter. return new DefaultPointcutAdvisor(advice); } for (AdvisorAdapter adapter : this.adapters) { // Check that it is supported. if (adapter.supportsAdvice(advice)) { return new DefaultPointcutAdvisor(advice); } } throw new UnknownAdviceTypeException(advice); } @Override public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List<MethodInterceptor> interceptors = new ArrayList<>(3); // 获取通知 Advice advice = advisor.getAdvice(); // 判断是否是MethodInterceptor类型 if (advice instanceof MethodInterceptor) { interceptors.add((MethodInterceptor) advice); } for (AdvisorAdapter adapter : this.adapters) { if (adapter.supportsAdvice(advice)) { interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException(advisor.getAdvice()); } return interceptors.toArray(new MethodInterceptor[0]); } @Override public void registerAdvisorAdapter(AdvisorAdapter adapter) { this.adapters.add(adapter); } }
调用拦截器链
获取完了拦截器链之后,在方法执行时就会调用拦截器链的增强逻辑了。这里又回到了DynamicAdvisedInterceptor的intercept(),当Advisor链为空的时候就直接执行目标对象的方法不进行代理了,不为空则需要调用proceed()进行代理逻辑处理了。
这里仅显示关键部分的代码:
// 获取拦截器链 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; // Check whether we only have one InvokerInterceptor: that is, // no real advice, but just reflective invocation of the target. if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { // We can skip creating a MethodInvocation: just invoke the target directly. // Note that the final invoker must be an InvokerInterceptor, so we know // it does nothing but a reflective operation on the target, and no hot // swapping or fancy proxying. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); // 如果拦截器链为空,则直接进入拦截器链 retVal = methodProxy.invoke(target, argsToUse); } else { // We need to create a method invocation... retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); }
进入到ReflectiveMethodInvocation的逻辑部分,这里的执行过程为:
1. 根据下标获取拦截器。
2. 如果匹配就直接调用invoke执行拦截器,如果不匹配就继续调用proceed继续递归。
3. proceed方法在这里起到一个递归的作用。
public Object proceed() throws Throwable { // We start with an index of -1 and increment early. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } // 获取拦截器链的元素 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // Evaluate dynamic method matcher here: static part will already have // been evaluated and found to match. InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. return proceed(); } } else { // It's an interceptor, so we just invoke it: The pointcut will have // been evaluated statically before this object was constructed. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
后置通知的实现:
public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice, Serializable { public AspectJAfterAdvice( Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { super(aspectJBeforeAdviceMethod, pointcut, aif); } @Override public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } finally { invokeAdviceMethod(getJoinPointMatch(), null, null); } } @Override public boolean isBeforeAdvice() { return false; } @Override public boolean isAfterAdvice() { return true; } }
环绕通知实现逻辑:
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable { public AspectJAroundAdvice( Method aspectJAroundAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { super(aspectJAroundAdviceMethod, pointcut, aif); } @Override public boolean isBeforeAdvice() { return false; } @Override public boolean isAfterAdvice() { return false; } @Override protected boolean supportsProceedingJoinPoint() { return true; } @Override public Object invoke(MethodInvocation mi) throws Throwable { if (!(mi instanceof ProxyMethodInvocation)) { throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); } ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi); JoinPointMatch jpm = getJoinPointMatch(pmi); return invokeAdviceMethod(pjp, jpm, null, null); } /** * Return the ProceedingJoinPoint for the current invocation, * instantiating it lazily if it hasn't been bound to the thread already. * @param rmi the current Spring AOP ReflectiveMethodInvocation, * which we'll use for attribute binding * @return the ProceedingJoinPoint to make available to advice methods */ protected ProceedingJoinPoint lazyGetProceedingJoinPoint(ProxyMethodInvocation rmi) { return new MethodInvocationProceedingJoinPoint(rmi); } }
-
cglib底层源码分析(⼀)
2022-04-10 19:12:31在分析底层源码实现之前,我们先来试试,cglib能否代理接⼝,定义⼀个UserInterface接⼝ 然后利⽤cglib来代理⼀个接⼝: 也是可以正常运⾏的,那么⽤cglib代理⼀个类和代理⼀个接⼝的底层有什么区别呢?我们...cglib是⼀种动态代理技术,可以针对类来⽣成⼀个代理对象。 ⽐如,我们现有⼀个UserService类:
现在利⽤cglib对UserService类中的test()⽅法进⾏增强:
在分析底层源码实现之前,我们先来试试,cglib能否代理接⼝,定义⼀个UserInterface接⼝
然后利⽤cglib来代理⼀个接⼝:
也是可以正常运⾏的,那么⽤cglib代理⼀个类和代理⼀个接⼝的底层有什么区别呢?我们继续分析。
我们知道,既然要⽣成⼀个代理对象,那么就肯定需要⼀个代理类,只不过当我们⽤cglib时,这个代理 类是由cglib⽣成的,那么我们能不能看到这个代理类是怎么⽣成的呢?
可以!我们只需要在运⾏时加上:
1 -Dcglib.debugLocation=D:\IdeaProjects\cglib\cglib\target\classes
cglib就会将⽣成的代理类放到上⾯所指定的路径上。那么我们分别来看看cglib代理类和接⼝时所产⽣的 代理类是怎样的。
UserService的代理类,我保留了类中⽐较关键的信息:
UserInterface的代理类,我保留了类中⽐较关键的信息:
可以发现这两种情况所产⽣的类区别不⼤,⽆⾮就是UserService代理类是UserService的⼦类, UserInterface代理类实现了UserInterface。
我们可以发现在代理类中(以上两个任选⼀个),都存在⼀个test()⽅法和CGLIB$test$0()(以 UserService代理类举例⼦):
test()⽅法内会去调⽤所设置的Callbacks中的intercept(),相当于执⾏增强逻辑,如果没有Callbacks, 则会执⾏super.test(),那么我们⾃然能想到,如果不设置Callbacks,那是不是就能正常执⾏呢?⽐如 这样:
不好意思,运⾏这段代码时,cglib在构造代理对象时就会报⼀个没有Callbacks的空指针异常,所以我 们⽆法看到我们想看到的效果。
但是这并不影响我们继续研究,我们再来看代理类中的另外⼀个⽅法:
这个⽅法我们并不能直接调⽤,要通过所设置的Callback,也就是MethodInterceptor中的 MethodProxy对象来调⽤,MethodProxy对象表示⽅法代理,举个例⼦,假如UserService代理对象在 执⾏test()⽅法,那么当执⾏流程进⼊到intercept()⽅法时,MethodProxy对象表示的就是test()⽅法, 但是我们现在知道了在UserService类和UserService代理类中都有test()⽅法,所以MethodProxy对象 代理的就是这两个test(),⽐如:
所以在执⾏methodProxy.invokeSuper()⽅法时,就会去执⾏CGLIB$test$0()⽅法。
我们来总结⼀下cglib的⼤概⼯作原理是:cglib会根据所设置的Superclass,⽣成代理类作为其⼦类, 并且会重写Superclass中的⽅法,Superclass中的某⼀个⽅法,⽐如test(),相应的在代理类中会对应 两个⽅法,⼀个是重写的test(),⽤来执⾏增强逻辑,⼀个是CGLIB$test$0(),会直接调⽤ super.test(),是让MethodProxy对象来⽤的。
那接下来的问题就是:
1.代理类是怎么⽣成的?
2. MethodProxy是怎么实现的?
我们下篇⽂章⻅。
-
cglib底层源码分析(⼆)
2022-04-12 19:08:09其实我们如果看到了cglib所⽣成的代理类之后,其实就不难猜测,cglib是如何去⽣成代理类了,我们看 ⼀个完整的代理类: 我们发现,UserService代理类既继承了UserService类,也实现了Factory接⼝,从⽽...其实我们如果看到了cglib所⽣成的代理类之后,其实就不难猜测,cglib是如何去⽣成代理类了,我们看 ⼀个完整的代理类:
我们发现,UserService代理类既继承了UserService类,也实现了Factory接⼝,从⽽代理中就需要去 实现Factory接⼝中的⼏个⽅法:
我们可以发现newInstance()⽅法会重新⽣成⼀个代理对象,setCallbacks()和getCallbacks()可以⽤来 设置或获取增强逻辑。
我们还发现,不仅只有test()⽅法会⽣成对应的两个⽅法,其他⽅法也会⽣成,⽐如:
1. equals()
2. toString()
3. hashCode()
4. clone()
对于这些⽅法的实现上篇⽂章已经有所介绍了,所以我们再看⼀下⼀下代理类中还有什么代码是我们不 熟悉的:
我们发现代理中有很多的属性,仔细阅读可以发现,这些属性中很多都是针对某个⽅法的Method对象 和MethodProxy对象,我们先把equals等所对应的先去掉:
代理类中有⼀个代理块,会调⽤CGLIB$STATICHOOK1(),这个⽅法主要就是给属性赋值,⽐如:
1. 构造⼀个ThreadLocal对象给CGLIB$THREAD_CALLBACKS属性
2. 获取UserService类中的test⽅法的Method对象给CGLIB$test$0$Method属性
3. 构造test()⽅法所对应的MethodProxy对象给CGLIB$test$0$Proxy属性
另外,代理类中还有⼀些其他⽅法,但是我看了源码后,发现有⼏个⽅法它只是⽣成了,并没有被调⽤ 到,其中有⼀个⽅法是cglib在⽣成代理对象后,会主动调⽤的⼀个⽅法,这个⽅法是 CGLIB$SET_THREAD_CALLBACKS,我把其他⼏个不⽤的⽅法去掉:
这样,我们就可以更加理解这个代理类了,⼤致流程是:
1. cglib先⽣成代理类
2. 然后调⽤构造⽅法得到代理对象
3. 然后cglib调⽤代理对象的CGLIB$SET_THREAD_CALLBACKS()⽅法,把程序员所设置的 Callbacks设置到CGLIB$THREAD_CALLBACKS这个ThreadLocal中
4. 后续代理对象在执⾏test()⽅法时,就会从CGLIB$THREAD_CALLBACKS拿到所设置的 Callbacks,调⽤其intercept()⽅法
⽽代理类的⽣成逻辑就是:
1. 先⽣成类的定义,实现UserService和Factory接⼝
2. 根据UserService类中的⽅法⽣成代理类中对应的⽅法和属性
3. ⽣成⼀些辅助的属性和⽅法
具体源码就不去分析了,感兴趣的可以⾃⼰花时间去啃了。
⽂章到这⾥,还有还有⼀个点没分析,就是MethodProxy对象,下篇⽂章继续。
-
springAOP-CGLIB代理源码分析
2019-08-18 18:14:49(1)如果为true,那么使用cglib的动态代理。 (2)如果为true为false或这不设置,那么aop根据类是否继承接口决定用哪一种代理方式。 那么cglib的代理方式是怎么实现的呢,一起来探究一下: jdk的动态代理是用... -
Cglib源码分析 invoke和invokeSuper的差别
2018-03-17 17:06:20本文重在源码的分析,Cglib的使用不再复述。 //被代理类 public class InfoDemo { public void welcome (String person){ System.out.println("welcome :" + person); } } public class ... -
cglib源码分析--转
2019-09-27 03:41:48前段时间在工作中,包括一些代码阅读过程中,spring aop经常性的会看到cglib中的相关内容,包括BeanCopier,BulkBean,Enancher等内容,以前虽大致知道一些内容,原理是通过bytecode,但没具体深入代码研究,只知其... -
Cglib源码分析 invoke和invokeSuper的差别(转)
2018-05-14 23:34:00原文... Cglib的实例 本文重在源码的分析,Cglib的使用不再复述。 //被代理类 public class InfoDemo { public void welcome (String person){ System.out.pr... -
Cglib动态代理源码分析
2022-02-10 11:30:31public class MyTest { public static void main(String[] args) { //动态代理创建的class文件... //通过cglib动态代理获取代理对象的过程,创建调用的对象,在后续创建过程中EnhanceKey的对象,所以在进行enhance. -
cglib底层源码分析(三)
2022-04-14 19:24:57前⾯介绍到MethodProxy对象,表示⼀个⽅法的代理,⽐如UserSerivce中的test()⽅法,在对应的代理 类中会有对应的两个⽅法: ⽽MethodProxy对象代理...2. sig2,表示CGLIB$test$0⽅法 3. createInfo,表示Us... -
Spring AOP(六)【源码分析】Spring中CgLib动态代理的实现
2020-08-12 00:30:57CgLib中AOP的实现是基于org.springframework.cglib.proxy包中Enhancer和MethodInterceptor(是CgLib包中的)两个接口来实现的。创建增强器Enhancer,并配置其callback为自定义的MethodInterceptor,然后创建代理。... -
Cglib源码解析
2018-02-27 21:47:34Cglib(Code Generator Library)是一个 java字节码生成工具,...本系列文章分析cglib的源码实现。一、基本框架ClassGenerator是Cglib的核心接口,其中核心方法generateClass方法用于产生目标类;public interface Cla... -
cglib源码分析(一): 缓存和KEY
2014-07-15 15:22:00cglib是一个java 字节码的生成工具,它是对asm的进一步封装,提供了一系列class generator。研究cglib主要是因为它也提供了动态代理功能,这点和jdk的动态代理类似。 一、 Cache的创建 与jdk动态代理一样,cglib... -
cglib动态代理原理分析(含部分源码分析)
2022-05-28 23:24:09cglib动态代理 给出一个例子,再做分析 目标类 public class AliSmsService { public String send(String message) { System.out.println("send message:" + message); return message; } } 实现一个 ... -
cglib源码分析(二):Class name 生成策略
2014-07-16 13:18:00结合生成的class文件是一个学习cglib的比较好的方法。在cglib中,生成的class文件默认只存储在内存中,我们可以在代码中加入下面语句来获取class file。 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_... -
JDK动态代理和CGLIB代理源码分析
2021-09-07 16:20:54目录 一、使用方式 1.业务方法类 2.实现代理方法 3.使用场景分析 3.1.使用CGLIB代理执行非接口实现类HelloWorld ...3.2.使用CGLIB代理执行接口实现类UserServiceImpl ...2.CGLIB代理源码分析 2.1创建代理对象 2.2调 -
cglib源码分析(三):Class生成策略
2014-07-23 14:11:00cglib中生成类的工作是由AbstractClassGenerator的create方法使用相应的生成策略完成,具体代码如下: private GeneratorStrategy strategy = DefaultGeneratorStrategy.INSTANCE; byte[] b = strategy.generate... -
Spring | Aop核心 | Cglib源码详细解析
2018-10-27 23:37:05概述 很多时候在编译时期不能决定具体的对象类型,无法生成所需要的字节码。只能在运行时期,根据传入的实例,来生成字节码。这就是动态代理要解决的问题...Spring Aop中的代理生成方式采用了jdk动态代理和cglib... -
Spring源码解析(24)之JDK动态代理与cglib动态代理源码解析
2022-03-23 09:35:35一、前言 ...二、JDK动态代理源码分析 下面先来看下我们一般是如何使用JDK动态代理的。 /** * @author maoqichuan * @date 2022年03月22日 18:42 */ public class CalculatorProxy { public s... -
cglib 源代码分析(原创)
2019-08-12 01:46:59NULL 博文链接:https://zhangyu84849467.iteye.com/blog/2278744 -
cglib动态代理源码解析 超级详细
2019-05-13 20:31:20一、CGLIB动态代理实例 小A同学想要找女朋友,自己又不好意思,所以需要一个媒婆帮助他找对象,媒婆作为小A的代理,下面我们使用cglib动态代理,来用代码实现下: xiaoA: public class XiaoA { public void ...