Spring源码解析(27)之AOP的核心对象创建过程2

news2024/11/25 5:50:46

一、前言

        我们在上一节中已经介绍了Advisor的创建过程,当时我们创建的logUtil这bean,他在

resolveBeforeInstantiation返回的是null,那么就会继续往下执行doCreateBean方法。

二、源码分析

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		// 这个beanWrapper是用来持有创建出来的bean对象的
		BeanWrapper instanceWrapper = null;
		// 获取factoryBean实例缓存
		if (mbd.isSingleton()) {
			// 如果是单例对象,从factorybean实例缓存中移除当前bean定义信息
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		// 没有就创建实例
		if (instanceWrapper == null) {
			// 根据执行bean使用对应的策略创建新的实例,如,工厂方法,构造函数主动注入、简单初始化
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		// 从包装类中获取原始bean
		Object bean = instanceWrapper.getWrappedInstance();
		// 获取具体的bean对象的Class属性
		Class<?> beanType = instanceWrapper.getWrappedClass();
		// 如果不等于NullBean类型,那么修改目标类型
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		// 允许beanPostProcessor去修改合并的beanDefinition
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					// MergedBeanDefinitionPostProcessor后置处理器修改合并bean的定义
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		// 判断当前bean是否需要提前曝光:单例&允许循环依赖&当前bean正在创建中,检测循环依赖
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			// 为避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

//			//只保留二级缓存,不向三级缓存中存放对象
//			earlySingletonObjects.put(beanName,bean);
//			registeredSingletons.add(beanName);
//
//			synchronized (this.singletonObjects) {
//				if (!this.singletonObjects.containsKey(beanName)) {
//					//实例化后的对象先添加到三级缓存中,三级缓存对应beanName的是一个lambda表达式(能够触发创建代理对象的机制)
//					this.singletonFactories.put(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
//					this.registeredSingletons.add(beanName);
//				}
//			}

		}

		// Initialize the bean instance.
		// 初始化bean实例
		Object exposedObject = bean;
		try {
			// 对bean的属性进行填充,将各个属性值注入,其中,可能存在依赖于其他bean的属性,则会递归初始化依赖的bean
			populateBean(beanName, mbd, instanceWrapper);
			// 执行初始化逻辑
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		if (earlySingletonExposure) {
			// 从缓存中获取具体的对象
			Object earlySingletonReference = getSingleton(beanName, false);
			// earlySingletonReference只有在检测到有循环依赖的情况下才会不为空
			if (earlySingletonReference != null) {
				// 如果exposedObject没有在初始化方法中被改变,也就是没有被增强
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						// 返回false说明依赖还没实例化好
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					// 因为bean创建后所依赖的bean一定是已经创建的
					// actualDependentBeans不为空则表示当前bean创建后其依赖的bean却没有全部创建完,也就是说存在循环依赖
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			// 注册bean对象,方便后续在容器销毁的时候销毁对象
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

        然后就会进入到 initializeBean,进行bean的初始化,我们之前都知道在这个initializeBean会会执行BPP的after方法,然后我们之前解析AOP配置文件的时候注入的AutoProxyCreator他是一个BeanPostProcessor,这里会执行它的after方法来判断是否需要创建代理对象,我们继续往下跟。

/**
	 * 初始化给定的bean实例,应用工厂回调以及init方法和BeanPostProcessors
	 *
	 * Initialize the given bean instance, applying factory callbacks
	 * as well as init methods and bean post processors.
	 * <p>Called from {@link #createBean} for traditionally defined beans,
	 * and from {@link #initializeBean} for existing bean instances.
	 * @param beanName the bean name in the factory (for debugging purposes)
	 * @param bean the new bean instance we may need to initialize
	 * @param mbd the bean definition that the bean was created with
	 * (can also be {@code null}, if given an existing bean instance)
	 * @return the initialized bean instance (potentially wrapped)
	 * @see BeanNameAware
	 * @see BeanClassLoaderAware
	 * @see BeanFactoryAware
	 * @see #applyBeanPostProcessorsBeforeInitialization
	 * @see #invokeInitMethods
	 * @see #applyBeanPostProcessorsAfterInitialization
	 */
	protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
		// 如果安全管理器不为空
		if (System.getSecurityManager() != null) {
			// 以特权的方式执行回调bean中的Aware接口方法
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			// Aware接口处理器,调用BeanNameAware、BeanClassLoaderAware、beanFactoryAware
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		//如果mdb不为null || mbd不是"synthetic"。一般是指只有AOP相关的prointCut配置或者Advice配置才会将 synthetic设置为true
		if (mbd == null || !mbd.isSynthetic()) {
			// 将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessBeforeInitialization初始化方法。
			// 返回的Bean实例可能是原始Bean包装器
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			//调用初始化方法,先调用bean的InitializingBean接口方法,后调用bean的自定义初始化方法
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			//捕捉调用初始化方法时抛出的异常,重新抛出Bean创建异常:调用初始化方法失败
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		//如果mbd为null || mbd不是"synthetic"
		if (mbd == null || !mbd.isSynthetic()) {
			// 将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessAfterInitialization方法。
			// 返回的Bean实例可能是原始Bean包装器
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		//返回包装后的Bean
		return wrappedBean;
	}

 

        我们继续往里面跟AutoProxyCretor的after方法,看里面具体的执行逻辑。

	@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		//初始化结果对象为result,默认引用existingBean
		Object result = existingBean;
		//遍历该工厂创建的bean的BeanPostProcessors列表
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			//回调BeanPostProcessor#postProcessAfterInitialization来对现有的bean实例进行包装
			Object current = processor.postProcessAfterInitialization(result, beanName);
			//一般processor对不感兴趣的bean会回调直接返回result,使其能继续回调后续的BeanPostProcessor;
			// 但有些processor会返回null来中断其后续的BeanPostProcessor
			// 如果current为null
			if (current == null) {
				//直接返回result,中断其后续的BeanPostProcessor处理
				return result;
			}
			//让result引用processor的返回结果,使其经过所有BeanPostProcess对象的后置处理的层层包装
			result = current;
		}
		//返回经过所有BeanPostProcess对象的后置处理的层层包装后的result
		return result;
	}

  

        AbstractAutoProxyCreator的postProcessAfterInitialization方法。他里面会调用具体的wrapIfNecessary来判断是否要创建代理对象。
	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			// 获取当前bean的key:如果beanName不为空,则以beanName为key,如果为FactoryBean类型,
			// 前面还会添加&符号,如果beanName为空,则以当前bean对应的class为key
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			// 判断当前bean是否正在被代理,如果正在被代理则不进行封装
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				// 如果它需要被代理,则需要封装指定的bean
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

        这里的前面判断逻辑是跟之前是一样,首先会在缓存里面判断当前bean是否已经被处理过,很明显我们当前的logUtil之前已经被解析过并且放入到了缓存中,因为我们的logUtil他是一个切面逻辑他不需要被创建代理对象。

        

        其次会判断当前的bean是否是基础bean,如果是则不用创建带来对象,如果不是则会去盗用shouldSkip方法来判断当前的bean是否需要被跳过,而在这这个shouldSkip方法中我们知道,会寻找容器中的advisor对象。

/**
	 * 先判断是否已经处理过,是否需要跳过,跳过的话直接就放进advisedBeans里,表示不进行代理,如果这个bean处理过了,获取通知拦截器,然后开始进行代理
	 *
	 * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
	 * @param bean the raw bean instance
	 * @param beanName the name of the bean
	 * @param cacheKey the cache key for metadata access
	 * @return a proxy wrapping the bean, or the raw bean instance as-is
	 */
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		// 如果已经处理过,直接返回
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		// 这里advisedBeans缓存了已经进行了代理的bean,如果缓存中存在,则可以直接返回
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		// 这里isInfrastructureClass()用于判断当前bean是否为Spring系统自带的bean,自带的bean是
		// 不用进行代理的;shouldSkip()则用于判断当前bean是否应该被略过
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			// 对当前bean进行缓存
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		// 获取当前bean的Advices和Advisors
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		// 对当前bean的代理状态进行缓存
		if (specificInterceptors != DO_NOT_PROXY) {
			// 对当前bean的代理状态进行缓存
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			// 根据获取到的Advices和Advisors为当前bean生成代理对象
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			// 缓存生成的代理bean的类型,并且返回生成的代理bean
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

        然后我们跳过logUtil,看一下真正需要被创建代理对象的 myCalculator。

        他会进入到 getAdvicesAndAdvisorsForBean方法中,这个方法就是给当前的bean寻找适配的advisor对象,我们知道advisor对象中包含advice对象,advice对象中包含MethodLocadingFactory还有AspectJExpressionPointcut和SimpleBeanFactoryAwareAspectInstanceFactory对象。

        思考一个问题,我们根据什么条件给bean对象创建代理对象,肯定是根据我们配置express表达式来判断哪些包那些类那些对象需要创建代理对象,而Spring的匹配规则主要是通过ClassFilter和MethodMatcher对象来实现的,之前我们只知道advice对象需要一个AspectJExpressionPointCut对象,我们来看下这个类的继承关系图。

@FunctionalInterface
public interface ClassFilter {

	/**
	 * 是否应该将pointcut应用到给定的接口或者类上
	 *
	 * Should the pointcut apply to the given interface or target class?
	 * @param clazz the candidate target class
	 * @return whether the advice should apply to the given target class
	 */
	boolean matches(Class<?> clazz);


	/**
	 * ClassFilter的规范实例能够匹配所有的类
	 *
	 * Canonical instance of a ClassFilter that matches all classes.
	 */
	ClassFilter TRUE = TrueClassFilter.INSTANCE;

}
/**
 * 一个特殊类型的MethodMatcher接口,当匹配方法的时候需要将说明考虑进去
 *
 * A specialized type of {@link MethodMatcher} that takes into account introductions
 * when matching methods. If there are no introductions on the target class,
 * a method matcher may be able to optimize matching more effectively for example.
 *
 * @author Adrian Colyer
 * @since 2.0
 */
public interface IntroductionAwareMethodMatcher extends MethodMatcher {

	/**
	 * Perform static checking whether the given method matches. This may be invoked
	 * instead of the 2-arg {@link #matches(java.lang.reflect.Method, Class)} method
	 * if the caller supports the extended IntroductionAwareMethodMatcher interface.
	 * @param method the candidate method
	 * @param targetClass the target class
	 * @param hasIntroductions {@code true} if the object on whose behalf we are
	 * asking is the subject on one or more introductions; {@code false} otherwise
	 * @return whether or not this method matches statically
	 */
	boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions);

}

        有了以上知识,我们继续往下跟getAdvicesAndAdvisorsForBean方法。

	/**
	 * 检查前面切面解析是否有通知器advisors创建,有就返回,没有就是null
	 * @param beanClass the class of the bean to advise
	 * @param beanName the name of the bean
	 * @param targetSource
	 * @return
	 */
	@Override
	@Nullable
	protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

		// 找合适的增强器对象
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		// 若为空表示没找到
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}

        里面是通过findEligibleAdvisors查找合适的advisor对象。

	/**
	 * 找到所有符合条件的通知对于自动代理的类
	 *
	 * Find all eligible Advisors for auto-proxying this class.
	 * @param beanClass the clazz to find advisors for
	 * @param beanName the name of the currently proxied bean
	 * @return the empty List, not {@code null},
	 * if there are no pointcuts or interceptors
	 * @see #findCandidateAdvisors
	 * @see #sortAdvisors
	 * @see #extendAdvisors
	 */
	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		// 将当前系统中所有的切面类的切面逻辑进行封装,从而得到目标Advisor
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		// 对获取到的所有Advisor进行判断,看其切面定义是否可以应用到当前bean,从而得到最终需要应用的Advisor
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		// 提供的hook方法,用于对目标Advisor进行扩展
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			// 对需要代理的Advisor按照一定的规则进行排序
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

        findCandidateAdvisors我们在之前就比较熟悉了,他是寻找容器中所有的advisor对象,他在之前第一次调用的时候就会初始化所有的advisor对象,并且把他放入到缓存中去。

        获取得到所有的advisor对象之后就会通过findAdvisorsThatCanApply查找可以应用在当前类的advisor对象,如果找不到适配的advisor对象说明当前对象不需要被代理,直接返回空,表示不需要被代理,我们继续往下看他的匹配过程。   

	/**
	 * 检测实例化之后的bean是否需要通知器,其实就是检测方法或者类上是否需要事务注解
	 *
	 * Search the given candidate Advisors to find all Advisors that
	 * can apply to the specified bean.
	 * @param candidateAdvisors the candidate Advisors
	 * @param beanClass the target's bean class
	 * @param beanName the target's bean name
	 * @return the List of applicable Advisors
	 * @see ProxyCreationContext#getCurrentProxiedBeanName()
	 */
	protected List<Advisor> findAdvisorsThatCanApply(
			List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			// 从候选的通知器中找到合适正在创建的实例对象的通知器
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}

        继续往下跟findAdvisorsThatCanApply方法。

	/**
	 * 遍历每一个advisor,然后判断是否可以应用到目标类clazz上,可以的话就加入候选列表
	 *
	 * Determine the sublist of the {@code candidateAdvisors} list
	 * that is applicable to the given class.
	 * @param candidateAdvisors the Advisors to evaluate
	 * @param clazz the target class
	 * @return sublist of Advisors that can apply to an object of the given class
	 * (may be the incoming List as-is)
	 */
	public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		// 若候选的增强器集合为空 直接返回
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		// 定义一个合适的增强器集合对象
		List<Advisor> eligibleAdvisors = new ArrayList<>();
		// 循环我们候选的增强器对象,IntroductionAdvisor与PointcutAdvisor本质区别,一个是可以作用在类上,一个是可以作用的方法上
		for (Advisor candidate : candidateAdvisors) {
			// 判断我们的增强器对象是不是实现了IntroductionAdvisor (很明显我们事务的没有实现 所以不会走下面的逻辑)
			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
				eligibleAdvisors.add(candidate);
			}
		}
		// 是否有引介增强
		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
		for (Advisor candidate : candidateAdvisors) {
			// 判断我们的增强器对象是不是实现了IntroductionAdvisor
			if (candidate instanceof IntroductionAdvisor) {
				// already processed
				// 在上面已经处理过,不需要处理
				continue;
			}

			// 真正的判断增强器是否合适当前类型
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}

        第一个循环我们所有获取得到的advisor对象,判断当前的advisor对象是否是引介增强,之前我们都知道,我们AOP创建的advisor都是AspectJPointcutAdvisor对象,所以我们跳过,直接看canApply方法。

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
		// 如果是IntroductionAdvisor的话,则调用IntroductionAdvisor类型的实例进行类的过滤
		// 这里是直接调用的ClassFilter的matches方法
		if (advisor instanceof IntroductionAdvisor) {
			return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
		}
		// 通常我们的Advisor都是PointcutAdvisor类型
		else if (advisor instanceof PointcutAdvisor) {
			// 转为PointcutAdvisor类型
			PointcutAdvisor pca = (PointcutAdvisor) advisor;
			//这里从Advisor中获取Pointcut的实现类 这里是AspectJExpressionPointcut
 			return canApply(pca.getPointcut(), targetClass, hasIntroductions);
		}
		else {
			// It doesn't have a pointcut so we assume it applies.
			return true;
		}
	}

        这里开始也是有一个advisor对象的类型判断,我们继续往下跟他具体实现的canApply方法。

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");
		// 进行切点表达式的匹配最重要的就是ClassFilter和MethodMatcher这两个方法的实现。
		// MethodMatcher中有两个matches方法。一个参数是只有Method对象和targetClass,另一个参数有
		// Method对象和targetClass对象还有一个Method的方法参数,他们两个的区别是:
		// 两个参数的matches是用于静态的方法匹配 三个参数的matches是在运行期动态的进行方法匹配的
		// 先进行ClassFilter的matches方法校验
		// 首先这个类要在所匹配的规则下
		if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}

		// 再进行MethodMatcher方法级别的校验
		MethodMatcher methodMatcher = pc.getMethodMatcher();
		if (methodMatcher == MethodMatcher.TRUE) {
			// No need to iterate the methods if we're matching any method anyway...
			return true;
		}

		// 判断匹配器是不是IntroductionAwareMethodMatcher
		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
		}

		// 创建一个集合用于保存targetClass的class对象
		Set<Class<?>> classes = new LinkedHashSet<>();
		// 判断当前class是不是代理的class对象
		if (!Proxy.isProxyClass(targetClass)) {
			// 加入到集合中去
			classes.add(ClassUtils.getUserClass(targetClass));
		}
		// 获取到targetClass所实现的接口的class对象,然后加入到集合中
		classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

		// 循环所有的class对象
		for (Class<?> clazz : classes) {
			// 通过class获取到所有的方法
			Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
			// 循环我们的方法
			for (Method method : methods) {
				// 只要有一个方法能匹配到就返回true
				// 这里就会有一个问题:因为在一个目标中可能会有多个方法存在,有的方法是满足这个切点的匹配规则的
				// 但是也可能有一些方法是不匹配切点规则的,这里检测的是只有一个Method满足切点规则就返回true了
				// 所以在运行时进行方法拦截的时候还会有一次运行时的方法切点规则匹配
				if (introductionAwareMethodMatcher != null ?
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
						// 通过方法匹配器进行匹配
						methodMatcher.matches(method, targetClass)) {
					return true;
				}
			}
		}

		return false;
	}

        这里就比较有意思了,首先获取对应的classFilter进行类级别的匹配,然后会在循环方法进行方法级别的匹配。

 

        这里看得到匹配到一个方法就返回true,因为这里只是单纯的判断当前类是否需要创建代理对对象,在后续的创建代理对象的时候会再具体进行匹配,所以这里匹配到一个就直接返回true。

        进过以上一系列判断,我们就可以获取得到当前bean适配的所有的advisor对象。

       

         获取得到对应的所有的advisor对象的时候,对调用一个对这些advisor进行拓extendAdvisors,我们继续往下跟。

	@Override
	protected void extendAdvisors(List<Advisor> candidateAdvisors) {
		AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
	}

	public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
		// Don't add advisors to an empty list; may indicate that proxying is just not required
		if (!advisors.isEmpty()) {
			boolean foundAspectJAdvice = false;
			for (Advisor advisor : advisors) {
				// Be careful not to get the Advice without a guard, as this might eagerly
				// instantiate a non-singleton AspectJ aspect...
				if (isAspectJAdvice(advisor)) {
					foundAspectJAdvice = true;
					break;
				}
			}
			if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
				advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
				return true;
			}
		}
		return false;
	}

        可以看得到他只是给我们的advisor集合中添加了ExposeInvocationInterceptor,这个类的作用是啥呢?在解决这个问题之前,首先问一下大家,我们生成的这个advisor对象在执行切面逻辑的时候是不是会有执行顺序,答案是肯定会有的,那我们如果控制这些advisor的执行顺序呢?

        我们看下ExposeInvocationIntercetor里面有啥。

        其实他就是通过这个ExposeInvocationInterceptor里面维护的一个ThreadLocal来控制当前的执行的advisor对象 。

	public static final Advisor ADVISOR = new DefaultPointcutAdvisor(INSTANCE) {
		@Override
		public String toString() {
			return ExposeInvocationInterceptor.class.getName() +".ADVISOR";
		}
	};

	private static final ThreadLocal<MethodInvocation> invocation =
			new NamedThreadLocal<>("Current AOP method invocation");


	/**
	 * 此处是继续调用ReflectiveMethodInvocation的proceed方法来进行递归调用
	 *
	 * Return the AOP Alliance MethodInvocation object associated with the current invocation.
	 * @return the invocation object associated with the current invocation
	 * @throws IllegalStateException if there is no AOP invocation in progress,
	 * or if the ExposeInvocationInterceptor was not added to this interceptor chain
	 */
	public static MethodInvocation currentInvocation() throws IllegalStateException {
		MethodInvocation mi = invocation.get();
		if (mi == null) {
			throw new IllegalStateException(
					"No MethodInvocation found: Check that an AOP invocation is in progress and that the " +
					"ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that " +
					"advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor! " +
					"In addition, ExposeInvocationInterceptor and ExposeInvocationInterceptor.currentInvocation() " +
					"must be invoked from the same thread.");
		}
		return mi;
	}

        既然我们的advisor有执行顺序,所以spring接下来就是对获取得到的advisor对象进行排序。

	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		// 将当前系统中所有的切面类的切面逻辑进行封装,从而得到目标Advisor
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		// 对获取到的所有Advisor进行判断,看其切面定义是否可以应用到当前bean,从而得到最终需要应用的Advisor
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		// 提供的hook方法,用于对目标Advisor进行扩展
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			// 对需要代理的Advisor按照一定的规则进行排序
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

        这里的排序就比较麻烦了,他使用到的是一个拓扑有限无环排序,有兴趣的伙伴可以去研究一下这个算法。

        最后就会返回排好序的advisor对象,接下来就是真正创建代理对象。在看创建代理对象的之前,如果对cglib跟jdk动态代理源码不是很熟悉的先去看一下之前的博客Spring源码解析(24)之JDK动态代理与cglib动态代理源码解析_spring 选择 jdk 代理 cglib 代理源码-CSDN博客 

        接下来会先画一个图总结一下,这三篇博客的脉络,然后再往下看他是如何创建代理对象的。 

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

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

