Spring源码深度解析:十六、@Aspect方式的AOP下篇 - createProxy

news2024/12/26 10:39:01

一、前言

文章目录:Spring源码深度解析:文章目录

我们上篇已经分析到了 Spring将已经找到所有适用于当前bean 的Advisor 集合。下面就要创建代理对象了,而代理对象的创建是从 AbstractAutoProxyCreator#createProxy()开始。下面我们就来看看代理对象的创建过程。

1. ProxyFactory

ProxyFactory的结构图如下:
在这里插入图片描述
在代理对象的创建过程中,实际上是委托给ProxyFactory来完成的。ProxyFactory在创建过程中保存了筛选后的 Advisor集合以及其他的一些属性。而在后面创建代理类的时候,将 ProxyFactory作为参数传递给了 JdkDynamicAopProxyObjenesisCglibAopProxy。这个在后面的代码分析中会有详细说明。

二、创建代理类 - AbstractAutoProxyCreator#createProxy

AbstractAutoProxyCreator#createProxy 的代码如下:

	// 这里的入参 beanClass :当前BeanClass, 
	// beanName : 当前BeanName
	// specificInterceptors : 中篇中寻找出来的 Advisor
	// targetSource : SingletonTargetSource 目标类是单例 拥有给定对象的TargetSource接口的实现。 这是Spring AOP框架使用的TargetSource接口的默认实现。 通常不需要在应用程序代码中创建此类的对象。
	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);
		// 判断当前bean 是使用 TargetClass 代理还是接口代理
		if (!proxyFactory.isProxyTargetClass()) {
			// 检查 proxyTargeClass设置以及preservetargetClass 属性
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}
		// 将拦截器 Interceptors 封装成增强器 Advisor
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		// 加入增强器
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		// 定制代理
		customizeProxyFactory(proxyFactory);
		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}
		// 在这里面就封装出了ProxyFactory,并交由其来完成剩下的代理工作。
		return proxyFactory.getProxy(getProxyClassLoader());
	}

代码中已经有详细的注释了,可以看到代理类的创建Spring委托给ProxyFactory去处理,而在此函数中主要是对ProxyFactory的初始化操作:

  1. 获取当前类的属性
  2. 添加代理接口
  3. 封装Advisor并加入到,ProxyFactory
  4. 设置要代理的类
  5. 通过customizeProxyFactory定制代理类 ,对ProxyFactory进一步封装
  6. 进行获取代理操作

下面我们主要下面两个方法:

1. buildAdvisors(beanName, specificInterceptors);

这一步的目的是将Interceptors封装成增强器Advisor。虽然我们之前动态解析的都是Advisor,但是保不齐用户自己注入的并不是Advisor类型,所以这里需要一个转换。

需要注意的是:这里的参数 就是Object[] specificInterceptors就是getAdvicesAndAdvisorsForBean()方法返回的 Advisor,通过对getAdvicesAndAdvisorsForBean()方法的分析我们可以得知,specificInterceptors应该全是InstantiationModelAwarePointcutAdvisorImpl类型。

protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
		// Handle prototypes correctly...
		// 解析注册的所有 Interceptor Name。即我们可以手动添加一些 拦截器,这里将手动添加的拦截器保存到commonInterceptors  中
		Advisor[] commonInterceptors = resolveInterceptorNames();

		List<Object> allInterceptors = new ArrayList<>();
		if (specificInterceptors != null) {
			// 加入拦截器
			allInterceptors.addAll(Arrays.asList(specificInterceptors));
			if (commonInterceptors.length > 0) {
				if (this.applyCommonInterceptorsFirst) {
					allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
				}
				else {
					allInterceptors.addAll(Arrays.asList(commonInterceptors));
				}
			}
		}
		// ... 日志打印
		if (logger.isDebugEnabled()) {
			int nrOfCommonInterceptors = commonInterceptors.length;
			int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
			logger.debug("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
					" common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
		}

		Advisor[] advisors = new Advisor[allInterceptors.size()];
		for (int i = 0; i < allInterceptors.size(); i++) {
			// 拦截器进行转化为 Advisor
			advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
		}
		return advisors;
	}

	/**
	 * Resolves the specified interceptor names to Advisor objects.
	 * @see #setInterceptorNames
	 */
	//  this.interceptorNames 是自己通过set设置的属性。在基础篇中Advice 有过类似的设置。我们这里是没有的
	private Advisor[] resolveInterceptorNames() {
		BeanFactory bf = this.beanFactory;
		ConfigurableBeanFactory cbf = (bf instanceof ConfigurableBeanFactory ? (ConfigurableBeanFactory) bf : null);
		List<Advisor> advisors = new ArrayList<>();
		// 将 interceptorNames 获取到的拦截器保存起来,并返回。
		for (String beanName : this.interceptorNames) {
			if (cbf == null || !cbf.isCurrentlyInCreation(beanName)) {
				Assert.state(bf != null, "BeanFactory required for resolving interceptor names");
				Object next = bf.getBean(beanName);
				advisors.add(this.advisorAdapterRegistry.wrap(next));
			}
		}
		return advisors.toArray(new Advisor[0]);
	}

我们下面来看一下this.advisorAdapterRegistry.wrap(allInterceptors.get(i)); 的实现。
DefaultAdvisorAdapterRegistry#wrap()方法也很简单,就是将adviceObject包装成Advisor

2. proxyFactory.getProxy(getProxyClassLoader());

上述代码中proxyFactory.getProxy(getProxyClassLoader()); 会继续调用到DefaultAopProxyFactory#createAopProxy
因此我们来看DefaultAopProxyFactory#createAopProxy

首先我们来看一下proxyFactory.getProxy()方法。

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

显然意见我们需要将这个内容分为两步:createAopProxy()和 ,CODE>getProxy(classLoader)

2.1 ProxyCreatorSupport#createAopProxy

ProxyCreatorSupport#createAopProxy代码如下,这里我们可以看到,ProxyCreatorSupport#createAopProxy会调用DefaultAopProxyFactory#createAopProxy,并且将this作为参数传递了过去。而此时的 this,正是上面提到的创建的 ProxyFactory

	protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		// 这里我们需要注意的是 ,这里 createAopProxy 传入的是 this。也就是说这里参数传递实际上是ProxyFactroy
		return getAopProxyFactory().createAopProxy(this);
	}

这里我们再来看DefaultAopProxyFactory#createAopProxy的实现

	@Override
	// 这里的参数 AdvisedSupport config 即是之前创建的ProxyFactory。这里又将其传递给了AopProxy 
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (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.");
			}
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

在这个方法中我们可以看到 Aop代理使用了 JDK动态代理和 Cglib动态代理两种动态代理模式,并根据某些参数来进行选择代理方式

createAopProxy代码中我们可以看到几个参数:

  • optimize : 用来控制通过CGlib 创建的代理是否使用激进的优化策略,一般默认false,对JDK动态代理无效。
  • proxyTargetClass:若为true,则目标类本身被代理,而不是代理目标类的接口,创建 cglib代理。
  • hasNoUserSuppliedProxyInterfaces:是否存在代理接口

即:

  • 如果目标对象实现了接口,默认会采用JDK动态代理实现AOP
  • 如果目标对象实现了接口,可以强制使用CGLIB动态代理实现AOP
  • 如果目标对象没有实现接口,必须采用CGLIB代理,Spring会自动在JDK动态代理和CGLIB代理之前切换。

2.2 getProxy(classLoader)

首先我们需要知道的是,调用这个方法的是createAopProxy()方法的返回值,那么就可能是JdkDynamicAopProxy.getProxy或者ObjenesisCglibAopProxy.getProxy。下面我们来详细分析一下代理生成的过程。

三、代理对象

1. JdkDynamicAopProxy

下面代码省略了JdkDynamicAopProxy部分无关代码。

