本文已参与「新人创作礼」活动,一起开启掘金创作之路。
这篇文章主要介绍了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方法并没有重写。
如果您觉得有帮助,欢迎点赞收藏哦 ~ ~ 多谢~