相关文章

永结无间Ⅸ--你不需要LLM Agent

人们将目光锁定在下一个闪亮的事物上。FOMO 是人性的一部分。这也适用于企业。就像数据科学成为每个企业分析功能的热潮一样&#xff0c;Agentic Architecture 是大多数 AI 雷达上的热门目标。 但您是否考虑过您是否真的需要它&#xff1f; 实际情况是&#xff0c;您不需要 A…

解答|一年期HTTPS证书如何获取?

自2023年年底以来&#xff0c;各大平台陆续下架了一年期免费HTTPS证书&#xff0c;目前市面上已经不再提供一年期的免费证书。付费正式版证书成为首选&#xff01;而DV证书由于其低廉的价格广受个人或者中小企业的青睐。 下面是DV类型证书&#xff08;13个月时长&#xff09;的…

防火墙Firewalld(iptables)

目录 一、Linux防火墙基础 1.什么是防火墙 2.防火墙的功能 3.防火墙的类型 二、Linux防火墙工具 1.iptables 2. netfilter 3.四表五链结构 3.1四表 3.2五链 3.3总结 4.数据包过滤的匹配流程 4.1规则表之间的顺序 4.2规则链之间的顺序 4.3规则链内的匹配顺序 …

人数管控系统助力图书馆实现精准客流统计分析