对于JDK 动态代理来说,实际调用代理方法是在java.lang.reflect.InvocationHandler#invoke中,因此 JdkDynamicAopProxy#invoke是我们的重点关注对象。
在这里插入图片描述

1.1 JdkDynamicAopProxy#getProxy

@Override
	public Object getProxy() {
		return getProxy(ClassUtils.getDefaultClassLoader());
	}

	@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
		}
		// 获取代理接口,因为是jdk代理,所以需要获取代理接口
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		// 发现 equals 和 hashCode 方法,如果发现,则改变 equalsDefined = true; 和 	hashCodeDefined = true;
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

1.2 JdkDynamicAopProxy#invoke

	@Override
	@Nullable
	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 {
			// 处理 equals 方法
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			// 处理 hashCode 方法
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			// 处理 DecoratingProxy 类
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// There is only getDecoratedClass() declared -> dispatch to proxy config.
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			// 处理 Class类的isAssignableFrom(Class cls) 方法
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;
			// 是否暴露代理对象。有时候目标对象内部的自我调用将无法实施切面中的增强,则需要通过此属性暴露
			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.
			//  获取当前方法的拦截链路,其中包括将AspectJMethodBeforeAdvice、AspectJAfterAdvice、AspectJAfterReturningAdvice 转换成合适的类型(InterceptorAndDynamicMethodMatcher)
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);


			if (chain.isEmpty()) {
				// 拦截链路为空则直接调用切点方法
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// We need to create a method invocation...
				// 否则构建一个新的 方法调用对象 ReflectiveMethodInvocation
				// 以便于使用proceed 方法进行链接表用拦截器
				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;
			}
			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);
			}
			if (setProxyContext) {
				// Restore old proxy.
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}

上面我们有两个方法需要注意:

  1. List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);。这一句将 获取当前方法的拦截链路,其中包括将AspectJMethodBeforeAdvice、AspectJAfterAdvice、AspectJAfterReturningAdvice转换成 拦截器,用于后面的调用。
    在这里插入图片描述
  2. retVal = invocation.proceed(); : 对增强方法的调用

1.2.1. this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

在中篇中我们讲了在InstantiationModelAwarePointcutAdvisorImpl中,Spring根据Aspect系列注解的不同将方法封装成了不同的Advice :AspectJAroundAdvice、AspectJMethodBeforeAdvice、AspectJAfterAdvice、AspectJAfterReturningAdvice、AspectJAfterThrowingAdvice

invocation.proceed()的分析中我们会发现最终调用的增强方法为MethodInterceptor#invoke方法(这个就是2.2.2 的部分)。但是在上述五个Advice 中,只有AspectJAroundAdviceAspectJAfterAdvice实现了MethodInterceptor接口,其余的并没有实现MethodInterceptor接口,那么这时候就需要进行一个转换,将 Advice转换成MethodInterceptor类型,该转换就是在此方法中完成。

由于this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);方法最终会调用DefaultAdvisorChainFactory#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) {
			// 我们这里的Advisor 都是 PointcutAdvisor 所以这里只分析该内容
			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;
	}

我们可以看到关键的代码就是registry.getInterceptors(advisor);,所以我们这里来看 DefaultAdvisorAdapterRegistry#getInterceptors 的实现,其目的是将所有的Advisor中的Advice 转换成MethodInterceptor

	@Override
	public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
		List<MethodInterceptor> interceptors = new ArrayList<>(3);
		Advice advice = advisor.getAdvice();
		// 如果 Advice 就是MethodInterceptor 类型,则直接保存
		if (advice instanceof MethodInterceptor) {
			interceptors.add((MethodInterceptor) advice);
		}
		// 否则寻找合适的适配器进行转换。
		// 这里的适配器有三个,分别是`AfterReturningAdviceAdapter`、`MethodBeforeAdviceAdapter`、`ThrowsAdviceAdapter`
		for (AdvisorAdapter adapter : this.adapters) {
			if (adapter.supportsAdvice(advice)) {
				interceptors.add(adapter.getInterceptor(advisor));
			}
		}
		if (interceptors.isEmpty()) {
			throw new UnknownAdviceTypeException(advisor.getAdvice());
		}
		return interceptors.toArray(new MethodInterceptor[0]);
	}

