image.png
image.png

1.开启AOP

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJ***Registrar.class) public @interface EnableAspectJ*** {

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

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

        Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); if (registry.containsBeanDefinition(***_CREATOR_BEAN_NAME)) {
            BeanDefinition apcDefinition = registry.getBeanDefinition(***_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(***_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition;
    }

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

image.png
image.png

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

image.png
image.png
image.png
image.png

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

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

image.png
image.png

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

以上都是IOC的内容。

image.png
image.png

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

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

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

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

2.切面通知加载

AnnotationAwareAspectJ***Creator的父类实现了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 {
    }
image.png

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

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

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

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

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

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

正好容器中@EnableAspectJ***为我们添加了该类型的后置处理器。所以每次单实例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) { // 调用AnnotationAwareAspectJ***Creator的postProcessorsBeforeInstantiation() // 其实是父类Abstract***Creator中的 bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); if (bean != null) { //调用AnnotationAwareAspectJ***Creator的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在AbstractAdvisor***Creator中有实现,同时被AnnotationAwareAspectJ***Creator重写了。

不过可以看到重写的方法中先调用了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;
        }
    }
image.png

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

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