一、客流统计痛点在图书馆的日常运营中&#xff0c;客流统计面临着诸多难题。传统的人工计数方法不仅耗费人力&#xff0c;而且数据准确性难以保证。无法精确掌握不同时间段的读者流量&#xff0c;导致图书馆在资源配置和服务安排上缺乏科学依据。难以了解各个区域的受欢迎程度…

查看RAM和Flash

0 Preface/Foreword 1 查看方法 1.1 map文件中查看 1.1.1 RAM可用情况 在map文件中&#xff0c;搜索字符串&#xff1a;free_ramcp 该字段表示剩余可用的RAM大小&#xff0c;前面对应的是hexadecimal的数值&#xff08;单位Byte&#xff09;&#xff0c;就是剩余可用的RA…

浅谈ArkTS/ArkUI组件开发

浅谈ArkTS/ArkUI组件开发 本篇文章将从一个移动开发思维的维度出发&#xff0c;浅谈ArkTS组件开发的基础问题&#xff0c;比如状态管理、装饰器、属性传递、自定义构建函数、插槽、条件渲染&#xff0c;模块引用和路由跳转等。 创建项目 这里使用截图简单过一下&#xff0c;不…

数据结构与算法 - 递归

一、递归 1. 概述 定义&#xff1a;在计算机科学中&#xff0c;递归是一种解决计算问题的方法&#xff0c;其中解决方案取决于同一类问题的更小子集。 比如单链表递归遍历的例子&#xff1a; void f(Node node) {if(node null) {return;}println("before:" node…

