SpringAop 源码解析 (二) - 代理对象的创建以及执行过程

news2025/1/17 0:00:32

一、SpringAop 代理创建 以及 执行过程

在上篇文章中分析得出在使用 Aop 时,实际向 Spring 容器中注入了一个 AnnotationAwareAspectJAutoProxyCreator 动态代理 bean 生成处理器,该类有实现 BeanPostProcessor 扩展方法,并且在 postProcessAfterInitialization 进行了代理的创建,主要逻辑在 AbstractAutoProxyCreator 类下的 wrapIfNecessary 方法中,上篇文章主要分析的该方法下getAdvicesAndAdvisorsForBean 方法,主要做了对切面方法的扫描和匹配过程,并且这里拿到的结果就是所有匹配的切面方法包装类集合,本篇文章继续上篇文章的脚步,分析下后面代理对象的创建过程和执行过程。

下面是上篇文章的地址:

SpringAop 源码解析 (一) - Aspect 切面方法的查找匹配过程

二、动态代理类型的判断过程

在这里插入图片描述
上面文章分析到这个位置,下面继续,如果存在匹配的切面方法,则先进行标记,反之不存在也进行标记,下次再进来该 beanName 时,不存在就直接跳过了。

这里看到获取到匹配的切面方法后,通过 createProxy 方法创建了代理对象,下面看到该方法下:

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
		@Nullable Object[] specificInterceptors, TargetSource targetSource) {

	if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
		AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
	}
       // 创建代理工厂
	ProxyFactory proxyFactory = new ProxyFactory();
	proxyFactory.copyFrom(this);

	if (!proxyFactory.isProxyTargetClass()) {
		if (shouldProxyTargetClass(beanClass, beanName)) {
			proxyFactory.setProxyTargetClass(true);
		}
		else {
			evaluateProxyInterfaces(beanClass, proxyFactory);
		}
	}

	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
	proxyFactory.addAdvisors(advisors);
	proxyFactory.setTargetSource(targetSource);
	customizeProxyFactory(proxyFactory);

	proxyFactory.setFrozen(this.freezeProxy);
	if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
	}

	return proxyFactory.getProxy(getProxyClassLoader());
}

这里创建了一个代理工厂,并将切面方法、目标 bean 资源等,设置进入了该代理工厂中。

下面主要看到 proxyFactory.getProxy 又是如何创建代理对象的:

public Object getProxy(@Nullable ClassLoader classLoader) {
	return createAopProxy().getProxy(classLoader);
}

这里首先使用 createAopProxy 方法创建一个 AopProxy ,然后再通过AopProxygetProxy 生成代理对象。

这里先看到 createAopProxy 方法下,在 ProxyCreatorSupport 类中:

protected final synchronized AopProxy createAopProxy() {
	if (!this.active) {
		activate();
	}
	// 通过 aop动态代理工厂 创建 aop动态代理
	return getAopProxyFactory().createAopProxy(this);
}

这里通过 AopProxyFactorycreateAopProxy 创建一个 AopProxy ,默认情况下 AopProxyFactory 的具体实现为 DefaultAopProxyFactory 类,在ProxyCreatorSupport 类的无参构造方法中进行初始化的。

在这里插入图片描述

下面看到 DefaultAopProxyFactory 类中的 createAopProxy 方法中:

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	if (!IN_NATIVE_IMAGE &&
			(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动态代理
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		// 如果被代理对象没有实现接口,则使用 cglib 动态代理
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		// 当前环境是否是原生环境,原生环境,使用 jdk动态代理
		return new JdkDynamicAopProxy(config);
	}
}

这里判断目标类是否有实现接口,如果有的话则使用 JDK 的动态代理,否则的话使用 cglib 进行代理。

下面回到上面的 getProxy 方法中,createAopProxy() 方法生成的要么是JDK 的动态代理,要么是 cglib 的动态代理,这里首先看下 JDK 动态代理的创建过程。

三、JDK 动态代理创建过程

这里先分析下 JdkDynamicAopProxy

在这里插入图片描述
可以看到实现了 InvocationHandler 接口,因此在执行代理时,会触发该类下的 invoke 方法。

再看下 JdkDynamicAopProxy 类的构造方法中做了什么事情:

