CGLIB是一個強大的高性能的代碼生成包。它廣泛地被許多AOP的框架使用,例如Spring AOP和dynaop,為他們提供方法的Interception(攔截)。EasyMock和jMock是通過使用模仿(moke)對象來測試Java代碼的包。它們都通過使用CGLIB來為那些沒有接口的類創建模仿(moke)對象。
CGLIB包的底層通過使用一個小而快的字節碼處理框架ASM,來轉換字節碼並生成新的類。除了CGLIB包,腳本語言例如Groovy和BeanShell,也是使用ASM來生成Java的字節碼。當然不鼓勵直接使用ASM,因為它要求你必須對JVM內部結構包括class文件的格式和指令集都很熟悉。
CGLIB代理的類是委托給CglibAopProxy類去實現的。Cglib2AopProxy的入口是在getProxy,也就是說在CglibAopProxy類的getProxy方法中實現了Enhancer的創建及接口封裝。
public Object getProxy() { return getProxy(null); } public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating CGLIB proxy: target source is " + 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 (ClassUtils.isCglibProxyClass(rootClass)) { proxySuperClass = rootClass.getSuperclass(); Class<?>[] additionalInterfaces = rootClass.getInterfaces(); for (Class<?> additionalInterface : additionalInterfaces) { this.advised.addInterface(additionalInterface); } } //驗證Class validateClassIfNecessary(proxySuperClass); //創建及配置Enhancer Enhancer enhancer = createEnhancer(); 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); enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class)); enhancer.setInterceptDuringConstruction(false); //設置攔截器 Callback[] callbacks = getCallbacks(rootClass); Class<?>[] types = new Class<?>[callbacks.length]; for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); enhancer.setCallbackTypes(types); enhancer.setCallbacks(callbacks); //生成代理類以及創建代理 Object proxy; if (this.constructorArgs != null) { proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs); } else { proxy = enhancer.create(); } return proxy; } catch (CodeGenerationException ex) { throw new AopConfigException("Could not generate CGLIB subclass of class [" + this.advised.getTargetClass() + "]: " + "Common causes of this problem include using a final class or a non-visible class", ex); } catch (IllegalArgumentException ex) { throw new AopConfigException("Could not generate CGLIB subclass of class [" + this.advised.getTargetClass() + "]: " + "Common causes of this problem include using a final class or a non-visible class", ex); } catch (Exception ex) { throw new AopConfigException("Unexpected AOP exception", ex); } }
以上函數完整地闡述了一個創建Spring中的Enhancer的過程,參考Enhancer的文檔查看每個步驟的含義,這里最重要的是通過getCallbacks方法設置攔截器鏈。
private Callback[] getCallbacks(Class<?> rootClass) throws Exception { //對於expose-proxy屬性的處理 boolean exposeProxy = this.advised.isExposeProxy(); boolean isFrozen = this.advised.isFrozen(); boolean isStatic = this.advised.getTargetSource().isStatic(); //將攔截器封裝在DynamicAdvisedInterceptor中 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中 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 optimisations 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<String, Integer>(methods.length); // TODO: small memory optimisation here (can skip creation for methods with no advice) for (int x = 0; x < methods.length; x++) { List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass); fixedCallbacks[x] = new FixedChainStaticTargetInterceptor( chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass()); this.fixedInterceptorMap.put(methods[x].toString(), 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; }
在getCallback中Spring考慮了很多情況,對於我們來說,只需要理解最常用的就可以了,比如將advised屬性封裝在DynamicAdvisedInterceptor並加入在callbacks中,這么做的目的是什么呢,如何調用呢?CGLIB中對於方法的攔截是通過將自定義的攔截器(實現MethodInterceptor接口)加入Callback中並在調用代理時直接激活攔截器中的intercept方法來實現的,那么在getCallback中正是實現了這樣一個目的,DynamicAdvisedInterceptor繼承自MethodInterceptor,加入Callback中后,在再次調用代理時會直接調用DynamicAdvisedInterceptor中的intercept方法,由此推斷,對於CGLIB方式實現的代理,其核心邏輯必然在DynamicAdvisedInterceptor中的intercept中。
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Class<?> targetClass = null; Object target = null; try { if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // May be null. Get as late as possible to minimize the time we // "own" the target, in case it comes from a pool... target = getTarget(); if (target != null) { targetClass = target.getClass(); }
//獲取攔截器鏈 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())) { //如果攔截器鏈為空則直接激活原方法 retVal = methodProxy.invoke(target, args); } else { //進入鏈 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } retVal = processReturnType(proxy, target, method, retVal); return retVal; } finally { if (target != null) { releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } }
上述的實現與JDK方式實現代理中的invoke方法大同小異,都是首先構造鏈,然后封裝此鏈進行串聯調用,稍有些區別就是在JDK中直接構造ReflectiveMethodInvocation,而在cglib中使用CglibMethodInvocation。CglibMethodInvocation繼承自ReflectiveMethodInvocation,但是proceed方法並沒有重寫。