Java 字符串常量池

目录 一、池化概念 二、字符串常量池 1. 概述 2. String对象的创建过程 1&#xff09;直接使用字符串常量进行赋值 2&#xff09;通过new创建String类对象 3&#xff09;结论 4&#xff09;intern方法 一、池化概念 先看如下的一段代码&#xff1a; String s1 "…

LLM实战系列(1)—强强联合Langchain-Vicuna应用实战

背景 本文主要介绍一下&#xff0c;基于Langchain与Vicuna-13B的外挂OceanBase知识库项目实战以及QA使用&#xff0c;项目地址: github.com/csunny/DB-G… 在开始之前&#xff0c;我们还是先看看效果&#xff5e; 自Meta发布LLaMA大模型以来&#xff0c; 围绕LLaMA微调的模型…

为什么越来越多的IT青年转行网络安全?

目前&#xff0c;我国互联网已经从爆发增长期进入平稳发展阶段&#xff0c;同时每年大量计算机相关专业的毕业生涌入就业市场&#xff0c;导致IT行业逐渐趋于饱和状态&#xff0c;甚至出现裁员现象&#xff0c;去年很多大厂都有裁员&#xff0c;不少程序员再就业成了难题。 面…

大彩触摸屏与单片机通讯

目录&#xff1a; 一、概述 1、触摸屏简介 2、安装软件 1&#xff09;设置VSPD软件 2&#xff09;设置VisualTFT软件 3&#xff09;设置串口软件 二、单片机发送指令给触摸屏 1、发送文本 2、显示与隐藏控件 1&#xff09;通过指令助手生成指令 2&#xff09;隐藏…