public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
	Assert.notNull(config, "AdvisedSupport must not be null");
	//判断增强器和拦截器的数量
	if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
		//如果为0就抛出异常
		throw new AopConfigException("No advisors and no TargetSource specified");
	}
	//注入配置
	this.advised = config;
	// 获取完整的代理接口,并进行缓存
	this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
	// 判断有没有定义的equals方法和hashCode方法
	findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces);
}

这里先判断增强器也就是切面方法是否存在,如果不存在代理也没有意义了,接着将配置注入到 advised 属性中,最后标记出被代理类是否有定义 equals 方法和 hashCode 方法。

下面再看到 getProxy 方法,如何生成代理对象的:

public Object getProxy(@Nullable ClassLoader classLoader) {
	if (logger.isTraceEnabled()) {
		logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
	}
	// 通过JDK 的 Proxy完成动态代理
	return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}

直接通过 Proxy.newProxyInstance 创建代理实例,并且 InvocationHandler 就是自己,也就是触发执行代理时会触发该类下的 invoke 方法。

四、JDK 动态代理执行过程

JDK 动态代理执行,直接看到动态的代理的 invoke 方法中

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	Object oldProxy = null;
	boolean setProxyContext = false;

	// 获取被代理对象的类信息
	TargetSource targetSource = this.advised.targetSource;
	Object target = null;

	try {
		if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
			// The target does not implement the equals(Object) method itself.
			// 如果被代理对象没有重写 equals方法,则调用本地的方法。 比较的是被代理对象
			return equals(args[0]);
		}
		else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
			// The target does not implement the hashCode() method itself.
			// 如果被代理对象没有重写 hashCode 方法,则调用本地的 hashCode 方法。
			return hashCode();
		}
		else if (method.getDeclaringClass() == DecoratingProxy.class) {
			// There is only getDecoratedClass() declared -> dispatch to proxy config.
			// 如果实现了 DecoratingProxy的方法,则 分发给代理配置
			return AopProxyUtils.ultimateTargetClass(this.advised);
		}
		else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
				method.getDeclaringClass().isAssignableFrom(Advised.class)) {
			// Service invocations on ProxyConfig with the proxy config...
			// 使用代理配置在ProxyConfig上调用服务
			return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
		}

		// 实际方法的返回值
		Object retVal;

		// 如果需要暴露至 threadLocal,则进行暴露
		// 目的是在同一个类中自我方法调用的情况下
		// 由于执行问题 被调用的无法执行代理
		// 因此可以通过配置 exposeProxy 为 true,将代理方法缓存到 threadLocal 中
		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);

		// Get the interception chain for this method.
		// 获取被代理类的当前方法的增强器链
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

		// Check whether we have any advice. If we don't, we can fallback on direct
		// reflective invocation of the target, and avoid creating a MethodInvocation.
		// 如果没有匹配的通知器,则通过反射直接进行调用
		if (chain.isEmpty()) {
			// 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 = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
		}
		else {
			// We need to create a method invocation...
			// 根据切面的配置,构造方法执行链
			MethodInvocation invocation =
					new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
			// Proceed to the joinpoint through the interceptor chain.
			// 通过过滤器链逐步执行连接点,每一个拦截器即是一个连接点
			retVal = invocation.proceed();
		}

		// Massage return value if necessary.
		// 对方法结果进行处理
		Class<?> returnType = method.getReturnType();
		if (retVal != null && retVal == target &&
				returnType != Object.class && returnType.isInstance(proxy) &&
				!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
			// Special case: it returned "this" and the return type of the method
			// is type-compatible. Note that we can't help if the target sets
			// a reference to itself in another returned object.
			retVal = proxy;
		}
		//如果返回值为null,并且返回类型不是void类型,并且返回类型还被定义为基本数据类型
		else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
			throw new AopInvocationException(
					"Null return value from advice does not match primitive return type for: " + method);
		}
		//返回返回值
		return retVal;
	}
	finally {
		if (target != null && !targetSource.isStatic()) {
			// Must have come from TargetSource.
			targetSource.releaseTarget(target);
		}
		//如果暴露过proxyContext
		if (setProxyContext) {
			// Restore old proxy.
			// 恢复为原始的proxy
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}

这里讲下 this.advised.exposeProxy 的作用,该值就是使用 @EnableAspectJAutoProxy 注解中的 exposeProxy 参数,如果是 true 的话,则会对当前代理对象进行缓存,目的是在同一个类中自我方法调用的情况下,如果被调用的方法带有 @Transactional@Async 等注解,直接调用方法注解会失效,因为指向的是this指针,并不是代理类,因此可以设置 exposeProxy 参数为true,将代理类缓存下来,自我调用时使用 AopContext.currentProxy() 获取到当前的代理对象,例如下面的案例:

@Component
public class TestAop {

    public void test(){
        System.out.println("test...");
        // 自我调用
        ((TestAop) AopContext.currentProxy()).test2();
    }

    @Transactional
    public void test2(){
        System.out.println("test2");
    }
}

这里的缓存其实就是使用的 ThreadLocal 进行的存储:

在这里插入图片描述

在继续看 invoke 方法,下面使用 this.advised.getInterceptorsAndDynamicInterceptionAdvice 生成所有匹配的切面方法的执行链,下面看到该方法中:

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
	MethodCacheKey cacheKey = new MethodCacheKey(method);
	List<Object> cached = this.methodCache.get(cacheKey);
	if (cached == null) {
		cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
				this, method, targetClass);
		this.methodCache.put(cacheKey, cached);
	}
	return cached;
}

