美文网首页工作生活
Spring源码学习系列(五)之AOP源码解析

Spring源码学习系列(五)之AOP源码解析

作者: just_like_you | 来源:发表于2019-07-04 22:19 被阅读0次

    今天记录一下Spring#Aop的功能实现过程,以及一些源码解析。

    1、首先呢,Aop是从哪里开始的激活的?答案是@EnableAspectJAutoProxy,这是基于注解驱动的,以前基于xml,我们开启注解功能,是用<aop:aspectj-autoproxy/>。那么这两个操作都是怎么开启Spring#Aop功能的呢?直接进入源码,以注解版的为例子:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(AspectJAutoProxyRegistrar.class)
    public @interface EnableAspectJAutoProxy {
       //配置为true强行使用CGLIB动态代理,默认false的时候当类有接口的时候会自动使用Jdk原生的动态代理
        boolean proxyTargetClass() default false;
       //这个属性主要是用来在一些场景下开启动态代理 ex : (在同一service中调用同类方法会让@Transactional注解失效)
        boolean exposeProxy() default false;
    }
    

    该注解是一个@Import的派生注解,给容器中加入了一个名为AspectJAutoProxyRegistrar的bean,查看该bean申明,发现其实现了ImportBeanDefinitionRegistrar接口,该接口可以根据像容器中注册一些bean

    class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    
        /**
         * Register, escalate, and configure the AspectJ auto proxy creator based on the value
         * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
         * {@code @Configuration} class.
         */
        @Override
        public void registerBeanDefinitions(
            AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            //核心代码
            AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
    }
    
    

    其中registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,见名知意,如果需要的话注册一个名为AspectJAnnotationAutoProxyCreator的bean,根据猜想继续跟进

        @Nullable
        public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
                BeanDefinitionRegistry registry, @Nullable Object source) {
    
            return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
        }
    

    果然如猜想一样,那么registerOrEscalateApcAsRequired又完成了什么操作呢?

        @Nullable
        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;
        }
    

    主要完成了两个操作:
    其中AUTO_PROXY_CREATOR_BEAN_NAME是一个字符串常量org.springframework.aop.config.internalAutoProxyCreator

    • 如果容器中已经含有了AUTO_PROXY_CREATOR_BEAN_NAME,那么会拿将要注入的和容器中存在的bean的Order顺序做比较,优先级高的设置到ioc中
    • 如果不存在,那么直接设置一个优先级最高的AnnotationAwareAspectJAutoProxyCreator,且他的名称为AUTO_PROXY_CREATOR_BEAN_NAME

    然后我们要开始分析AnnotationAwareAspectJAutoProxyCreator,使用IDEA查看继承关系:

    Aop继承类图
    其中红线会发现,这个bean其实是一个BeanPostProcessor的实现类,那么前面后置处理器分析文章我们知道BeanPostProcessor会在Bean的初始化前后执行其后置方法,那么我们进入到继承体系中的AbstractAutoProxyCreator.postProcessAfterInitialization()方法
        @Override
        public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
            if (bean != null) {
          //这里的cacheKey其实就是beanName,若beanName不存在,那么则是beanClass
                Object cacheKey = getCacheKey(bean.getClass(), beanName);
                if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                              //如果提前的代理引用缓存中没有该bean的存在,那么将执行下面的包装方法
                    return wrapIfNecessary(bean, beanName, cacheKey);
                }
            }
            return bean;
        }
    

    其中两个重要的地方,我写了注释,那么我们废话不多少直接进入关键的wrapIfNecessary(bean, beanName, cacheKey)方法

        protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
            if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
                return bean;
            }
            if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
                return bean;
            }
            if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return bean;
            }
            // 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;
        }
    

    其中主要步骤有下列几个:

    • 缓存处理,这个是Spring会将所有bean都用advisedBeans给缓存起来,其属性申明如下,k是cacheKey,v是true/false,true则为需要增强的bean
        private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);
    
    • 判断是否是需要包装的类,这里会排出一些aop相关基础设施类和设置需要跳过的类,
      • 其中isInfrastructureClass是用来判断是否是切面相关类,是则返回true
      • shouldSkip表明是否要跳过,其中主要逻辑就是判断是否以String ORIGINAL_INSTANCE_SUFFIX = ".ORIGINAL"结尾
        protected boolean isInfrastructureClass(Class<?> beanClass) {
            boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
                    Pointcut.class.isAssignableFrom(beanClass) ||
                    Advisor.class.isAssignableFrom(beanClass) ||
                    AopInfrastructureBean.class.isAssignableFrom(beanClass);
            return retVal;
        }
    //这是shouldSkip的核心逻辑
        static boolean isOriginalInstance(String beanName, Class<?> beanClass) {
            if (!StringUtils.hasLength(beanName) || beanName.length() !=
                    beanClass.getName().length() + AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX.length()) {
                return false;
            }
            return (beanName.startsWith(beanClass.getName()) &&
                    beanName.endsWith(AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX));
        }
    
    • 获取切面相关信息组装成List<Advisosr>,其中的Advisor是封装了Advice的接口类,这里是获取切面相关类的主要方法,可以调用练比较深,下面展示源码调用

    1.入口,获取通知方法

        protected Object[] getAdvicesAndAdvisorsForBean(
                Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
            //获取符合条件的Advisor
            List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
            if (advisors.isEmpty()) {
                return DO_NOT_PROXY;
            }
            //转化成数组
            return advisors.toArray();
        }
    

    2.获取所有符合条件的Advisor

        protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
            //查找所有可用的Advisor
            List<Advisor> candidateAdvisors = findCandidateAdvisors();
            //查看所有可以申请的Advisor,使用注解获取方法上面的切入点方法是否一致
            List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
            extendAdvisors(eligibleAdvisors);
            if (!eligibleAdvisors.isEmpty()) {
                eligibleAdvisors = sortAdvisors(eligibleAdvisors);
            }
            return eligibleAdvisors;
        }
    

    3.获取所有候选的Advisor,这里会调用子类AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors扩展

        @Override
        protected List<Advisor> findCandidateAdvisors() {
            // Add all the Spring advisors found according to superclass rules.
                    //获取所有的Advisor类
            List<Advisor> advisors = super.findCandidateAdvisors();
            // Build Advisors for all AspectJ aspects in the bean factory.
            if (this.aspectJAdvisorsBuilder != null) {
                    //构建Advisor,主要就是通过切入点表达式来校验看时候匹配,以及将所有对应的通知方法转化为对应的xxxAdvice类
                advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
            }
            return advisors;
        }
    

    4.通过AspectMetadata元数据来获取对应通知类的值,调用栈过深,直接到核心方法ReflectiveAspectJAdvisorFactory.getAdvisor

        public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
                                  int declarationOrderInAspect, String aspectName) {
    
            validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
    
            //获取承载切入点表达式的属性类
            AspectJExpressionPointcut expressionPointcut = getPointcut(
                    candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
            if (expressionPointcut == null) {
                return null;
            }
    
            //构造通过Advisor实现类,其中构造方法中有根据不同的通知方法类型,获取不同的Advisor实现类
            return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
                    this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
        }
    

    5.调用InstantiationModelAwarePointcutAdvisorImpl.instantiateAdvice中的getAdvice方法构造返回对应通知方法的xxxAdvice类

    
        public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
                                MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    
            AbstractAspectJAdvice springAdvice;
                  //根据不同通知注解获取不同的通知类
            switch (aspectJAnnotation.getAnnotationType()) {
                case AtPointcut:
                    if (logger.isDebugEnabled()) {
                        logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
                    }
                    return null;
                case AtAround:
                    springAdvice = new AspectJAroundAdvice(
                            candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                    break;
                case AtBefore:
                    springAdvice = new AspectJMethodBeforeAdvice(
                            candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                    break;
                case AtAfter:
                    springAdvice = new AspectJAfterAdvice(
                            candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                    break;
                case AtAfterReturning:
                    springAdvice = new AspectJAfterReturningAdvice(
                            candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                    AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
                    if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                        springAdvice.setReturningName(afterReturningAnnotation.returning());
                    }
                    break;
                case AtAfterThrowing:
                    springAdvice = new AspectJAfterThrowingAdvice(
                            candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                    AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
                    if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                        springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
                    }
                    break;
    

    枚举对应关系:


    其中枚举对应关系

    最后根据不同注解类型获取的不同通知类:


    所有通知类
    • 最后使用动态代理创建代理类,会根据类是否具有接口来判断是启动jdk动态代理还是CGLIB
        @Override
        public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
            if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
                Class<?> targetClass = config.getTargetClass();
                if (targetClass == null) {
                    throw new AopConfigException("TargetSource cannot determine target class: " +
                            "Either an interface or a target is required for proxy creation.");
                }
                if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                    return new JdkDynamicAopProxy(config);
                }
                return new ObjenesisCglibAopProxy(config);
            }
            else {
                return new JdkDynamicAopProxy(config);
            }
        }
    

    那么最后创建完了代理对象,当我们执行目标方法的时候自然就是执行代理对象的方法,Spring中使用JdkDynamicAopProxyCglibAopProxy两个类来实现代理方法

    JdkDynamicAopProxy为例,当执行目标方法的时候,会执行JdkDynamicAopProxy.invoke()

                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
                if (chain.isEmpty()) {
                    // We can skip creating a MethodInvocation: just invoke the target directly
                    // Note that the final invoker must be an InvokerInterceptor so we know it does
                    // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
                }
                else {
                    // We need to create a method invocation...
                    MethodInvocation invocation =
                            new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                    // Proceed to the joinpoint through the interceptor chain.
                    retVal = invocation.proceed();
                }
    

    这里处理逻辑主要有三个地方

    • getInterceptorsAndDynamicInterceptionAdvice,这里会将传递过来的Advisor [] 转化成List<MethodInterceptor> chain
    • 若拦截器链是空的,那么直接执行目标方法
    • 若不为空,则包装成MethodInvocation,然后执行proceed()方法,这里proceed()方法是执行通知的最核心逻辑
        public Object proceed() throws Throwable {
            //这里是讲传递过来的List<MethodInterceptor>的size -1 和当前索引(默认初始化为-1)进行比较判断,若相等则执行目标方法
            if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
                return invokeJoinpoint();
            }
                  
                // 依次获取下一个拦截器`MethodInterceptor`
            Object interceptorOrInterceptionAdvice =
                    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
              //如果拦截器的类型是InterceptorAndDynamicMethodMatcher,则需要进行切入点表达式匹配
            if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                InterceptorAndDynamicMethodMatcher dm =
                        (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
                Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
                if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
                                    //通过则执行拦截器方法
                        return dm.interceptor.invoke(this);
                }
                else {
                         //不执行拦截器方法。
                    return proceed();
                }
            }
            else {
                        //直接执行拦截器方法
                return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
            }
        }
    

    而我们能看到这些MethodInterceptor的类型都是

    MethodInterceptor类型
    • MethodBeforeAdviceInterceptor
        @Override
        public Object invoke(MethodInvocation mi) throws Throwable {
            this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
            return mi.proceed();
        }
    
    • AspectJAfterAdvice (无论如何都会在方法结束调用,源码在finally块里面调用说明了这一点)
        @Override
        public Object invoke(MethodInvocation mi) throws Throwable {
            try {
                return mi.proceed();
            }
            finally {
                invokeAdviceMethod(getJoinPointMatch(), null, null);
            }
        }
    

    其实在MethodInvocation.proceed()方法中,我们可以清楚的看到里面的递归调用,其中xxxAdvice执行增强方法与MethodInterceptor.proceed()方法的调用时机,很好的完成了Aop的各种不同位置调用的增强。很多都没有表示清楚,不知道的可以留言。见谅。

    相关文章

      网友评论

        本文标题:Spring源码学习系列(五)之AOP源码解析

        本文链接:https://www.haomeiwen.com/subject/lvldhctx.html