IDEA启动springBoot项目,显示构建和正在启动XxxApplication之后无反应

今天拉其他项目组的代码&#xff0c;然后发现IDEA启动不了项目&#xff0c;点击启动一闪而过&#xff0c;啥提示也没有&#xff0c;因为之前有过类似IDEA出错的经验&#xff0c;所以知道怎么排查。 首先打开IDEA日志输出&#xff0c;然后看具体是什么错 帮助>Tail Log in Co…

Linux用户无法访问Github怎么办?

进入Steam官网:Watt Toolkit 1.点击下载 2.在点击授权并下载 3.尽量选择Nas分流&#xff08;德国&#xff09; 4.然后选择最新版本 5.点击Linux版本它会自动文件夹 6.双击,他会自动下载 7.下载完成后进行解压,解压后进入目录 8.右键在此打开终端,在终端输入,运行此脚本 …

揭秘!焦虑症不只是心理战,这些躯体化症状你中招了吗?

引言 在这个快节奏、高压力的时代&#xff0c;焦虑症已成为许多人难以言说的秘密。它不仅悄无声息地侵蚀着我们的心理健康&#xff0c;还可能以一系列令人意想不到的躯体化症状显现&#xff0c;让人误以为自己只是“身体出了点小毛病”。今天&#xff0c;就让我们一起揭开焦虑…