这里的适配器有三个,分别是AfterReturningAdviceAdapter、MethodBeforeAdviceAdapter、ThrowsAdviceAdapter。很明显就是为了上面的三个Advice类型准备的。经历过此步骤,所有的Advice 都转换为了MethodInterceptor

我们这里挑选其中一个ThrowsAdviceAdapter看:

class ThrowsAdviceAdapter implements AdvisorAdapter, Serializable {

	@Override
	public boolean supportsAdvice(Advice advice) {
		return (advice instanceof ThrowsAdvice);
	}

	@Override
	public MethodInterceptor getInterceptor(Advisor advisor) {
		return new ThrowsAdviceInterceptor(advisor.getAdvice());
	}

}

逻辑很简答,就是将ThrowsAdvice封装成了ThrowsAdviceInterceptor
其他两个以此类推。

1.2.2. retVal = invocation.proceed();

我们来看看ReflectiveMethodInvocation#proceed的实现,上面说过增强方法的调用实际上是在此完成的。

	public Object proceed() throws Throwable {
		// We start with an index of -1 and increment early.
		// 如果所有的增强器已经执行完了,则调用实际方法
		// interceptorsAndDynamicMethodMatchers 是在2.2.1 中解析出来的动态拦截器集合
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			// 这里调用了真正的方法  通过Method.invoke 方法
			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)) {
				// 调用 拦截器的 invoke 方法
				return dm.interceptor.invoke(this);
			}
			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.
			// 普通的拦截器,直接调用拦截器。我们一般都走这里
			// 将this 作为参数传递以保证当前实力中的调用链路的执行
			// 直接调用 Advice 的 invoke 方法
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

ReflectiveMethodInvocation#process方法中的逻辑并不复杂。ReflectiveMethodInvocation中的主要职责是维护了链接调用的计数器,记录着当前调用链接的位置,以便链可以有序的进行下去,在这个方法中并没有维护各种增强的顺序,而是将此工作委托给了各个增强器,使各个增强器在内部进行逻辑实现。

1.3 总结

JdkDynamicAopProxy#invoke方法中:

  1. 首先处理equalshashcode 等方法。
  2. 随后调用 this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 方法将获取到拦截器。
  • 因为Jdk动态代理在调用增强方法时,是通过 MethodInterceptor#invoke 方法来调用,但对于AspectJAroundAdvice、AspectJMethodBeforeAdvice、AspectJAfterAdvice、AspectJAfterReturningAdvice、AspectJAfterThrowingAdvice来说,只有AspectJAroundAdviceAspectJAfterAdvice实现了MethodInterceptor接口,其余的并没有实现MethodInterceptor接口。所以在 registry.getInterceptors(advisor) 中,将Advisor中的Advice都封装成MethodInterceptor,以便后面方法增强调用。

  • 随后MethodInterceptor封装成InterceptorAndDynamicMethodMatcher,其实就是一个简单的封装,以便后面处理。
    关于InterceptorAndDynamicMethodMatcher的实现如下 ,可以看到其逻辑很简单:

class InterceptorAndDynamicMethodMatcher {
	// MethodInterceptor  方法拦截器,这里保存了针对于该方法的增强实现
	final MethodInterceptor interceptor;
	// 方法匹配器,用来匹配当前拦截器是否适用于当前方法
	final MethodMatcher methodMatcher;

	public InterceptorAndDynamicMethodMatcher(MethodInterceptor interceptor, MethodMatcher methodMatcher) {
		this.interceptor = interceptor;
		this.methodMatcher = methodMatcher;
	}

}
  • 至此,@Aspect 系列注解修饰的方法从Advisor转换成了InterceptorAndDynamicMethodMatcher
  1. 在调用invocation.proceed();方法时,针对InterceptorAndDynamicMethodMatcher类型,会通过InterceptorAndDynamicMethodMatcher#methodMatcher判断是否适用于当前方法,如果适用则调用InterceptorAndDynamicMethodMatcher#interceptorinvoke方法来执行增强方法。

