热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

(一)AOP如何注入SpringBoot中?

(一)AOP如何注入SpringBoot中?-主要内容SpringBoot如何将AOP相关的类注入BeanFactory中,如何起作用呢?梳理概要AopAutoConfigurat

主要内容

SpringBoot如何将AOP相关的类注入BeanFactory中,如何起作用呢?

梳理概要

  1. AopAutoConfiguration:自动注入AOP相关的配置类;AnnotationAwareAspectJAutoProxyCreator;
  2. 在populateBean的时候,每个bean都会扫描是否有切面,匹配一下;AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization;
  3. 匹配成功,则会经过cglib动态代理生成一个新的代理类;

具体的源码过程

1.1 自动配置类加载AOP相关的类;

  1. 加载AopAutoConfiguration
  2. 在加载CglibAutoProxyFactory的时候,里面有注解@EnableAspectJAutoProxy的时候有一个@Import注解,AspectJAutoProxyRegistrar;这个Registrar很重要!!!

    其在ConfigurationClassPostProcessor类扫描加载bean的时候,处理loadBeanDefinitionsFromRegistrars的时候;加载进去;

    public void registerBeanDefinitions(
             AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
         AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
    .....

    registerAspectJAnnotationAutoProxyCreatorIfNecessary()的时候,
    把AnnotationAwareAspectJAutoProxyCreator封装成BeanDefinition,对应的key=internalAutoProxyCreator;

    @Nullable
     public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
             BeanDefinitionRegistry registry, @Nullable Object source) {
    // 把AnnotationAwareAspectJAutoProxyCreator封装成一个BeanDefinition;
         return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
     }

1.2 使用代理类(AnnotationAwareAspectJAutoProxyCreator)


InitializeBean -- 初始化bean的时候,会统一调用所有的BeanPostProcessor.postProcessAfterInitialization;其中就会调用到AnnotationAwareAspectJAutoProxyCreator;进行查看是否有符合要求的切面方法;
调用方法如下:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    ......

// 重点如下:找到这个bean的所有切面方法,然后调用createProxy创建代理类;返回即可。
        // Create proxy if we have advice.
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            Object proxy = createProxy(
                    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }

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

1.3 找所有的合适的通知

protected List findEligibleAdvisors(Class beanClass, String beanName) {
// 1 找到所有的候选通知
        List candidateAdvisors = findCandidateAdvisors();
// 2 进行匹配,查看是否合适
        List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
// 3 这里排序Advisor?
            eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }

1.3.1 findCandidateAdvisors

    protected List findCandidateAdvisors() {
        // Add all the Spring advisors found according to superclass rules.
// 从所有带@Advisor注解的切面类;
        List advisors = super.findCandidateAdvisors();
        // Build Advisors for all AspectJ aspects in the bean factory.
        if (this.aspectJAdvisorsBuilder != null) {
// 开始找@AspectJ的注解类;            advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        }
        return advisors;
    }

this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
主要逻辑:

  1. 遍历BeanDefinitionMap,查看是否有@AspectJ注解,
  2. 如果有,则会遍历method,查看是否是一个通知,如果是一个通知,则会封装成一个InstantiationModelAwarePointcutAdvisorImpl类;
  3. 然后封装返回;
    在这个方法里面还有一个排序!! 在getAdvisorMethod中

    private List getAdvisorMethods(Class aspectClass) {
         List methods = new ArrayList<>();
         ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
         if (methods.size() > 1) {
             methods.sort(adviceMethodComparator);
         }
         return methods;
     }
    

按照什么排序呢?

    private static final Comparator adviceMethodComparator;

    static {
        // Note: although @After is ordered before @AfterReturning and @AfterThrowing,
        // an @After advice method will actually be invoked after @AfterReturning and
        // @AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation)
        // invokes proceed() in a `try` block and only invokes the @After advice method
        // in a corresponding `finally` block.
        Comparator adviceKindComparator = new ConvertingComparator<>(
                new InstanceComparator<>(
                        Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
                (Converter) method -> {
                    AspectJAnnotation ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
                    return (ann != null ? ann.getAnnotation() : null);
                });
        Comparator methodNameComparator = new ConvertingComparator<>(Method::getName);
        adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator);
    }

我们发现,他是按照Around、Before、After、AfterReturning进行排序,如果有相同,则按照methodName进行排序;

1.3.2 findAdvisorsThatCanApply

查看这个类是否和PointCut 匹配成功,匹配成功,即返回列表;

    protected List findAdvisorsThatCanApply(
            List candidateAdvisors, Class beanClass, String beanName) {

        ProxyCreationContext.setCurrentProxiedBeanName(beanName);
        try {
// 查看这个类是否和PointCut 匹配成功,匹配成功,即ok;
            return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
        }
        finally {
            ProxyCreationContext.setCurrentProxiedBeanName(null);
        }
    }

1.3.3 findAdvisorsThatCanApply

比较两个类的order大小;

1.4 createProxy

这个不在细追,
主题逻辑:

  1. 找到所有的Advisor
  2. 创建指定的拦截器,比如:dynamicAdvisorInterceptor加入到callback方法中;
  3. Enhancer.create();

总结

  1. 先想好,再去做;
  2. 命名艺术,AutoProxyCreator、AspectJAdvisor、AspectJAdvisorBuilder、XXFactory
  3. 封装成对象,便于以后的扩展

推荐阅读
author-avatar
浪漫的没天份
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有