Spring5源码之CglibAopProxy

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

这篇文章主要介绍了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方法并没有重写。

如果您觉得有帮助,欢迎点赞收藏哦 ~ ~ 多谢~