2. ObjenesisCglibAopProxy

2.1 ObjenesisCglibAopProxy#getProxy

	@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
		try {
			Class<?> rootClass = this.advised.getTargetClass();
			Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

			Class<?> proxySuperClass = rootClass;
			// 如果当前类名中包含 “$$” 则被认定为是 cglib 类。
			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.
			// 创建代理对象
			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);
		}
	}

....
	// 上面可以很明显知道,CallBack是代理增强的关键实现。
	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).
		// 创建 Aop 拦截器
		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());
		// 回调集合。其中包含aopInterceptor 中包含了 Aspect 的增强
		//  advisedDispatcher 用于判断如果method是Advised.class声明的,则使用AdvisedDispatcher进行分发
		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 = new HashMap<>(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);
				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 = 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;
	}

以上:内容部分参考
《Spring实战》
《Spring源码深度解析》
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正

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

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

相关文章

Spring Cloud实现Zuul自带的Debug功能

Zuul 中自带了一个 DebugFilter&#xff0c;一开始笔者也没明白这个 DebugFilter 有什么用&#xff0c;看名称很容易理解&#xff0c;它是用来调试的&#xff0c;可是你看它的源码几乎没什么逻辑&#xff0c;就 set 了两个值而已&#xff0c;代码如下所示。 Overridepublic Obj…

流媒体协议分析之webrtc之rtcp

TCP作为RTP控制协议&#xff0c;对于弱网下音视频质量和会话控制具有重要的作用。 1. RTCP Header V&#xff1a;RTCP的版本号&#xff0c;一定等于2&#xff1b; P&#xff1a;如果设置&#xff0c;填充位表示数据包包含末尾的附加填充八位字节&#xff0c;不属于控制信息&am…

CV-对比学习:概述【通过自监督学习,充分挖掘模型从海量无标注数据中学习通用知识的能力】

对比学习从目标来看&#xff0c;是要做在NLP类型类似Bert预训练的事&#xff0c;即通过自监督学习&#xff0c;充分挖掘模型从海量无标注数据中学习通用知识的能力。 大致分类 对比学习目前可大致可分为 基于负例的对比学习方法基于对比聚类的方法基于不对称网络结构的方法基…

PLC SECS/GEM解决方案,设计与应用

1 适用性 金南瓜SECS是最适应于全自动智能设备的选择。 适用行业&#xff1a;半导体、光伏、PCB等 全面支持E5、E30、E37、E40、E87、E90、E94、E116 PLC SECS/GEM具有怪兽级的强劲性能&#xff0c;处理性能高达10ms/条&#xff0c;全面升级的高适应性&#xff0c;易用友好的S…

30.前端笔记-CSS-CSS3的新特性

1、CSS3新增选择器 属性选择器&#xff0c;权重为10结构伪类选择器&#xff0c;权重为10伪元素选择器&#xff0c;权重为10 1.1 属性选择器 用属性选择器可以不用借助类或id选择器 语法&#xff1a; 正则表达式&#xff1a;^表示开头&#xff0c;$表示结尾,*表示任意 /*标…

怎么提高客服人员效率?

为了给客户提供更好的服务&#xff0c;很多企业会为自己网站配置客服服务&#xff0c;方便随时和客户沟通。但是凡事有利便有弊。虽然和客户接触的机会变多了&#xff0c;但是沟通不及时、回答不专业、问题处理时间长等问题也可能随之出现&#xff0c;反而会给客户带来不好的印…

[附源码]Python计算机毕业设计Django的个人理财系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

OpenCV-Python小应用(七):获取图片ROI的HSV取值范围

