深入理解Sping AOP(二)

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情

1.开启AOP

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
复制代码

基于AspectJ注解形式开启AOP需要使用@EnableAspectJAutoProxy注解,进入这个注解,它通过@Import标签向容器当中导入了一个注册器AspectJAutoProxyRegistrar。

	private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
				int requiredPriority = findPriorityForClass(cls);
				if (currentPriority < requiredPriority) {
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			return null;
		}

		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}
复制代码

然后AspectJAutoProxyRegistrar类实现了ImportBeanDefinitionRegistrar 接口,熟悉IOC容器的话应该能理解实现了在ImportBeanDefinitionRegistrar .registerBeanDefinitions()方法中可以动态的往容器里面添加Bean的配置(BeanDefinition)信息,也就是向BeanFactory中注册AnnotationAwareAspectJAutoProxyCreator对象的BeanDefinition信息。

观察继承关系图,因为它是后置处理器,所有在容器启动的Refresh()方法中会执行registerBeanPostProcessors(beanFactory) 方法时候会创建它。

打断点能看到未执行registerBeanPostProcessors方法前BeanDefinitionMap中是存在这个BeanDefinition的。

单例池中和BeanPostProcessors是没有生成这个bean的。

执行该方法后能够看到单例池和BeanPostProcessors中存在了这个后置处理器的Bean。

以上都是IOC的内容。

上图是AnnotationAwareAspectJAutoProxyCreator后置处理器的注册和创建阶段的流程图。

到此为止,我们已经知道Refresh()方法中的registerBeanPostProcessors() 方法已经初始化这个Bean了,在singletonObjects(即单例池)中是能看到这个bean的。

那么这个后置处理器是如何操作的呢?

在Refresh()方法中的registerBeanPostProcessors() 后面有一个方法finishBeanFactoryInitialization() ,会初始化所有的单例对象,而后置处理器就是在实例化和初始化这些对象的过程中发挥作用的。

2.切面通知加载

AnnotationAwareAspectJAutoProxyCreator的父类实现了InstantiationAwareBeanPostProcessor,而该接口继承了后置处理器BeanPostProcessor接口,他的父类有这么几个实现方法;

	//bean实例化前的回调操作
    @Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
	}
	//bean实例化后的回调操作
	@Override
	public boolean postProcessAfterInstantiation(Object bean, String beanName) {
	}
    //bean实例化完成后初始化之前回调操作
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
	}
	//bean实例化完成初始化之后回调操作
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
	}
复制代码

这里提前介绍说明一下:postProcessBeforeInstantiation方法中会加载切面及通知。

SpringIOC的refresh()方法包含了许多逻辑,其中在finishBeanFactoryInitialization()方法中,开始了解析AnnotationAwareAspectJAutoProxyCreator的工作。

熟悉一下IOC初始化bean的过程:

preInstantiateSingletons() -----> getBean() -----> doGetBean() ----->getSingleton(尝试从缓存中获取)---->lamda内部类方法getObject----->CreatBean();

在CreatBean方法中有一个方法:resolveBeforeInstantiation(beanName, mbdToUse);

该方法就会遍历所有后置处理器,调用InstantiationAwareBeanPostProcessor类型的后置处理器的postProcessBeforeInstantiation方法。

正好容器中@EnableAspectJAutoProxy为我们添加了该类型的后置处理器。所以每次单实例bean创建的时候都会调用该方法。

		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
复制代码

会先尝试返回一个代理对象,如果返回不成功,那么就执行doCreatBean方法。

	@Nullable
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
                    // 调用AnnotationAwareAspectJAutoProxyCreator的postProcessorsBeforeInstantiation()
                    // 其实是父类AbstractAutoProxyCreator中的
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
                        //调用AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization()
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}
复制代码

在看postProcessBeforeInstantiation()之前先看下我写的切面类,

@Component
@Aspect
public class Aop {

        /**
         * 切面
         */
        @Pointcut("execution(* com.yang.service..*.*(..))")
        public void pointcut() {
        }


        @Before("pointcut()")
        public void before() {
                System.out.println("增强-------------------------------------------");
        }
}
复制代码

我的demo中切面类叫AOP,接下来就看postProcessBeforeInitialization()是如何解析@Aspect修饰的类的;

	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
		//省略代码----------------------------------------
		if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
				this.targetSourcedBeans.add(beanName);
			}
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}
		return null;
	}
复制代码

getAdvicesAndAdvisorsForBean方法,该方法的目的是获取并生成Advisor Bean。其中包含了扫描通过@Aspect注解配置且与Bean方法的匹配的Advice。

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

	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        //获取到所有切面通知方法
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
        //匹配到符合当前对象的通知方法
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        //特殊处理,这里不赘述
		extendAdvisors(eligibleAdvisors);
        //对通知方法集合进行排序
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}
复制代码

什么是Advisor? 首先,Advice是增强方法,即@Around, @Before等注解修饰的方法。而Advisor则是在Advice之上再包了一层。例如PointcutAdvisor则包有Advice和Pointcut

findCandidateAdvisors()

	protected List<Advisor> findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
		List<Advisor> advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		if (this.aspectJAdvisorsBuilder != null) {
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}
复制代码

这里findCandidateAdvisors在AbstractAdvisorAutoProxyCreator中有实现,同时被AnnotationAwareAspectJAutoProxyCreator重写了。

不过可以看到重写的方法中先调用了super.findCandidateAdvisor。

this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 从所有Bean中获取@Aspect配置的Bean并创建Advisor,也是我们关注的内容。

由于这段代码比较长,这里就不细说了,深挖的话还能再写一篇文章。

主要是通过beanName扫描@Aspect配置并生成Advisor的过程了。

其中this.advisorFactory.getAdvisors(factory)是生成Advisor类的具体内容。

findAdvisorsThatCanApply()

现在我们获得了所有的候选Advisor,那么找出和当前Bean匹配的Advisor呢?

	protected List<Advisor> findAdvisorsThatCanApply(
			List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}
复制代码

会执行AopUtils.findAdvisorsThatCanApply

	public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new ArrayList<>();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
				eligibleAdvisors.add(candidate);
			}
		}
		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor) {
				// already processed
				continue;
			}
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}
复制代码

最后定位到canApply()

	public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
		if (advisor instanceof IntroductionAdvisor) {
			return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
		}
		else if (advisor instanceof PointcutAdvisor) {
			PointcutAdvisor pca = (PointcutAdvisor) advisor;
			return canApply(pca.getPointcut(), targetClass, hasIntroductions);
		}
		else {
			// It doesn't have a pointcut so we assume it applies.
			return true;
		}
	}
复制代码

可以看出判断是否是该bean合适的advisor,是通过advisor.getPointcut().getClassFilter().matches(targetClass)方法来判断的。匹配完class以后下面还有MethodMatcher来匹配method。回想我们在配置pointcut的时候不仅仅有class的规则,也有method的规则。

当然,再深入matches方法进去的话就是pointcut的匹配语法实现了。有兴趣的可以自行阅读。

补充:代理对象创建流程链接深入理解Sping AOP(一)

猜你喜欢

转载自juejin.im/post/7107498277817286686