为了账号安全,请及时绑定邮箱和手机立即绑定

Spring基础系列-AOP源码分析 (一)

标签:
Java


原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9560803.html 

一、概述

  Spring的两大特性:IOC和AOP。

  AOP是面向切面编程,Spring内置了自己实现的基于动态代理技术的AOP,同时还支持成熟的AspectJ框架,我们这里主要讲述的还是内置的基于动态代理的AOP实现。因为面对一些普通的需求,Spring内置的AOP已经绰绰有余。

  AOP一般用于增强原来的代码的功能,这种增强体现在辅助方面,比如安全、日志、事务等。

二、术语

1、连接点(JoinPoint)

  连接点就是具体的代码中的切入点,指的是具体的一处代码位置。

2、切点(PointCut)

  切点是对一系列代表同种功能(目的)的切入点(连接点)的统称,切点不是一个点,而是代表某一功能的一系列连接点的集合

3、通知(Advice)

  通知就是我们要在切点执行的操作,就是我们要实现的目的,是要实现的功能的代码实现。一般通知又称为增强,所谓增强就是对原来功能的基础上添加新功能,进行功能增强。

4、切面(Aspect)

  切面是通知和切点的综合体,定义好了一个切面,那么我们就知道,这个AOP要实现的功能是什么,需要切入到程序中的那些地方。抽象层次中,切面是代码功能的横切面,这个横切面的位置就是切点、这个切面的功能就是通知。

5、织入(Weaving)

  织入就是切面作用到目标代码中的方式,Spring内置的AOP采用的是动态代理的方式来织入,还可以采用编译器织入和加载期织入,后两者分别需要特定的编译器和类加载器来完成,后两种方式是AspectJ所支持的织入方式。

6、引介(Introduction)

  引介是另一种类型的增强,它可以为类添加一些属性和方法。它和通知是并列的两种不同的增强。

7、目标对象(Target)

  目标对象就是我们想要织入的对象,一般不会是一个,通常是一批符合条件的对象。

8、代理(Proxy)

  代理就好理解了,Spring内置的AOP就是通过动态代理的方式实现织入的,创建目标对象的代理类,在代理类中执行通知的内容,然后在合适的位置调用目标对象的方法,来达到织入的目的。

三、Spring AOP概述

  Spring AOP是基于动态代理技术实现的切面编程,代理技术包括JDK动态代理和CGLIB动态代理,前者基于接口实现,后者基于类实现。

1、Spring中使用AOP技术的方式:

  1)定义切面类,使用@Aspect注解

  2)在切面类中定义切点方法,使用@PointCut注解

  3)在切面类中定义通知方法,使用@Before、@After、@Around等注解

  4)在通知方法的注解中使用切点方法

  5)在切面类上加设注解@Component

  6)启动AOP功能,两种方式:原始的XML配置方式和注解方式

    XMl方式:<aop:aspectj-autoproxy/>

    注解方式:@EnableAspectJAutoProxy

    配置方式:spring.auto.proxy=true

2、Spring AOP支持的增强类型

通知增强:Advice  

  前置通知:MethodBeforeAdvice-在连接点之前执行

  后置通知:AfterReturningAdvice-在连接点正常执行完后执行,如果还未到连接点就异常,不会执行

  环绕通知:AroundAdvice-在连接点前后执行

  异常通知:AfterThrowingAdvice-在连接点抛出异常后执行

  finally通知:AfterAdvice-最终执行,无论是否异常,方法执行结束都会执行

引介增强:IntroductionInterceptor->DelegatingIntroductionInterceptor

  前五种很好理解,重点是最后一种引介增强,这种增强并不是针对方法的增强,而是针对类的增强,它会为目标添加属性和方法,比如它可以为目标类添加一个接口的实现。目标类原本没有实现某个接口,但是我们可以使用引介增强的方式为目标类创建一个实现该接口的代理,在这个代理中可以使用接口的功能来作用于目标对象。

3、原理图:(右键打开看大图)

https://img1.sycdn.imooc.com//5b94db970001947212310852.jpg

四、源码分析

1、入口

1.1 入口一:<aop:aspectj-autoproxy/>

  源码1-来自:AopNamespaceHandler