OpenCV-Python小应用&#xff08;七&#xff09;&#xff1a;获取图片ROI的HSV取值范围前言前提条件实验环境获取图片ROI的HSV取值范围参考文献前言 本文是个人使用OpenCV-Python的应用案例&#xff0c;由于水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评改正。更多精彩…

基于无人机的移动边缘计算网络研究(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

socket网络字节序以及大端序小端序

不同CPU中&#xff0c;4字节整数1在内存空间的存储方式是不同的。4字节整数1可用2进制表示如下&#xff1a; 00000000 00000000 00000000 00000001 有些CPU以上面的顺序存储到内存&#xff0c;另外一些CPU则以倒序存储&#xff0c;如下所示&#xff1a; 00000001 00000000 0…

【Spring】SpringBoot 配置 logback 日志

1. 概述 日志在一个业务系统重非常重要&#xff0c;包含有非常重要的数据&#xff0c;可以用于客户反馈问题的排查、线上问题的追踪&#xff0c;以及根据日志数据对业务情况进行有效的监控配置&#xff0c;及时发现线上问题。 常用的日志框架有好几种&#xff0c;但最常用的是…

[附源码]Node.js计算机毕业设计大学校园兼职网站Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

【观察】定义下一代云原生实时数仓,SelectDB Cloud“打了个样”

2020年&#xff0c;国家在《关于构建更加完善的要素市场化配置体制机制的意见》中&#xff0c;首次将数据与土地、资本、劳动力并列为关键生产要素&#xff0c;并提出加快培育数据要素市场的愿景&#xff0c;此举可谓意义重大。背后的原因是&#xff0c;当下中国企业正在加速从…

【车载开发系列】UDS诊断---写入内存($0x3D)

【车载开发系列】UDS诊断—写入内存&#xff08;$0x3D&#xff09; UDS诊断---写入内存&#xff08;$0x3D&#xff09;【车载开发系列】UDS诊断---写入内存&#xff08;$0x3D&#xff09;一.概念定义二.报文格式1&#xff09;请求报文2&#xff09;肯定响应3&#xff09;否定响…

Redis实战——消息队列

目录 1. 什么是消息队列&#xff1f; 2. 基于List结构模拟消息队列 3. 基于PubSub的消息队列 4. 基于Stream的消息队列 4.1 基于Stream的单消费者模式 4.2 基于Stream的消息队列-消费者组 1. 什么是消息队列&#xff1f; 字面意思就是存放消息的队列。最简单的消息队列模…

学习参数化计算优化风扇定位step by step

一、写在前面 本教程的目的是演示ANSYS Icepak的参数和优化功能。假定读者已经熟悉ANSYS Icepak界面&#xff0c;但是缺乏实战经验。 在这个案例中&#xff0c;读者可以掌握&#xff1a; 1、使用Network网络热阻Block来模拟IC芯片封装模型。 2、将变量定义为参数并通过参数…

算法竞赛入门【码蹄集进阶塔335题】(MT2226-2250)

算法竞赛入门【码蹄集进阶塔335题】(MT2226-2250&#xff09; 文章目录算法竞赛入门【码蹄集进阶塔335题】(MT2226-2250&#xff09;前言为什么突然想学算法了&#xff1f;为什么选择码蹄集作为刷题软件&#xff1f;目录1. MT2226 36进制22. MT2227 36进制33. MT2228 36进制44.…

电商、线上教育、在线医疗等必备资质——ICP许可证 。

危中有机&#xff0c;疫情也概莫能外。一场突如其来的疫情&#xff0c;引发了消费、健康、办公、学习等领域的新变革&#xff0c;电商、短视频、游戏、线上教育、在线医疗、知识付费等“互联网”项目&#xff0c;再次迎来发展机遇。 然而&#xff0c;如果想要借助互联网进行经…

[附源码]Python计算机毕业设计大学生网上书店Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

type 与 interface

type 与 interface 官方文档是这么说的&#xff1a; For the most part, you can choose based on personal preference, and TypeScript will tell you if it needs something to be the other kind of declaration. If you would like a heuristic, use interface until you…