这里会对执行链进行缓存,这里看下缓存中不存在时,调用的 this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice 方法:

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
		Advised config, Method method, @Nullable Class<?> targetClass) {

	// This is somewhat tricky... We have to process introductions first,
	// but we need to preserve order in the ultimate list.
	// 通知器适配注册表
	AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
	// 从动态代理配置中,获取 通知器列表
	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) {
					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) {
							// 当切面匹配器已经在工作时,则放入 InterceptorAndDynamicMethodMatcher,运行时匹配
							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;
}

在该方法中,获取到之前匹配出来的切面方法,再次进行筛选匹配。

下面再回到 invoke 方法中,接着向下看如果执行链为空则直接使用 AopUtils.invokeJoinpointUsingReflection 方法触发目标方法,逻辑如下:

public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
		throws Throwable {

	// Use reflection to invoke the method.
	try {
		ReflectionUtils.makeAccessible(method);
		return method.invoke(target, args);
	}
	catch (InvocationTargetException ex) {
		// Invoked method threw a checked exception.
		// We must rethrow it. The client won't see the interceptor.
		throw ex.getTargetException();
	}
	catch (IllegalArgumentException ex) {
		throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
				method + "] on target [" + target + "]", ex);
	}
	catch (IllegalAccessException ex) {
		throw new AopInvocationException("Could not access method [" + method + "]", ex);
	}
}

如果执行链存在,则根据切面的配置,构造一个 ReflectiveMethodInvocation 切面方法的执行链,执行链中包含了切面方法、目标方法、目标对象等:

protected ReflectiveMethodInvocation(
		Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
		@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {

	this.proxy = proxy;
	this.target = target;
	this.targetClass = targetClass;
	this.method = BridgeMethodResolver.findBridgedMethod(method);
	this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
	// 拦截器的动态方法匹配器
	this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}

再向下看则调用了 invocation.proceed() ,其实是触发所有的切面增强方法,最后再触发目标方法,看到 ReflectiveMethodInvocation 类中,逻辑如下:

public Object proceed() throws Throwable {
	// 该方法为 jdk的AOP实现的核心
	// 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);
		}
		//如果动态匹配失败,递归进行proceed
		//不匹配就不执行当前的拦截器
		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);
	}
}

这里使用 currentInterceptorIndex 变量表示当前触发的第几个切面增强方法,首先判断的当 currentInterceptorIndex 等于interceptorsAndDynamicMethodMatchers 最后一个时,就是代表所有的切面方法都触发完了,这里的 invokeJoinpoint() 等一会再看。

先来看
((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this) 是如何触发的目标切面方法,这里可以看到实现有很多种:

在这里插入图片描述

这里还是以 MethodBeforeAdviceInterceptor 为例,表示 @Before 前置通知方法:

public Object invoke(MethodInvocation mi) throws Throwable {
	this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
	// 继续触发下一个
	return mi.proceed();
}

这里通过 this.advice.before 触发前置通知方法后,又递归的方式触发下一个切面增强方法。这里看下 this.advice.before怎么触发的前置通知方法:

在这里插入图片描述在这里插入图片描述
最终触发的是 invokeAdviceMethodWithGivenArgs 方法,逻辑如下:

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
	//对参数处理
	Object[] actualArgs = args;
	if (this.aspectJAdviceMethod.getParameterCount() == 0) {
		actualArgs = null;
	}
	try {
		//下面就是通过反射来调用方法了
		//先让方法变得可以访问
		ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
		// TODO AopUtils.invokeJoinpointUsingReflection
		//使用切面实例共产获取切面实例,然后执行建言方法
		return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
	}
	catch (IllegalArgumentException ex) {
		throw new AopInvocationException("Mismatch on arguments to advice method [" +
				this.aspectJAdviceMethod + "]; pointcut expression [" +
				this.pointcut.getPointcutExpression() + "]", ex);
	}
	catch (InvocationTargetException ex) {
		throw ex.getTargetException();
	}
}

