深入理解Spring AOP(二)

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的匹配语法实现了。有兴趣的可以自行阅读。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值