复制代码

 1     @Override 2     public void init() { 3         // In 2.0 XSD as well as in 2.1 XSD. 4         registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); 5         registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); 6         registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); 7  8         // Only in 2.0 XSD: moved to context namespace as of 2.1 9         registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());10     }

复制代码

  上面源码就是针对XML配置中<aop:XXX/>配置的解析,红色部分正是针对<aop:aspectj-autoproxy/>的解析,如果配置了aspectj-autoproxy,则注册Bean定义解析器:AspectJAutoProxyBeanDefinitionParser

  AspectJAutoProxyBeanDefinitionParser是一个实现了BeanDefinitionParser接口的类,专门用于解析切面自动代理的Bean定义的解析工作,重点在其parse方法。

  源码2-来自:AspectJAutoProxyBeanDefinitionParser

复制代码

 1 class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser { 2  3     @Override 4     @Nullable 5     public BeanDefinition parse(Element element, ParserContext parserContext) { 6         // 1-注册AnnotationAwareAspectJAutoProxyCreator 7         AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); 8         // 2-扩展BeanDefinition 9         extendBeanDefinition(element, parserContext);10         return null;11     }12 13     private void extendBeanDefinition(Element element, ParserContext parserContext) {14         // 获取BeanName为internalAutoProxyCreator的BeanDefinition,其实就是之前注册的自动代理构建器15         BeanDefinition beanDef =16                 parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);17         if (element.hasChildNodes()) {18             // 如果当前元素有子节点,则给上面获取的Bean定义添加子节点中明确定义的类型值(填充BeanDefinition)19             addIncludePatterns(element, parserContext, beanDef);20         }21     }22 23     private void addIncludePatterns(Element element, ParserContext parserContext, BeanDefinition beanDef) {24         ManagedList<TypedStringValue> includePatterns = new ManagedList<>();25         NodeList childNodes = element.getChildNodes();//获取子节点26         for (int i = 0; i < childNodes.getLength(); i++) {27             // 遍历子节点,获取子节点中name属性值,封装到TypeStringValue中28             // 在上下文中提取子节点includeElement的元数据保存到TypedStringValue的source属性中29             // 最后封装好的TypeStringValue保存到includePatterns列表中30             Node node = childNodes.item(i);31             if (node instanceof Element) {32                 Element includeElement = (Element) node;33                 TypedStringValue valueHolder = new TypedStringValue(includeElement.getAttribute("name"));34                 valueHolder.setSource(parserContext.extractSource(includeElement));35                 includePatterns.add(valueHolder);36             }37         }38         if (!includePatterns.isEmpty()) {39             // 从解析上下文parserContext中提取指定节点element的元数据保存到includePatterns的source属性中,40             // 然后将includePatterns保存到BeanDefinition的propertyValues属性中41             includePatterns.setSource(parserContext.extractSource(element));42             beanDef.getPropertyValues().add("includePatterns", includePatterns);43         }44     }45 46 }

复制代码

  上面代码中有两个重点,首先就是registerAspectJAnnotationAutoProxyCreatorIfNecessary方法调用,用于注册AnnotationAwareAspectJAutoProxyCreator构建器;另一点就是在构建器注册完成后,为其填充一些必要内容,这些内容为XML配置中子节点的配置内容,具体内容参照源码,这里重点看看第一步,注册构建器的源码:

  源码3-来自:AopNamespaceUtils

复制代码

 1     public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary( 2             ParserContext parserContext, Element sourceElement) { 3         // 1-注册或升级AnnotationAwareAspectJAutoProxyCreator 4         // parserContext.getRegistry()获取到的是BeanDefinitionRegistry注册器,第二个参数是提取的指定元素的元数据 5         BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary( 6                 parserContext.getRegistry(), parserContext.extractSource(sourceElement)); 7         // 2-校验并设置是否适用基于CGLIB的动态代理实现AOP,和是否要暴露代理类 8         useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); 9         // 3-注册成组件10         registerComponentIfNecessary(beanDefinition, parserContext);11     }12 13     private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {14         if (sourceElement != null) {15             boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));//获取XML中设置的proxy-target-class属性的值,解析为Boolean值16             if (proxyTargetClass) {17                 // 如果为true,则强制自动代理构建器使用基于类的动态代理CGLIB,需要将属性设置到自动代理构建器的BeanDefinition中18                 AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);19             }20             boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));//获取XML中配置的expose-proxy属性的值,同样解析为Boolean值21             if (exposeProxy) {22                 // 如果为true,强制自动代理构建器暴露代理类,需要将属性设置到自动代理构建器的BeanDefinition中23                 AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);24             }25         }26     }27 28     private static void registerComponentIfNecessary(@Nullable BeanDefinition beanDefinition, ParserContext parserContext) {29         if (beanDefinition != null) {30             // 将自动代理构建器包装成为一个Bean组件定义。31             // Bean组件定义是将一个BeanDefinition中包含的所有的属性的值(可能为一个BeanDefinition或者BeanReference)全部封装起来成为一个组件包,然后将其注册到解析上下文中32             BeanComponentDefinition componentDefinition =33                     new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);34             parserContext.registerComponent(componentDefinition);35         }36     }

复制代码

  registerAspectJAnnotationAutoProxyCreatorIfNecessary方法中主要做了三件事情:

    1-注册构建器

    2-配置属性

    3-组件注册

  针对第2和第3,在源码注释中解释的很清楚啦,主要看看第一步,继续进行构建器的注册:

  源码4-来自:AopConfigUtils

复制代码

 1     public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) { 2         if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { 3             //如果构建器已经加载,获取其BeanDefinition,添加属性proxyTargetClass,值为true 4             BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); 5             definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE); 6         } 7     } 8  9     public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {10         if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {11             //如果构建器已经加载,获取其BeanDefinition,添加属性exposeProxy,值为true12             BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);13             definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);14         }15     }16 17     @Nullable18     private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry,19             @Nullable Object source) {20 21         Assert.notNull(registry, "BeanDefinitionRegistry must not be null");22 23         if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {24             // 1-如果internalAutoProxyCreator已经被注册那么比较新旧自动代理构建器类在列表中的优先级,如果已注册的构建器优先级低,则替换为给定的新构建器25             BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);26             if (!cls.getName().equals(apcDefinition.getBeanClassName())) {27                 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());28                 int requiredPriority = findPriorityForClass(cls);29                 if (currentPriority < requiredPriority) {30                     apcDefinition.setBeanClassName(cls.getName());31                 }32             }33             return null;34         }35         // 尚未注册internalAutoProxyCreator的情况下,将给定的构建器包装成RootBeanDefinition,然后注册这个BeanDefinition36         RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);37         // 把元数据保存到BeanDefinition中38         beanDefinition.setSource(source);39         // 设置为最高优先值40         beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);41         // 设置为基础角色42         beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);43         // 2-以internalAutoProxyCreator为beanName注册当前BeanDefinition(AnnotationAwareAspectJAutoProxyCreator类)44         registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);45         return beanDefinition;46     }

复制代码

  源码4中前两个方法时源码3中第二步里面配置属性时调用的方法,在此给出。

  源码4的1-中是在已存在一个自动代理构建器的情况下,将其与新的给定的AnnotationAwareAspectJAutoProxyCreator构建器的优先级进行比对,取优先极高的。

  最后的registerBeanDefinition方法用于注册BeanDefinition。至此,自动代理构建器加载完毕。

1.2 入口二:@EnableAspectJAutoProxy

  源码5-来自:EnableAspectJAutoProxy

复制代码

 1 @Target(ElementType.TYPE) 2 @Retention(RetentionPolicy.RUNTIME) 3 @Documented 4 @Import(AspectJAutoProxyRegistrar.class) 5 public @interface EnableAspectJAutoProxy { 6  7     /** 8      * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed 9      * to standard Java interface-based proxies. The default is {@code false}.10      */11     boolean proxyTargetClass() default false;12 13     /**14      * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}15      * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.16      * Off by default, i.e. no guarantees that {@code AopContext} access will work.17      * @since 4.3.118      */19     boolean exposeProxy() default false;20 21 }

复制代码

  源码中重点关注@Import(AspectJAutoProxyRegistrar.class),很明显这个注解导入了一个新类:AspectJAutoProxyRegistrar。

  使用@Import注解导入的方式可以将一个类注册到BeanFactory中。

  源码6-来自AspectJAutoProxyRegistrar

复制代码

 1 class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { 2  3     @Override 4     public void registerBeanDefinitions( 5             AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 6         // 1-注册或升级自动代理构建器 7         AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 8         // 2-封装注解属性,并根据属性进行配置 9         AnnotationAttributes enableAspectJAutoProxy =10                 AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);11         if (enableAspectJAutoProxy != null) {12             if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {13                 AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);14             }15             if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {16                 AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);17             }18         }19     }20 21 }

复制代码

  我们可以从源码5中看到注解@EnableAspectJAutoProxy内部有两个属性设置proxyTargetClass和exposeProxy,这个之前的入口一中源码3里面的2-中的设置是一样的,即我们在XML启动AOP的时候也可以设置这两个值。

  proxyTargetClass属性表示是否适用基于类的的动态代理CGLIB来创建代理类。true表示使用,false表示不使用,默认是false。

  exposeProxy属性表示是否暴露生成的代理类,暴露就是可手动调用,最常见的情况如,在一个类中使用this调用带有@Transactional注解的方法,你会发现事务是不生效的,这时候我们就可以将生成的代理暴露出来手动调用代理类来保证事务生效:

  如下例子中:

1 public interface TestService {2     void testMethod1();3     void testMethod2();4 }

复制代码

 1 public class TestServiceImpl { 2      3     @Transactional 4     public void testMethod1(){ 5         //some transaction operate     6     } 7      8     public void testMethod2(){ 9         this.testMethod1();10     }11 }

复制代码

  在testMethod2中以this.testMethod1()方式调用带事务注解的testMethod1方法时,其事务是不生效的。修改方式就是将exposeProxy设置为true,然后修改调用方式为:

1     ((TestService)AopContext.currnetProxy()).testMethod1();

  源码6中1-调用的是AopConfigUtils中的方法:

  源码7-来自:AopConfigUtils

1     @Nullable2     public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {3         return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);4     }

  然后它再调用的就是源码4中的源码了,到这里调用的就是公共部分啦。那么这一部分也就到此为止了,其余见源码4之后的部分。

  到此两个主要的入口都分析完毕,入口的主要作用就是注册或者升级自动代理构建器,因为之后AOP的操作基本都要依靠这个构建器来完成。

2、创建AOP代理

  我们的重点就是构建器AnnotationAwareAspectJAutoProxyCreator,分析下其继承结构,你会发现它实现了BeanPostProcessor接口。

  BeanPostProcessor接口有两个方法:

    postProcessBeforeInitialization:Bean实例初始化前调用

    postProcessAfterInitialization:Bean实例初始化之后调用

  然后我们在其继承体系中寻找实现这两个方法的类,一番寻找后发现:AbstractAutoProxyCreator

  源码8-来自:AbstractAutoProxyCreator

复制代码

 1     @Override 2     public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException { 3         if (bean != null) { 4             // 1-生成缓存key 5             Object cacheKey = getCacheKey(bean.getClass(), beanName); 6             // 校验该key是否已存在于earlyProxyReferences缓存 7             if (!this.earlyProxyReferences.contains(cacheKey)) { 8                 // 2-执行创建代理对象 9                 return wrapIfNecessary(bean, beanName, cacheKey);10             }11         }12         return bean;13     }

复制代码

  我们发现了这个方法的实现,这个方法会在构建器Bean初始化之后被调用。我们看看它做了啥?

  重点就是wrapIfNecessary方法,这个方法用于代理对象的生成。

  源码9-来自:AbstractAutoProxyCreator

复制代码

 1     protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { 2         if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { 3             // 已经处理过,直接返回 4             return bean; 5         } 6         if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { 7             // 如果不需要增强,直接返回 8             return bean; 9         }10         if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {11            // 检测目标类是否是AOP的基础设施类,基础设施类包括Advice、Pointcut、Advisor、AopInfrastructureBean,或者是否需要跳过代理,如果是则将其设置为无需增强12             this.advisedBeans.put(cacheKey, Boolean.FALSE);13             return bean;14         }15 16         // Create proxy if we have advice.17         // 1-获取针对当前Bean的增强18         Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);19         if (specificInterceptors != DO_NOT_PROXY) {20             // 如果获取到增强则执行下面的创建代理21             this.advisedBeans.put(cacheKey, Boolean.TRUE);22             // 2-创建代理23             Object proxy = createProxy(24                     bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));25             // 缓存代理类26             this.proxyTypes.put(cacheKey, proxy.getClass());27             return proxy;28         }29         // 如果未获取到增强,则设置跳过代理30         this.advisedBeans.put(cacheKey, Boolean.FALSE);31         return bean;32     }

复制代码

  上面的源码中除了进行一些必要的校验之外,主要的逻辑是获取针对当前Bean的增强和创建代理这两步。

  首先来看下如何获取增强

  源码10-来自:AbstractAdvisorAutoProxyCreator

复制代码

 1     //获取通知(增强) 2     @Override 3     @Nullable 4     protected Object[] getAdvicesAndAdvisorsForBean( 5             Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { 6  7         List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); 8         if (advisors.isEmpty()) { 9             return DO_NOT_PROXY;10         }11         return advisors.toArray();12     }

复制代码

  源码11-来自:AbstractAdvisorAutoProxyCreator

复制代码

 1    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { 2         // 1-先获取所有的增强器列表 3         List<Advisor> candidateAdvisors = findCandidateAdvisors(); 4         // 2-获取应用到当前目标类的增强器列表 5         List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); 6         //这个方法是一个钩子方法,用于子类重写扩展 7         extendAdvisors(eligibleAdvisors); 8         if (!eligibleAdvisors.isEmpty()) { 9             eligibleAdvisors = sortAdvisors(eligibleAdvisors);//排序10         }11         return eligibleAdvisors;12     }

复制代码

  上面的源码我们重点关注findCandidateAdvisors方法和findAdvisorsThatCanApply方法,分别用于找出BeanFactory中所有的可用的增强器,和从可用增强器中找出作用于目标类的增强器。

  源码12-来自:AbstractAdvisorAutoProxyCreator

1     protected List<Advisor> findCandidateAdvisors() {2         Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");3         return this.advisorRetrievalHelper.findAdvisorBeans();4     }

  源码13-来自:BeanFactoryAdvisorRetrievalHelper

复制代码

 1     public List<Advisor> findAdvisorBeans() { 2         // Determine list of advisor bean names, if not cached already. 3         String[] advisorNames = null; 4         synchronized (this) { 5             advisorNames = this.cachedAdvisorBeanNames; 6             if (advisorNames == null) { 7                 // Do not initialize FactoryBeans here: We need to leave all regular beans 8                 // uninitialized to let the auto-proxy creator apply to them! 9                 // 1-获取当前BeanFactory及其继承体系中的容器中所有的Advisor类型的Bean的BeanName数组,排除掉FactoryBeans10                 advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(11                         this.beanFactory, Advisor.class, true, false);12                 this.cachedAdvisorBeanNames = advisorNames;13             }14         }15         if (advisorNames.length == 0) {16             return new LinkedList<>();17         }18 19         List<Advisor> advisors = new LinkedList<>();20         for (String name : advisorNames) {21             if (isEligibleBean(name)) {22                 // 2-再排除创建中的Bean23                 if (this.beanFactory.isCurrentlyInCreation(name)) {24                     if (logger.isDebugEnabled()) {25                         logger.debug("Skipping currently created advisor '" + name + "'");26                     }27                 }28                 else {29                     try {30                         // 3-把剩下的Bean添加到通知(增强器)列表中31                         advisors.add(this.beanFactory.getBean(name, Advisor.class));32                     }33                     catch (BeanCreationException ex) {34                         Throwable rootCause = ex.getMostSpecificCause();35                         if (rootCause instanceof BeanCurrentlyInCreationException) {36                             BeanCreationException bce = (BeanCreationException) rootCause;37                             String bceBeanName = bce.getBeanName();38                             if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {39                                 if (logger.isDebugEnabled()) {40                                     logger.debug("Skipping advisor '" + name +41                                             "' with dependency on currently created bean: " + ex.getMessage());42                                 }43                                 // Ignore: indicates a reference back to the bean we're trying to advise.44                                 // We want to find advisors other than the currently created bean itself.45                                 continue;46                             }47                         }48                         throw ex;49                     }50                 }51             }52         }53         return advisors;54     }

复制代码

  这段源码看起来挺复杂,我们去掉一些不必要的内容,总结起来,总共三件事:

    1-获取容器中所有的Advisor,排除FactoryBeans

    2-再排除创建中的Bean

    3-将剩余的Advisor通过getBean创建Bean实例并添加到列表中返回

  至于再下一步的逻辑就不再探寻啦。

  然后是源码11中的2-findAdvisorsThatCanApply方法

  源码14-来自:AbstractAdvisorAutoProxyCreator

复制代码

 1     protected List<Advisor> findAdvisorsThatCanApply( 2             List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { 3  4         // 将代理的目标Bean的beanName设置到ThreadLocal中 5         ProxyCreationContext.setCurrentProxiedBeanName(beanName); 6         try { 7             // 1-在候选增强器中找出可作用于目标Bean的增强器 8             return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); 9         }10         finally {11             ProxyCreationContext.setCurrentProxiedBeanName(null);12         }13     }

复制代码

  重点操作就是AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);用于找出能作用于目标Bean的增强器列表

  源码15-来自:AopUtils

复制代码

 1     public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { 2         if (candidateAdvisors.isEmpty()) { 3             return candidateAdvisors; 4         } 5         List<Advisor> eligibleAdvisors = new LinkedList<>(); 6         for (Advisor candidate : candidateAdvisors) { 7             if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { 8                 // 1-首先添加引介增强 9                 eligibleAdvisors.add(candidate);10             }11         }12         boolean hasIntroductions = !eligibleAdvisors.isEmpty();13         for (Advisor candidate : candidateAdvisors) {14             if (candidate instanceof IntroductionAdvisor) {15                 // already processed16                 //跳过引介增强17                 continue;18             }19             //校验其余增强器是否能应用到目标Bean20             if (canApply(candidate, clazz, hasIntroductions)) {21                 // 2-添加通知增强22                 eligibleAdvisors.add(candidate);23             }24         }25         return eligibleAdvisors;26     }

复制代码

  源码中可以看出来,这里针对了两种类型的增强器(引介增强和通知增强)分别进行了处理,首先处理了引介增强,然后是通知增强。

  这里有两个canApply方法,第一个用于判断引介增强是否能作用到目标类,第二个用于判断通知增强是否能作用到目标类。

  其实第一个是通过调用第二个实现的。

  我觉得我们可以简单看看其实现逻辑:

  源码16-来源:AopUtils

复制代码

    //用于校验引介增强
    public static boolean canApply(Advisor advisor, Class<?> targetClass) {        return (advisor, targetClass, false);
    }        
    //用于校验通知增强
    public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {        if (advisor instanceof IntroductionAdvisor) {            return ((IntroductionAdvisor) advisor).getClassFilter().(targetClass);// 针对引介增强的类级匹配校验
        }        else if (advisor instanceof PointcutAdvisor) {
            PointcutAdvisor pca = (PointcutAdvisor) advisor;            return(pca.getPointcut(), targetClass, hasIntroductions);// 针对通知增强的匹配校验
        }        else {            // It doesn't have a pointcut so we assume it applies.
            return true;
        }
    }
    // 针对通知增强的匹配校验
    public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
        Assert.notNull(pc, "Pointcut must not be null");        if (!pc.getClassFilter().matches(targetClass)) {            return false;// 针对通知增强的类级匹配校验,如果类级校验不通过,直接驳回
        }
     
        MethodMatcher methodMatcher = pc.getMethodMatcher();// 获取方法匹配器
        if (methodMatcher == MethodMatcher.TRUE) {// 获取方法匹配器匹配的是所有方法,这里直接返回true,不必要做校验
            // No need to iterate the methods if we're matching any method anyway...
            return true;
        }

        IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;        if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
            introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
        }

        Set<Class<?>> classes = new LinkedHashSet<>();        if (!Proxy.isProxyClass(targetClass)) {
            classes.add(ClassUtils.getUserClass(targetClass));
        }
        classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));        for (Class<?> clazz : classes) {
            Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);            for (Method method : methods) {                if (introductionAwareMethodMatcher != null ?
                        introductionAwareMethodMatcher.(method, targetClass, hasIntroductions) :
                        methodMatcher.(method, targetClass)) {
            // 方法匹配校验                    return true;
                }
            }
        }        return false;
    }

复制代码

  上面的源码中用于判断增强是否与给定的类匹配,用了多个matches方法,包括ClassFilter的matches方法,IntroductionAwareMethodMatcher的matches方法和MethodMatcher中的matches方法。

  第一个matches匹配的是类,第二、三个matches匹配的是方法。其中引介增强针对的是类,所以其校验仅仅使用类级匹配进行校验,但是通知增强针对的是类中的方法,需要进行类和方法的双重匹配校验。

原文出处:https://www.cnblogs.com/V1haoge/p/9560803.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消