通过反射直接触发目标切面方法。

下面再回到 proceed() 方法中,当执行完所有的切面方法后会触发 invokeJoinpoint 方法:

在这里插入图片描述
这里和前面无执行链时调用逻辑一样,使用AopUtils.invokeJoinpointUsingReflection 方法触发目标方法。

五、cglib 动态代理创建过程

cglib 动态代理和 JDK动态代理实现逻辑大致相同,这里还是先看下继承关系:
在这里插入图片描述
继承了 CglibAopProxy ,主要代理创建的逻辑其实都在 CglibAopProxy 中,构造方法也是调用了父类的构造方法中:

public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
	Assert.notNull(config, "AdvisedSupport must not be null");
	if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
		throw new AopConfigException("No advisors and no TargetSource specified");
	}
	this.advised = config;
	this.advisedDispatcher = new AdvisedDispatcher(this.advised);
}

同样也是将配置注入到 advised 属性中,下面主要看到 getProxy 方法 中:

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);
			}
		}

		// Validate the class, writing log messages as necessary.
		// 对类进行合法性验证
		validateClassIfNecessary(proxySuperClass, classLoader);

		// Configure CGLIB Enhancer...
		// 创建 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 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.
		// 创建cglib动态代理实例
		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);
	}
}

这里主要声明了 cglib 中的 Enhancer 实例,并填充代理的信息,其中创建代理对象在 createProxyClassAndInstance 方法中:

protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
	enhancer.setInterceptDuringConstruction(false);
	enhancer.setCallbacks(callbacks);
	return (this.constructorArgs != null && this.constructorArgTypes != null ?
			enhancer.create(this.constructorArgTypes, this.constructorArgs) :
			enhancer.create());
}

六、cglib 动态代理执行过程

JDK 动态代理时,触发代理类时会触发 invoke 方法,同样在 cglib 代理中,触发代理类时,会触发 Enhancercallbacks 类中的 intercept 方法,下面就从 callbacks 开始分析:

在前一步创建代理时 callbacks 就是通过 getCallbacks 方法获取的结果,下面看到该方法下:

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
	// Parameters used for optimization choices...
	//判断是不是要进行曝光
	boolean exposeProxy = this.advised.isExposeProxy();
	boolean isFrozen = this.advised.isFrozen();
	boolean isStatic = this.advised.getTargetSource().isStatic();

	// Choose an "aop" interceptor (used for AOP calls).
	// 创建 cgLib 层面的动态切面拦截器,动态代理通过它完成
	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;

	//判断是否要曝光
	//根据是否要曝光并且是动态代理还是静态代理去生成拦截器
	//这里的targetInterceptor拦截器称为目标拦截器
	//这个拦截器的作用实质上没有对方法进行增强,但里面的额外操作会将当前代理对象切面曝光出来
	//Cglib还支持静态代理咧。。。
	if (exposeProxy) {
		//如果要曝光,对应要创建exposedInterceptor
		//并且从创建方法可以看到,直接给了目标对象,并没有给增强器
		//在这里exposedInterceptor是会对代理对象进行曝光的
		targetInterceptor = (isStatic ?
				new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
				new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
	}
	else {
		//如果不需要曝光,创建unadvvisedInterceptor,从名字就可以看出,是一个没有增强器的拦截器
		//但其实还会对返回值做一些处理
		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).
	// 创建targetDispatcher,这个跟unadvisedInterceptor的作用其实差不多
	// 直接执行目标对象的方法,本质上没有做其他任何其他增强操作,不过可能会对返回值做一些处理
	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 = CollectionUtils.newHashMap(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);
			//封装成FixedChainStaticTargetInterceptor存放进fixedCallBacks中
			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都集合起来
		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 中的 intercept 方法:

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 {
		// 如果需要暴露至 threadLocal,则进行暴露
		// 目的是在同一个类中自我方法调用的情况下
		// 由于执行问题 被调用的无法执行代理
		// 因此可以通过配置 exposeProxy 为 true,将代理方法缓存到 threadLocal 中
		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);
		}
	}
}

