zoukankan      html  css  js  c++  java
  • spring源码学习之AOP(一)

      继续源码学习,看了spring中基础的容器和AOP感觉自己也没有什么长进,哈哈,我也不知道到底有用没有,这可能是培养自己的一种精神吧,不管那么多,继续学习!AOP中

    AOP中几个重要的概念:
    (1)Advice--通知
    Advice定义在连接点做什么,为切面增强提供织入接口。在spring中,他主要描述spring AOP围绕方法调用而注入的切面行为。在spring AOP的实现中,使用了AOP联盟定义的统一接口--Advice接口并通过这个接口,为AOP切面的增强的织入功能做了更多的细话和扩展
    (2)PonitCut--切点
    PonitCut(切点)决定Advice通知应该作用于哪个连接点,也就是说通过PonitCut来定义需要增强的方法的集合。这些集合的选取可以按照一定的规则来完成。这种情况下,PonitCut通常意味着标识方法,例如,这些需要增强的地方可以由某个正则表达式进行标识,或根据某个方法名进行匹配
    (3)Advisor--通知器
    完成对目标方法的切面增强设计(Advice)和关注点的设计(PointCut)以后,需要一个对象把它们结合起来,完成这个作用的就是Advisor,通过Advisor,可以定义在应该使用哪个通知并在哪个关注点使用它,也就是说通过Advisor,把Advice和PointCut结合起来,这个结合为使用IoC容器配置AOP应用,或者说即开即用地使用AOP基础设施,提供了便利

    一、动态AOP的使用案例

    1、创建用于拦截的bean
    test方法中封装这核心业务,想在test前后加入日志来跟踪调试,这时候可以使用spring中提供的AOP功能来实现

     1 public class TestBean(){
     2     private String testStr = "testStr";
     3     
     4     public void setTestStr(String testStr){
     5         this.testStr = testStr;
     6     }
     7     
     8     public String getTestStr(){
     9         rerurn testStr;
    10     }
    11     
    12     public void test(){
    13         System.out.println("test");
    14     }
    15 }

    2、创建Advisor
    spring中使用注解的方式实现AOP功能,简化了配置

     1 @Aspect
     2 public class AspectJTest{
     3     
     4     @Pointcut("execution(* *.test(..))")
     5     public void test(){
     6         
     7     }
     8     
     9     @Before("test()")
    10     public void beforeTest(){
    11         System.out.println("beforeTest");
    12     }
    13     
    14     @AfterTest("test()")
    15     public void afterTest(){
    16         System.out.println("afterTest");
    17     }
    18     
    19     @Around("test()")
    20     public Object aroundTest(ProceedingJoinPoint p){
    21         System.out.println("before1");
    22         Object o = null;
    23         o = p.proceed();
    24         System.out.println("after1");
    25         return o;
    26     }    
    27 }

    3、创建配置文件
    XML是Spring的基础。尽管Spring一再简化配置,并且大有使用注解取代XML配置之势,但是在spring中开启AOP功能,还需配置一些信息

    1 <aop:aspectj-autoproxy />
    2 <bean id="test" class="test.TestBean"/>
    3 <bean class="test.AspectJTest"/>

    4、测试

    1 public static void main(String[] args){
    2     ApplicationContext bf = new ClassPathXmlApplicationContext("aspectTest.xml");
    3     TestBean bean = bf.getBean("test");
    4     bean.test();
    5 }

    那么,spring是如何实现AOP的呢?spring是否支持注解的AOP由一个配置文件控制的,<aop:aspectj-autoproxy />,当在spring的配置文件中声明这句配置的时候,
    spring就会支持注解的AOP,从这个注解开始分析

    二、动态AOP自定义标签

    全局搜索一下aspectj-autoproxy,在org.springframework.aop.config包下的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 }

    这里的解析aspectj-autoproxy标签的解析器是AspectJAutoProxyBeanDefinitionParser,看一下这个类的内部实现

    1、注册AspectJAutoProxyBeanDefinitionParser

    所有解析器,因为是对BeanDefinitionParser接口的实现,入口都是从parse函数开始的,从AspectJAutoProxyBeanDefinitionParser的parse方法来看:

    1 @Override
    2 @Nullable
    3 public BeanDefinition parse(Element element, ParserContext parserContext) {
    4     // 注册一个类型为AnnotationAwareAspectJAutoProxyCreator的bean到Spring容器中
    5     AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
    6     // 对于注解中子类的处理
    7     extendBeanDefinition(element, parserContext);
    8     return null;
    9 }

    看一下registerAspectJAnnotationAutoProxyCreatorIfNecessary方法中逻辑的实现:

     1 public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
     2         ParserContext parserContext, Element sourceElement) {
     3 
     4     // 注册AnnotationAwareAspectJAutoProxyCreator的BeanDefinition
     5     BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
     6             parserContext.getRegistry(), parserContext.extractSource(sourceElement));
     7     // 解析标签中的proxy-target-class和expose-proxy属性值,
     8     // proxy-target-class主要控制是使用Jdk代理还是Cglib代理实现,expose-proxy用于控制
     9     // 是否将生成的代理类的实例防御AopContext中,并且暴露给相关子类使用
    10     useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    11     // 将注册的BeanDefinition封装到BeanComponentDefinition中,注册组件并监听,便于监听器做进一步处理
    12     registerComponentIfNecessary(beanDefinition, parserContext);
    13 }

    看一下具体的逻辑代码:主要是分三部分,基本没一行代码都是代表着一部分逻辑

    (1)注册或者升级AnnotationAwareAspectJAutoProxyCreator
    对于AOP实现,基本上都是靠AnnotationAwareAspectJAutoProxyCreator去完成的,为了方便,spring使用了自定义配置来帮助我们自动注册AnnotationAwareAspectJAutoProxyCreator
    起源吗主要是这样的:
    org.springframework.aop.config包下的AopConfigUtils类中

     1 @Nullable
     2 public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
     3         BeanDefinitionRegistry registry, @Nullable Object source) {
     4 
     5     return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
     6 }
     7 
     8 同一个类中:
     9 @Nullable
    10 private static BeanDefinition registerOrEscalateApcAsRequired(
    11         Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
    12 
    13     Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    14 
    15     // 如果已经存在了自动代理创建器且存在的自动代理创建器与现在的不一致,那么需要根据优先级来判断到底需要使用哪个
    16     if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
    17         // AUTO_PROXY_CREATOR_BEAN_NAME = "org.springframework.aop.config.internalAutoProxyCreator"
    18         BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
    19         if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
    20             int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
    21             int requiredPriority = findPriorityForClass(cls);
    22             if (currentPriority < requiredPriority) {
    23                 // 改变bean最重要的是改变bean所对应的className属性
    24                 apcDefinition.setBeanClassName(cls.getName());
    25             }
    26         }
    27         // 如果已经存在自动代理创造器并且与将要创建的一致,那么无须再次创建
    28         return null;
    29     }
    30 
    31     RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
    32     beanDefinition.setSource(source);
    33     beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
    34     beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    35     registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
    36     return beanDefinition;
    37 }

    (2)处理proxy-target-class和expose-proxy属性
    org.springframework.aop.config包下的AopNamespaceHandler类useClassProxyingIfNecessary方法

     1 private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
     2     if (sourceElement != null) {
     3         // 对于proxy-target-class属性的处理
     4         boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
     5         if (proxyTargetClass) {
     6             AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
     7         }
     8         // 对于 expose-proxy属性的处理
     9         boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
    10         if (exposeProxy) {
    11             AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
    12         }
    13     }
    14 }

    org.springframework.aop.config包下的AopConfigUtils类中forceAutoProxyCreatorToUseClassProxying方法和forceAutoProxyCreatorToExposeProxy方法

     1 // 强制使用的过程也是属性设置的过程
     2 public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
     3     if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
     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 definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
    12         definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
    13     }
    14 }

    proxy-target-class属性:Spring AOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理(建议尽量使用JDK的动态代理),如果目标对象实现了至少一个接口,
    则会使用JDK动态代理,所有该目标被实现的接口都将被代理,若该目标对象没有实现任何接口,则创建一个CGLIB代理。
    强制使用CGLIB代理需要将proxy-target-class属性设置为true

    实际使用中发现的使用中的差别:
    JDK动态代理:
    其代理对象必须是某个接口的实现,他是通过在运行期间创建一个接口的实现类来完成对目标对象的代理
    CGLIB代理:
    实现原理类似于JDK动态代理,只是他在运行期间生成的代理对象是针对目标类扩展的子类,CGLIB是高效的代码生成包,底层是依靠ASM操作字节码实现的,性能比JDK强

    expose-proxy属性:
    有时候目标对象内部的自我调用将无法实施切面中的增强

    (3)将注册的BeanDefinition封装到BeanComponentDefinition中

    org.springframework.aop.config包下的AopNamespaceHandler类中的registerComponentIfNecessary方法

    1 private static void registerComponentIfNecessary(@Nullable BeanDefinition beanDefinition, ParserContext parserContext) {
    2     if (beanDefinition != null) {
    3         parserContext.registerComponent(
    4                 new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME));
    5     }
    6 }

    三、创建AOP代理

      上文中讲解了通过自定义配置完成了对AnnotationAwareAspectJAutoProxyCreator的注册,那么这个类到底做了什么工作来完成AOP工作的,可以看一下AnnotationAwareAspectJAutoProxyCreator类的层次结构,我们可以看到AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessor接口,当spring加载这个Bean的时候会在实例化前调用其postProcessAfterInitialization,从这个开始

     org.springframework.aop.framework.autoproxy包下的AbstractAutoProxyCreator,看一下父类这个postProcessAfterInitialization方法

     1 @Override
     2 public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
     3     if (bean != null) {
     4         // 根据给定的bean的class和name构建出一个key,格式beanClassName_beanName
     5         Object cacheKey = getCacheKey(bean.getClass(), beanName);
     6         if (this.earlyProxyReferences.remove(cacheKey) != bean) {
     7             // 如果它适合被代理,则需封装指定bean
     8             return wrapIfNecessary(bean, beanName, cacheKey);
     9         }
    10     }
    11     return bean;
    12 }
    13 
    14 // 同一个类中:
    15 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    16     // 如果已经处理过
    17     if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
    18         return bean;
    19     }
    20     // 无需增强
    21     if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    22         return bean;
    23     }
    24     // 给定的bean类是否代表一个基础施设类,基础设施类不应代理或者配置了指定类不需要自动代理
    25     if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    26         this.advisedBeans.put(cacheKey, Boolean.FALSE);
    27         return bean;
    28     }
    29 
    30     // Create proxy if we have advice.
    31     // 如果存在增强方法则创建代理
    32     Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    33     // 如果获取到了增强,则需要根据增强创建代理
    34     if (specificInterceptors != DO_NOT_PROXY) {
    35         this.advisedBeans.put(cacheKey, Boolean.TRUE);
    36         // 创建代理
    37         Object proxy = createProxy(
    38                 bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    39         this.proxyTypes.put(cacheKey, proxy.getClass());
    40         return proxy;
    41     }
    42 
    43     this.advisedBeans.put(cacheKey, Boolean.FALSE);
    44     return bean;
    45 }

    函数中,我们已经看到了代理创建的雏形,在创建之前还需要经过一些判断,比如,是否已经处理过或者是否需要跳过的bean,而真正创建代理的代码是从getAdvicesAndAdvisorsForBean方法开始的
    创建代理的逻辑主要分为两部分:
    (1)获取增强方法或者增强器
    (2)根据获取的增强进行代理

    org.springframework.aop.framework.autoproxy包下的AbstractAdvisorAutoProxyCreator类中

     1 @Override
     2 @Nullable
     3 protected Object[] getAdvicesAndAdvisorsForBean(
     4         Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
     5 
     6     List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
     7     if (advisors.isEmpty()) {
     8         return DO_NOT_PROXY;
     9     }
    10     return advisors.toArray();
    11 }
    12 
    13 protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    14     // 获取增强器
    15     List<Advisor> candidateAdvisors = findCandidateAdvisors();
    16     // 寻找匹配的增强器
    17     List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    18     extendAdvisors(eligibleAdvisors);
    19     if (!eligibleAdvisors.isEmpty()) {
    20         eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    21     }
    22     return eligibleAdvisors;
    23 }

    对于指定bean的增强方法的获取一定是包含两个步骤,获取所有的增强以及寻找所有增强中适用于bean的增强并应用,那么findCandidateAdvisors和findAdvisorsThatCanApply
    便是做了这两件事情

    1、获取增强器

    由于我们分析的是使用注解进行的AOP,所以对于findCandidateAdvisors的实现其实是由org.springframework.aop.aspectj.annotation包下的AnnotationAwareAspectJAutoProxyCreator完成的,继续跟踪此类中的findCandidateAdvisors方法

     1 @Override
     2 protected List<Advisor> findCandidateAdvisors() {
     3     // Add all the Spring advisors found according to superclass rules.
     4     // 当使用注解方式配置AOP的时候并不是丢弃了对XML配置的支持
     5     // 这里调用父类方法加载配置文件中的AOP声明
     6     List<Advisor> advisors = super.findCandidateAdvisors();
     7     // Build Advisors for all AspectJ aspects in the bean factory.
     8     if (this.aspectJAdvisorsBuilder != null) {
     9         advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    10     }
    11     return advisors;
    12 }

    AnnotationAwareAspectJAutoProxyCreator简接继承了AbstractAdvisorAutoProxyCreator,在实现获取增强的方法中除了保留父类的获取配置文件中定义的增强外,
    同时添加了获取Bean的注解增强的功能,那么其实正是由this.aspectJAdvisorsBuilder.buildAspectJAdvisors();来实现的。思路如下:
    (1)获取所有的beanName,这一步骤中所有在beanFactory中注册的bean都会被提取出来
    (2)遍历所有的beanName,并找出声明AspectJ注解的类,进行进一步处理
    (3)对标记AspectJ注解的类进行增强器的提取
    (4)将提取结果加入缓存

    看看源码如何实现AspectJ注解增强处理:提取Advisor
    org.springframework.aop.aspectj.annotation包下的BeanFactoryAspectJAdvisorsBuilder类中的buildAspectJAdvisors方法

     1 public List<Advisor> buildAspectJAdvisors() {
     2     List<String> aspectNames = this.aspectBeanNames;
     3 
     4     if (aspectNames == null) {
     5         synchronized (this) {
     6             aspectNames = this.aspectBeanNames;
     7             if (aspectNames == null) {
     8                 List<Advisor> advisors = new ArrayList<>();
     9                 aspectNames = new ArrayList<>();
    10                 // 获取所有的beanName
    11                 String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
    12                         this.beanFactory, Object.class, true, false);
    13                 // 循环所有的beanName找出对应的增强方法
    14                 for (String beanName : beanNames) {
    15                     // 不合法的bean略过,又子类定义规则,默认返回true
    16                     if (!isEligibleBean(beanName)) {
    17                         continue;
    18                     }
    19                     // We must be careful not to instantiate beans eagerly as in this case they
    20                     // would be cached by the Spring container but would not have been weaved.
    21                     // 获取对应的bean类型
    22                     Class<?> beanType = this.beanFactory.getType(beanName);
    23                     if (beanType == null) {
    24                         continue;
    25                     }
    26                     // 如果存在AspectJ注解
    27                     if (this.advisorFactory.isAspect(beanType)) {
    28                         aspectNames.add(beanName);
    29                         AspectMetadata amd = new AspectMetadata(beanType, beanName);
    30                         // 
    31                         if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
    32                             MetadataAwareAspectInstanceFactory factory =
    33                                     new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
    34                             // 解析标记AspectJ注解中的增强方法
    35                             List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
    36                             if (this.beanFactory.isSingleton(beanName)) {
    37                                 this.advisorsCache.put(beanName, classAdvisors);
    38                             }
    39                             else {
    40                                 this.aspectFactoryCache.put(beanName, factory);
    41                             }
    42                             advisors.addAll(classAdvisors);
    43                         }
    44                         else {
    45                             // Per target or per this.
    46                             if (this.beanFactory.isSingleton(beanName)) {
    47                                 throw new IllegalArgumentException("Bean with name '" + beanName +
    48                                         "' is a singleton, but aspect instantiation model is not singleton");
    49                             }
    50                             MetadataAwareAspectInstanceFactory factory =
    51                                     new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
    52                             this.aspectFactoryCache.put(beanName, factory);
    53                             advisors.addAll(this.advisorFactory.getAdvisors(factory));
    54                         }
    55                     }
    56                 }
    57                 this.aspectBeanNames = aspectNames;
    58                 return advisors;
    59             }
    60         }
    61     }
    62 
    63     if (aspectNames.isEmpty()) {
    64         return Collections.emptyList();
    65     }
    66     // 记录在缓存中
    67     List<Advisor> advisors = new ArrayList<>();
    68     for (String aspectName : aspectNames) {
    69         List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
    70         if (cachedAdvisors != null) {
    71             advisors.addAll(cachedAdvisors);
    72         }
    73         else {
    74             MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
    75             advisors.addAll(this.advisorFactory.getAdvisors(factory));
    76         }
    77     }
    78     return advisors;
    79 }

    至此已经完成了Advisor的提取,在上面的步骤中最为重要的,也是最为复杂的就是增强器的获取。而这一功能委托给this.advisorFactory.getAdvisors(factory)
    看一下这个方法的源码中逻辑是如何实现的:
    org.springframework.aop.aspectj.annotation包下的ReflectiveAspectJAdvisorFactory类中

     1 @Override
     2 public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
     3     // 获取标记为AspectJ的类
     4     Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
     5     // 获取标记为AspectJ的name
     6     String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
     7     // 验证
     8     validate(aspectClass);
     9 
    10     // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
    11     // so that it will only instantiate once.
    12     MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
    13             new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
    14 
    15     List<Advisor> advisors = new ArrayList<>();
    16     // getAdvisorMethods方法中利用反射来获取Advisor中所有的方法,spring中做了一部分处理
    17     for (Method method : getAdvisorMethods(aspectClass)) {
    18         Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
    19         if (advisor != null) {
    20             advisors.add(advisor);
    21         }
    22     }
    23 
    24     // If it's a per target aspect, emit the dummy instantiating aspect.
    25     if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
    26         // 如果寻找的增强器不为空而且又配置了增强延迟的初始化,那么需要在首位加入同步实例化增强器
    27         Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
    28         advisors.add(0, instantiationAdvisor);
    29     }
    30 
    31     // Find introduction fields.
    32     // 获取DeclareParents注解
    33     for (Field field : aspectClass.getDeclaredFields()) {
    34         Advisor advisor = getDeclareParentsAdvisor(field);
    35         if (advisor != null) {
    36             advisors.add(advisor);
    37         }
    38     }
    39 
    40     return advisors;
    41 }
    42 
    43 // getAdvisorMethods方法在spring5.0 中是封装到一个单独的方法中去了,作者书中的源码并没有进行封装
    44 private List<Method> getAdvisorMethods(Class<?> aspectClass) {
    45     final List<Method> methods = new ArrayList<>();
    46     ReflectionUtils.doWithMethods(aspectClass, method -> {
    47         // Exclude pointcuts
    48         // 声明为Pointcut的方法不处理
    49         if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
    50             methods.add(method);
    51         }
    52     });
    53     methods.sort(METHOD_COMPARATOR);
    54     return methods;
    55 }

    函数中首先完成了对增强器的获取,包括获取注解以及根据注解生成增强的步骤,然后考虑到在配置中可能会将增强配置成延迟初始化,那么需要在首位加入同步
    实例化增强器以保证增强使用之前的实例化,最后是对DeclareParents注解的获取

    (1)普通增强器的获取

    普通增强器的获取逻辑是通过getAdvisor方法实现的,实现步骤包括对切入的注解的获取以及根据注解信息生成增强

    org.springframework.aop.aspectj.annotation包下的ReflectiveAspectJAdvisorFactory类中

     1 @Override
     2 @Nullable
     3 public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
     4         int declarationOrderInAspect, String aspectName) {
     5 
     6     validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
     7 
     8     // 切点信息的获取
     9     AspectJExpressionPointcut expressionPointcut = getPointcut(
    10             candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    11     if (expressionPointcut == null) {
    12         return null;
    13     }
    14     // 根据切点信息生成增强器
    15     return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
    16             this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
    17 }

    1.1 切点信息的获取,这个就是指定注解的表达式信息的获取,如Befor("test()")
    org.springframework.aop.aspectj.annotation包下的ReflectiveAspectJAdvisorFactory类中

     1 @Nullable
     2 private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
     3     // 获取方法上的注解
     4     AspectJAnnotation<?> aspectJAnnotation =
     5             AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
     6     if (aspectJAnnotation == null) {
     7         return null;
     8     }
     9 
    10     // AspectJExpressionPointcut来封装获取到的信息
    11     AspectJExpressionPointcut ajexp =
    12             new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
    13     // 提取得到的注解中的表达式 如@Before("test()") 中的 test()
    14     ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
    15     if (this.beanFactory != null) {
    16         ajexp.setBeanFactory(this.beanFactory);
    17     }
    18     return ajexp;
    19 }

    org.springframework.aop.aspectj.annotation包下的ReflectiveAspectJAdvisorFactory类中

     1 @SuppressWarnings("unchecked")
     2 @Nullable
     3 protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
     4     // 设置敏感的注解类
     5     for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
     6         AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
     7         if (foundAnnotation != null) {
     8             return foundAnnotation;
     9         }
    10     }
    11     return null;
    12 }

    org.springframework.aop.aspectj.annotation包下的ReflectiveAspectJAdvisorFactory类中

     1 // 获取指定方法上的注解并使用AspectJAnnotation封装
     2 @Nullable
     3 private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
     4     A result = AnnotationUtils.findAnnotation(method, toLookFor);
     5     if (result != null) {
     6         return new AspectJAnnotation<>(result);
     7     }
     8     else {
     9         return null;
    10     }
    11 }

    1.2 根据切点信息生成增强,所有的增强都是由Advisor的实现类InstantiationModelAwarePointcutAdvisorImpl统一封装的

    org.springframework.aop.aspectj.annotation包下的InstantiationModelAwarePointcutAdvisorImpl类的构造方法

     1 public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
     2         Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
     3         MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
     4 
     5     this.declaredPointcut = declaredPointcut;
     6     this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
     7     this.methodName = aspectJAdviceMethod.getName();
     8     this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
     9     this.aspectJAdviceMethod = aspectJAdviceMethod;
    10     this.aspectJAdvisorFactory = aspectJAdvisorFactory;
    11     this.aspectInstanceFactory = aspectInstanceFactory;
    12     this.declarationOrder = declarationOrder;
    13     this.aspectName = aspectName;
    14 
    15     if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
    16         // Static part of the pointcut is a lazy type.
    17         Pointcut preInstantiationPointcut = Pointcuts.union(
    18                 aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
    19 
    20         // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
    21         // If it's not a dynamic pointcut, it may be optimized out
    22         // by the Spring AOP infrastructure after the first evaluation.
    23         this.pointcut = new PerTargetInstantiationModelPointcut(
    24                 this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
    25         this.lazy = true;
    26     }
    27     else {
    28         // A singleton aspect.
    29         this.pointcut = this.declaredPointcut;
    30         this.lazy = false;
    31         this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
    32     }
    33 }

    在封装过程中只是简单地将信息封装在类的实例中,所有的信息单纯的赋值,在实例初始化的过程中,还完成了对于增强器的初始化。因为不同的增强所体现的逻辑是不同的
    比如,@Before("test()")、@After("test()")标签的不同就是增强的位置不同,所以就需要不同的增强逻辑,而这部分逻辑实现是在instantiateAdvice方法中实现的

    org.springframework.aop.aspectj.annotation包下的InstantiationModelAwarePointcutAdvisorImpl类中

     1 private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
     2     Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
     3             this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
     4     return (advice != null ? advice : EMPTY_ADVICE);
     5 }
     6 
     7 // getAdvice方法的实现是在org.springframework.aop.aspectj.annotation包下的ReflectiveAspectJAdvisorFactory类中
     8 
     9 @Override
    10 @Nullable
    11 public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
    12         MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    13 
    14     Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    15     validate(candidateAspectClass);
    16 
    17     AspectJAnnotation<?> aspectJAnnotation =
    18             AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    19     if (aspectJAnnotation == null) {
    20         return null;
    21     }
    22 
    23     // If we get here, we know we have an AspectJ method.
    24     // Check that it's an AspectJ-annotated class
    25     if (!isAspect(candidateAspectClass)) {
    26         throw new AopConfigException("Advice must be declared inside an aspect type: " +
    27                 "Offending method '" + candidateAdviceMethod + "' in class [" +
    28                 candidateAspectClass.getName() + "]");
    29     }
    30 
    31     if (logger.isDebugEnabled()) {
    32         logger.debug("Found AspectJ method: " + candidateAdviceMethod);
    33     }
    34 
    35     AbstractAspectJAdvice springAdvice;
    36 
    37     // 根据不同的增强类型封装不同的增强器
    38     switch (aspectJAnnotation.getAnnotationType()) {
    39         case AtPointcut:
    40             if (logger.isDebugEnabled()) {
    41                 logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
    42             }
    43             return null;
    44         case AtAround:
    45             springAdvice = new AspectJAroundAdvice(
    46                     candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
    47             break;
    48         case AtBefore:
    49             springAdvice = new AspectJMethodBeforeAdvice(
    50                     candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
    51             break;
    52         case AtAfter:
    53             springAdvice = new AspectJAfterAdvice(
    54                     candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
    55             break;
    56         case AtAfterReturning:
    57             springAdvice = new AspectJAfterReturningAdvice(
    58                     candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
    59             AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
    60             if (StringUtils.hasText(afterReturningAnnotation.returning())) {
    61                 springAdvice.setReturningName(afterReturningAnnotation.returning());
    62             }
    63             break;
    64         case AtAfterThrowing:
    65             springAdvice = new AspectJAfterThrowingAdvice(
    66                     candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
    67             AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
    68             if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
    69                 springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
    70             }
    71             break;
    72         default:
    73             throw new UnsupportedOperationException(
    74                     "Unsupported advice type on method: " + candidateAdviceMethod);
    75     }
    76 
    77     // Now to configure the advice...
    78     springAdvice.setAspectName(aspectName);
    79     springAdvice.setDeclarationOrder(declarationOrder);
    80     String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
    81     if (argNames != null) {
    82         springAdvice.setArgumentNamesFromStringArray(argNames);
    83     }
    84     springAdvice.calculateArgumentBindings();
    85 
    86     return springAdvice;
    87 }

    spring会根据不同的注解生成不同的增强器,例如@Before对应的就是AspectJMethodBeforeAdvice增强器,这里有几个增强器的详解:

    第一个:MethodBeforeAdviceInterceptor,不知道为啥是这个,为什么不是AspectJMethodBeforeAdvice类
    org.springframework.aop.framework.adapter包下的MethodBeforeAdviceInterceptor类

     1 public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
     2 
     3     private final MethodBeforeAdvice advice;
     4 
     5 
     6     /**
     7      * Create a new MethodBeforeAdviceInterceptor for the given advice.
     8      * @param advice the MethodBeforeAdvice to wrap
     9      */
    10     public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
    11         Assert.notNull(advice, "Advice must not be null");
    12         this.advice = advice;
    13     }
    14 
    15 
    16     @Override
    17     public Object invoke(MethodInvocation mi) throws Throwable {
    18         this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    19         return mi.proceed();
    20     }
    21 
    22 }
    23 
    24 // 其中MethodBeforeAdvice属性代表着前置增强的AspectJMethodBeforeAdvice,跟踪before方法
    25 
    26 org.springframework.aop.aspectj包下的AspectJMethodBeforeAdvice方法
    27 @Override
    28 public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
    29     invokeAdviceMethod(getJoinPointMatch(), null, null);
    30 }
    31 
    32 protected Object invokeAdviceMethod(
    33         @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex)
    34         throws Throwable {
    35 
    36     return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
    37 }
    38 
    39 protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
    40     Object[] actualArgs = args;
    41     if (this.aspectJAdviceMethod.getParameterCount() == 0) {
    42         actualArgs = null;
    43     }
    44     try {
    45         ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
    46         // TODO AopUtils.invokeJoinpointUsingReflection 激活增强方法!终于可以使用增强的方法了
    47         return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
    48     }
    49     catch (IllegalArgumentException ex) {
    50         throw new AopInvocationException("Mismatch on arguments to advice method [" +
    51                 this.aspectJAdviceMethod + "]; pointcut expression [" +
    52                 this.pointcut.getPointcutExpression() + "]", ex);
    53     }
    54     catch (InvocationTargetException ex) {
    55         throw ex.getTargetException();
    56     }
    57 }
    58 // invokeAdviceMethodWithGivenArgs方法中的aspectJAdviceMethod正是对于前置增强的方法,在这里得到了调用

    第二个:AspectJAfterAdvice @After对应的增强器

    后置增强与前置增强有少许不一致的地方之前讲解的前置增强,大致的结构是在拦截器中放置MethodBeforeAdviceInterceptor,而在MethodBeforeAdviceInterceptor中放置了
    AspectJMethodBeforeAdvice,并在调用的invoke时首先串联调用,但是后置增强器却不一样,没有提供中间类,而是直接在拦截器中使用了中间的AspectJAfterAdvice
    org.springframework.aop.aspectj包下AspectJAfterAdvice类

     1 public class AspectJAfterAdvice extends AbstractAspectJAdvice
     2         implements MethodInterceptor, AfterAdvice, Serializable {
     3 
     4     public AspectJAfterAdvice(
     5             Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
     6 
     7         super(aspectJBeforeAdviceMethod, pointcut, aif);
     8     }
     9 
    10 
    11     @Override
    12     public Object invoke(MethodInvocation mi) throws Throwable {
    13         try {
    14             return mi.proceed();
    15         }
    16         finally {
    17             // 激活增强方法
    18             invokeAdviceMethod(getJoinPointMatch(), null, null);
    19         }
    20     }
    21 
    22     @Override
    23     public boolean isBeforeAdvice() {
    24         return false;
    25     }
    26 
    27     @Override
    28     public boolean isAfterAdvice() {
    29         return true;
    30     }
    31 
    32 }

    2、寻找匹配的增强器

    前面的方法中已经完成了所有增强器的解析,但是对于所有的增强器来说,并不一定都适用于当前的bean,还要挑出适合的增强器,也就是满足我们配置中通配符的增强器
    具体实现在下面的方法中 --> findAdvisorsThatCanApply()

    org.springframework.aop.framework.autoproxy包下的AbstractAdvisorAutoProxyCreator类中

     1 protected List<Advisor> findAdvisorsThatCanApply(
     2         List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
     3 
     4     ProxyCreationContext.setCurrentProxiedBeanName(beanName);
     5     try {
     6         // 过滤已经得到的advisors
     7         return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
     8     }
     9     finally {
    10         ProxyCreationContext.setCurrentProxiedBeanName(null);
    11     }
    12 }

    看一下findAdvisorsThatCanApply()源码,如何过滤?
    org.springframework.aop.support包下的AopUtils类中的findAdvisorsThatCanApply(List<Advisor>, Class<?>)方法

     1 public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
     2     if (candidateAdvisors.isEmpty()) {
     3         return candidateAdvisors;
     4     }
     5     List<Advisor> eligibleAdvisors = new ArrayList<>();
     6     // 首先处理引介增强
     7     for (Advisor candidate : candidateAdvisors) {
     8         if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
     9             eligibleAdvisors.add(candidate);
    10         }
    11     }
    12     boolean hasIntroductions = !eligibleAdvisors.isEmpty();
    13     for (Advisor candidate : candidateAdvisors) {
    14         // 引介增强已经处理
    15         if (candidate instanceof IntroductionAdvisor) {
    16             // already processed
    17             continue;
    18         }
    19         // 对于普通的bean的处理
    20         if (canApply(candidate, clazz, hasIntroductions)) {
    21             eligibleAdvisors.add(candidate);
    22         }
    23     }
    24     return eligibleAdvisors;
    25 }

    findAdvisorsThatCanApply方法主要的功能是寻找所有增强器中适用于当前class的增强器。引介增强处理和普通的增强处理是不一样的,分开处理,真正的匹配逻辑是在
    canApply()中的,看canApply的源码:

    org.springframework.aop.support包下的AopUtils类中的canApply方法

     1 public static boolean canApply(Advisor advisor, Class<?> targetClass) {
     2     return canApply(advisor, targetClass, false);
     3 }
     4 
     5 public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
     6     if (advisor instanceof IntroductionAdvisor) {
     7         return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
     8     }
     9     else if (advisor instanceof PointcutAdvisor) {
    10         PointcutAdvisor pca = (PointcutAdvisor) advisor;
    11         return canApply(pca.getPointcut(), targetClass, hasIntroductions);
    12     }
    13     else {
    14         // It doesn't have a pointcut so we assume it applies.
    15         return true;
    16     }
    17 }
    18 
    19 public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
    20     Assert.notNull(pc, "Pointcut must not be null");
    21     if (!pc.getClassFilter().matches(targetClass)) {
    22         return false;
    23     }
    24 
    25     MethodMatcher methodMatcher = pc.getMethodMatcher();
    26     if (methodMatcher == MethodMatcher.TRUE) {
    27         // No need to iterate the methods if we're matching any method anyway...
    28         return true;
    29     }
    30 
    31     IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
    32     if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
    33         introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
    34     }
    35 
    36     Set<Class<?>> classes = new LinkedHashSet<>();
    37     if (!Proxy.isProxyClass(targetClass)) {
    38         classes.add(ClassUtils.getUserClass(targetClass));
    39     }
    40     classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
    41 
    42     for (Class<?> clazz : classes) {
    43         Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
    44         for (Method method : methods) {
    45             if (introductionAwareMethodMatcher != null ?
    46                     introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
    47                     methodMatcher.matches(method, targetClass)) {
    48                 return true;
    49             }
    50         }
    51     }
    52     return false;
    53 }
  • 相关阅读:
    Linux 管道命令(pipe)
    SQLITE入门逐步讲解SQLITE命令行(二)
    用flash上传多个图片、文件的插件TinyBrowser
    PHP的时区问题GMT8
    解决Apache+PHP服务器提示HTTP 500问题
    SQLITE入门逐步讲解SQLITE命令行(四)
    SQLITE入门逐步讲解SQLITE命令行(五)
    linux tar命令使用范例
    SQLITE入门逐步讲解SQLITE命令行(六)
    Tinymce配置智能的Url
  • 原文地址:https://www.cnblogs.com/ssh-html/p/11296329.html
Copyright © 2011-2022 走看看