這篇文章主要介紹了Spring5源碼之CglibAopProxy,通過Cglib代理使用示例來一步步剖析源碼。需要的朋友可以參考一下。
1、Cglib使用示例
Cglib是一個強大的高性能的代碼生成包。Cglib包的底層通過使用一個小而快的字節碼處理框架ASM,來轉換字節碼並生成新的類。除了Cglib包,腳本語言例如Groovy和BeanShell,也是使用ASM來生成Java字節碼。當然不鼓勵直接使用ASM,因爲它要求你必須對JVM內部(包括class文件的格式和指令集)都很熟悉。
- 目標類MyEnhancer
package com.test.spring5code.cglib.enhancer;
import lombok.extern.slf4j.Slf4j;
/**
* @Description: my Enhancer
* @Author: Janson
* @Date: 2020/5/1 22:50
**/
@Slf4j
public class MyEnhancer {
public void testCglib(){
log.info("MyEnhancer testCglib");
}
}
- Cglib動態代理類MyMethodInterceptor
package com.test.spring5code.cglib.method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @Description: my MethodInterceptor
* @Author: Janson
* @Date: 2020/5/1 22:41
**/
@Slf4j
public class MyMethodInterceptor implements MethodInterceptor {
private static volatile MyMethodInterceptor instance;
private MyMethodInterceptor() {
// do nothing
}
public static MyMethodInterceptor getInstance() {
if (instance == null) {
synchronized (MyMethodInterceptor.class) {
if (instance == null) {
instance = new MyMethodInterceptor();
}
}
}
return instance;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
log.info("before invoke method:{}", method);
Object result = methodProxy.invokeSuper(o, objects);
log.info("after invoke method:{}", method);
return result;
}
private Enhancer enhancer = new Enhancer();
public <T> T getProxy(Class<T> clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return (T) enhancer.create();
}
}
- Cglib測試類CglibPrxoyTest
package com.test.spring5code;
import com.test.spring5code.cglib.enhancer.MyEnhancer;
import com.test.spring5code.cglib.method.MyMethodInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
/**
* @Description: cglib proxy test
* @Author: Janson
* @Date: 2020/5/1 23:07
**/
@Slf4j
public class CglibPrxoyTest {
@Test
public void testCglibProxy() {
MyEnhancer proxy = MyMethodInterceptor.getInstance().getProxy(MyEnhancer.class);
proxy.testCglib();
log.info("MyEnhancer:{}", proxy);
}
}
- Cglib測試類CglibPrxoyTest輸出結果
23:17:04.708 [main] INFO com.test.spring5code.cglib.method.MyMethodInterceptor - before invoke method:public void com.test.spring5code.cglib.enhancer.MyEnhancer.testCglib()
23:17:04.719 [main] INFO com.test.spring5code.cglib.enhancer.MyEnhancer - MyEnhancer testCglib
23:17:04.719 [main] INFO com.test.spring5code.cglib.method.MyMethodInterceptor - after invoke method:public void com.test.spring5code.cglib.enhancer.MyEnhancer.testCglib()
23:17:04.719 [main] INFO com.test.spring5code.CglibPrxoyTest - MyEnhancer:com.test.spring5code.cglib.enhancer.MyEnhancer$$EnhancerByCGLIB$$c6f3e22@6ab7a896
從 log.info(“MyEnhancer:{}”, proxy)輸出結果來看,首先調用了toString方法,然後又調用了hashCode方法,生成對象的爲MyEnhancer$$EnhancerByCGLIB$$c6f3e22@6ab7a896
,這個類是運行時由Cglib產生的。完成Cglib代理的類是委託給CglibAopProxy類去實現的。
2、CglibAopProxy
public Object getProxy(@Nullable 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, classLoader);
// 創建及配置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 ClassLoaderAwareUndeclaredThrowableStrategy(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只在上面的getCallbacks調用之後填充
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// 生成代理類並創建代理實例
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) {
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
以上方法完整地闡述了一個創建Spring中的Enhancer的過程,讀者可以參考Enhancer文檔查看每個步驟的含義,這裏最重要的是通過getCallbacks方法設置攔截器鏈。
3、getCallbacks
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// 用於優化選擇的參數
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
// 選擇一個aop攔截器(用於aop調用)
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// 選擇一個直接命中目標的攔截器
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()));
}
// 選擇直接到目標的轉發
Callback targetDispatcher = (isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());
Callback[] mainCallbacks = new Callback[] {
// 將攔截器加入Callback
aopInterceptor,
targetInterceptor,
new SerializableNoOp(),
targetDispatcher, this.advisedDispatcher,
new EqualsInterceptor(this.advised),
new HashCodeInterceptor(this.advised)
};
Callback[] callbacks;
// 如果目標是靜態的,並且通知鏈是凍結的,然後我們可以通過發送AOP調用來進行一些優化
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap<>(methods.length);
// 這裏的小內存優化(可以跳過沒有通知的方法的創建)
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(methods.toString(), x);
}
// 現在從mainCallbacks複製兩個回調並將fixedCallbacks放入callbacks數組中
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;
}
4、DynamicAdvisedInterceptor
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) {
// 在必要時使調用可用。
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 獲取攔截器鏈
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// 如果攔截器鏈爲空,則直接激活原方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// 進入攔截器鏈
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) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
上述的實現與JDK方式的實現代理的invoke方法大同小異,都是手洗構造鏈,然後封裝此鏈進行串聯調用,稍有些區別就是JDK找那個直接構造ReflectiveMethodInvocation,而在Cglib中使用CglibMethodInvocation。CglibMethodInvocation繼承自ReflectiveMethodInvocation,但是proceed方法並沒有重寫。
如果您覺得有幫助,歡迎點贊收藏哦 ~ ~ 多謝~