可以看到这里实现逻辑和JDK代理时的大致相同,如果 exposeProxytrue,就缓存暴露至threadLocal中,同样使用 this.advised.getInterceptorsAndDynamicInterceptionAdvice 生成切面增强方法链。

最后 proceed() 方法同样是触发的父类的方法,和 JDK 代理执行了相同的 proceed() 方法:

public Object proceed() throws Throwable {
	try {
		return super.proceed();
	}
	catch (RuntimeException ex) {
		throw ex;
	}
	catch (Exception ex) {
		if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {
			throw ex;
		}
		else {
			throw new UndeclaredThrowableException(ex);
		}
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/415520.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

文心一言 VS chatgpt (7)-- 算法导论2.3 3~4题

三、使用数学归纳法证明:当n刚好是2的幂时&#xff0c;以下递归式的解是 T(n)nlgn。若n2&#xff0c;T(n)2&#xff1b;若n2^k,k>1&#xff0c;T(n)2T(n/2)n。 文心一言&#xff1a; chatgpt&#xff1a; 首先&#xff0c;当 n2 时&#xff0c;T(n)2log₂n2&#xff0c;显…

结构体全解,适合初学者的一条龙深度讲解(附手绘图详解)

我们知道&#xff0c;C语言是允许我们自己来创造类型的&#xff0c;这些类型就叫做——自定义类型。 自定义类型又包括结构体类型&#xff0c;联合体类型还有枚举类型。 今天的文章&#xff0c;我们就着重讲解这其中的结构体类型。 目录 结构体的声明 1.1结构的基础知识 …

托福高频真词List01//附阅读真题

once in a whileoccasionally adv 偶尔 &#x1f36e;segregateseparateV.隔离&#x1f36e;leftover remainingadj.剩余的 rivalcompetitor rivalcompete n.对手 v.对抗 apparentlyseeminglyadv.显然 &#x1f36e;unrivaledunequaledadj.无与伦比的 &#x1f36e;&#x…

TCPIP vs OSI模型:网络通信的两种参考模型有哪些不同?

前言 欢迎来到今天的每日一题&#xff0c;每日一提。昨天聊的是面试中经常会问到tcp协议 。在面试中一旦问到TCP/IP&#xff0c;那么OSI模型肯定是躲不过的。如果直接回答OSI模型有7层&#xff0c;和TCP/IP的区别就是层数不一样。那么恭喜你可以提前回去等通知了。所以今天就聊…

23考研重大软院数一英一391分经验帖

今年这情况之后&#xff0c;所有前人的经验帖作废。 前言&#xff1a; 本校本专业生一战上岸&#xff0c;属于考研界难度最低的一档。 今年有个初试439的怪物&#xff0c;属于是蚌了&#xff0c;第二名也有419&#xff0c;第三名就断档了&#xff0c;我初试第五。 政治78&#…

基于html+css的盒子展示1

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

学习MongoDB这一篇就足够了

这篇博客详细的介绍了MongoDB的安装过程&#xff0c;并配置成了自启动服务&#xff0c;非常方便&#xff0c;亲测有效。 MongoDB的安装配置教程&#xff08;很详细&#xff0c;你想要的都在这里&#xff09;http://t.csdn.cn/XWV0B IDEA中 JAVA操作MongoDB: 1. 这篇博客主要介…

计算机操作系统第四版第五章虚拟存储器—课后题答案

1.常规存储器管理方式具有哪两大特征&#xff1f;它对系统性能有何影响&#xff1f; 一次性和驻留性。 一次性及驻留性特征使得许多在程序中不用或暂时不用的程序&#xff08;数据&#xff09;占据了大量的内存空间&#xff0c;而一些需要运行的作业又无法装入运行&#xff0c;…

CSDN每日一练:鬼画符门之点点大阵

CSDN每日一练&#xff1a;鬼画符门之点点大阵题目描述题目逻辑老顾的提交CSDN题目特色&#xff1a;阅读理解小结题目描述 题目名称&#xff1a;鬼画符门之点点大阵 时间限制&#xff1a;1000ms 内存限制&#xff1a;256M 题目描述 小艺师从鬼画符门派&#xff0c;由于学艺不精只…

如何解决DNS劫持

随着互联网的不断发展&#xff0c;DNS(域名系统)成为了构建网络基础的重要组成部分。而DNS遭到劫持&#xff0c;成为一种常见的安全问题。那么DNS遭到劫持是什么意思呢?如何解决DNS劫持问题呢?下面就让小编来为您一一解答。 DNS遭到劫持是什么意思? DNS遭到劫持指的是黑客通…

SSM学习记录2:传参(注释方式 + SprigMVC项目 + 2022发布版本IDEA)

SpingMVC传参&#xff08;一般方式 json方式&#xff09; 一般方式 package controller;import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBod…

OldWang带你了解MySQL(五)

文章目录&#x1f525;MySQL中定义空值&#x1f525;MySQL中的别名&#x1f525;MySQL中去除重复&#x1f525;查询中的行选择&#x1f525;MySQL中的比较条件&#x1f525;其他比较条件&#x1f525;逻辑条件&#x1f525;优先规则&#x1f525;使用 ORDER BY 排序&#x1f52…

JavaScript【八】JavaScript函数高级

文章目录&#x1f31f;前言&#x1f31f;回调函数&#x1f31f;递归函数&#x1f31f;闭包&#x1f31f;什么是闭包函数?&#x1f31f; 闭包三个特性&#x1f31f; 闭包的缺点&#x1f31f;JavaScript的垃圾回收机制&#x1f31f;闭包小案例&#x1f31f;局部变量长期驻扎内存…

STM32F407串口通信

本文是基于江科大B站视频编写&#xff0c;参考各种资料进行学习。 1、USART串口协议 硬件电路&#xff08;接线&#xff09; 2、USART串口外设 常用波特率为9600、115200 必须对应特定引脚&#xff0c;才能实现通信&#xff0c;如果引脚冲突&#xff0c;看看有没有重…

数据结构和算法学习记录——层序遍历(层次遍历)、二叉树遍历的应用(输出二叉树中的叶节点、求二叉树的高度、二元运算表达式树及其遍历、由两种遍历序列确定二叉树)

目录 层序遍历 思路图解 代码实现 二叉树遍历的应用 输出二叉树中的叶节点 代码实现 求二叉树的高度 思路图解 代码实现 二元运算表达式树及其遍历 由两种遍历序列确定二叉树 层序遍历 层序遍历可以通过一个队列来实现&#xff0c;其基本过程为&#xff1a; 先根…

计算机网络P5~P7

目录 1.计算机网路性能指标 2.吞吐量 3.时延 4.时延带宽积 5.往返时间 6.利用率 7.丢包率 8.计算机体系结构 1.计算机网路性能指标 速率和带宽 速率 &#xff1a;每秒传输的比特的个数 单位 b/s kb/s mb/s gb/s 带宽&#xff1a;表示传送数据的能力 。带宽可以理解为高…

医院手术麻醉信息管理系统源码

医院手术麻醉信息管理系统源码 实现整个围术期术前、术中、术后的全数字化和信息化。 医院手术麻醉临床信息管理系统是一种基于云计算技术的信息系统&#xff0c;它可以帮助医院更好地管理手术麻醉临床信息&#xff0c;提高手术麻醉的安全性和效率。 首先&#xff0c;医院手术…

数学分析:多元微积分1

卓里奇的数学分析的好处在于直接从多元函数来入手多元微积分&#xff0c;引出矩阵&#xff0c;十分自然。 紧集的概念&#xff0c;感觉直接用闭集去理解就行&#xff0c;&#xff08;对于图形学来说&#xff09;。 多元函数的极限&#xff0c;其实和单元函数并没有什么区别。 这…

在你眨眼时,VR这样欺骗你的视觉

VR的沉浸感&#xff0c;可以让人仿佛置身于现实之外&#xff0c;还可以利用各种生物传感特性&#xff0c;来模拟一种具有存在感的虚拟空间。实际上&#xff0c;VR可以很好的欺骗人的感官&#xff0c;比如尽管你身处空间有限的房间中&#xff0c;但在VR中你仿佛已来到开阔的户外…

网络应用程序设计(idea版)——实验三:Web组件重用与JavaBeans

目录 实验预习报告 一、实验目的 二、实验原理 三、实验预习内容 实验报告 一、实验目的 二、实验要求 三、实验内容及要求 实验预习报告 一、实验目的 1. 理解静态包含和动态包含的概念&#xff0c;掌握相关指令和动作的使用&#xff1b; 2. 掌握JavaBeans的含义和…