[工具推荐]前端加解密之Burp插件Galaxy

如果觉得该文章有帮助的&#xff0c;麻烦师傅们可以搜索下微信公众号&#xff1a;良月安全。点个关注&#xff0c;感谢师傅们的支持。 免责声明 本号所发布的所有内容&#xff0c;包括但不限于信息、工具、项目以及文章&#xff0c;均旨在提供学习与研究之用。所有工具安全性…

肖扬率团队到北京军区干休所与离退休老干部座谈

在中国人民解放军建军97周年到来之际&#xff0c;为弘扬拥军优属光荣传统&#xff0c;营造尊崇关爱军人的浓厚氛围&#xff0c;世界中医药联合会骨伤科专业委员会副会长肖扬教授率团队遵从上级部门安排于7月31日上午到北京军区干休所看望离退休的老干部和多位老将军的后代&…

【DRF性能优化】

一、背景 项目中有一个查询脚本的接口&#xff0c;查询20条数据需要5min&#xff0c;性能很差,需要优化 二、问题排查 查看代码发现&#xff0c;serializers中&#xff0c;发现了一个奇怪的查询 查询脚本时&#xff0c;关联的脚本版本的一些字段也需要查询出来&#xff0c;…

安卓单机游戏:世界盒子手机游戏,最新版,春秋MOD整合 下载

《世界盒子》&#xff08;WorldBox&#xff09;是一款由Maxim Karpenko制作的沙盒模拟类游戏。这款游戏允许玩家在游戏中扮演上帝的角色&#xff0c;使用神力来创造和改变像素世界。玩家可以利用水、沙子、土壤、森林、人类、种子、动物等元素&#xff0c;以及温度、降雨等环境…

【数据结构】了解哈希表,解决哈希冲突,用Java模拟实现哈希桶

哈希表的概念 哈希表&#xff08;Hash Table&#xff09;是一种高效的数据结构&#xff0c;用于实现快速的数据存储和检索。它通过将数据映射到一个数组的索引位置&#xff0c;从而能够在平均情况下实现O(1)的时间复杂度进行查找、插入和删除操作。 哈希表的基本概念包括以下…

LLM应用-prompt提示:让大模型总结生成PPT

参考&#xff1a; https://mp.weixin.qq.com/s/frKOjf4hb6yec8LzSmvQ7A 思路&#xff1a;通过大模型生成markdown内容&#xff0c;通过markdown去生成PPT 技术&#xff1a;Marp&#xff08;https://marp.app/&#xff09;这里用的这个工具进行markdown转PPT 1、让大模型生成Ma…