springspring

springAOP源码1

2021-09-20  本文已影响0人  念䋛

在介绍AOP之前先讲解一下advice和advisor,以及调用链
先从advice介绍
被代理的类

@Component
public class CalculateTest {
    public int add(int i, int j) {
        System.out.println ("加");
        return i + j;
    }

    public int subtract(int i, int j) {
        System.out.println ("减");
        return i - j;
    }

    public int multiply(int i, int j) {
        System.out.println ("乘");
        return i * j;
    }

    public int divide(int i, int j) {
        System.out.println ("除");
        return i / j;
    }
}

下面为两个advice 前后过滤器

public class LogAdviceAfter implements AfterReturningAdvice {

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        String methodName = method.getName();
        System.out.println("执行目标方法【"+methodName+"】的<后置通知>,入参"+ Arrays.asList(args)+"得到的结果"+returnValue);
    }
}
public class LogAdviceBefore implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        String methodName = method.getName();
        System.out.println("执行目标方法【"+methodName+"】的<前置通知>,入参"+ Arrays.asList(args));
    }
}

Interceptor拦截器

public class LogIntreceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println ("MethodInterceptor方法调用前");
        Object proceed = invocation.proceed ();
        System.out.println ("MethodInterceptor方法调用后");
        return proceed;
    }
}

配置类

@Configuration
@ComponentScan(basePackages = "springlearn.aspectjtest")
public class ConfigurationAspectJ {
  
    //以类为单位,不能精确到方法,而且多个类需要多个代理
    //在ioc,如果要使用代理那么bean的名称为proxyFactoryBean,bean名称为calculateTest是未代理的类
    //这里要注意的是CalculateTest不能是cglib代理之后的类,@Configuration是不可以的,可以使用@Component
 @Bean
public ProxyFactoryBean proxyFactoryBean(CalculateTest calculateTest ) {
    ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean ();
//可以指定advice也可以执行interecptor
    proxyFactoryBean.setInterceptorNames ("adviceBefore","logIntreceptor");
    proxyFactoryBean.setTarget (calculateTest);
    return proxyFactoryBean;
}
@Bean
    public LogAdviceBefore logAdviceBefore() {
        return new LogAdviceBefore ();
    }
    @Bean
    public LogAdviceAfter logAdviceAfter() {
        return new LogAdviceAfter ();
    }
@Bean
public LogIntreceptor logIntreceptor() {
    return new LogIntreceptor ();
}

}
public class Main {
    public static void main(String[] args) {
        //查找配置类.配置类有扫描类的路径,满足条件的放到容器中
        AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext (ConfigurationAspectJ.class);
//获取代理类,bean的名称为proxyFactoryBean,其实就是调用了FactoryBean的getObject方法
        CalculateTest calculateTestProxy = ( CalculateTest ) configApplicationContext.getBean ("proxyFactoryBean");
        int divide = calculateTestProxy.divide (4, 2);
        int add = calculateTestProxy.add (4, 2);
        configApplicationContext.close ();
    }
}

得到的结果


image.png

Advisor包含了advice和Pointcut,拦截方法和拦截方法做什么.
配置类

@Configuration
@ComponentScan(basePackages = "springlearn.aspectjtest")
public class ConfigurationAspectJ {

    //通知(advice):通知类,没有切点 举例:LogAdvice实现了MethodBeforeAdvice接口,切面为CalculateTest类的add和divide方法,LogAdvice会在执行add和divide方法前,执行LogAdvice的before方法,LogAdvice就是通知类
    //通知者(advisor):  包含了advice和切点,切点为方法名称,注意这里没有规定哪个类,类是在ProxyFactoryBean中定义的
    @Bean
    public NameMatchMethodPointcutAdvisor nameMatchMethodPointcutAdvisorBefore() {
        NameMatchMethodPointcutAdvisor nameMatchMethodPointcutAdvisor = new NameMatchMethodPointcutAdvisor ();
        nameMatchMethodPointcutAdvisor.setAdvice (logAdviceBefore ());
        nameMatchMethodPointcutAdvisor.setMappedNames ("divide", "add");
        return nameMatchMethodPointcutAdvisor;
    }

    @Bean
    public NameMatchMethodPointcutAdvisor nameMatchMethodPointcutAdvisorAfter() {
        NameMatchMethodPointcutAdvisor nameMatchMethodPointcutAdvisor = new NameMatchMethodPointcutAdvisor ();
        nameMatchMethodPointcutAdvisor.setAdvice (logAdviceAfter ());
        nameMatchMethodPointcutAdvisor.setMappedNames ("divide", "add");
        return nameMatchMethodPointcutAdvisor;
    }

    @Bean
    public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
        BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator ();
//以通配符的方式模糊匹配,这样就不用每个类写一个代理
        beanNameAutoProxyCreator.setBeanNames ("calculateTest*");
        //多个过滤器组成调用链
        beanNameAutoProxyCreator.setInterceptorNames ("nameMatchMethodPointcutAdvisorBefore", "nameMatchMethodPointcutAdvisorAfter");
        return beanNameAutoProxyCreator;
    }


    @Bean
    public LogAdviceBefore logAdviceBefore() {
        return new LogAdviceBefore ();
    }

    @Bean
    public LogAdviceAfter logAdviceAfter() {
        return new LogAdviceAfter ();
    }

    @Bean
    public LogIntreceptor logIntreceptor() {
        return new LogIntreceptor ();
    }
}

public class Main {
    public static void main(String[] args) {
        //查找配置类.配置类有扫描类的路径,满足条件的放到容器中
        AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext (ConfigurationAspectJ.class);
        //bean的名称为calculateTest,类的本身已经被代理了
        CalculateTest calculateTest = ( CalculateTest ) configApplicationContext.getBean ("calculateTest");
        int divide = calculateTest.divide (4, 2);
        int add = calculateTest.add (4, 2);
        configApplicationContext.close ();
    }
}
image.png

Advisor可以指定代理的方法和拦截器,多个Advisor形成了调用链,
BeanNameAutoProxyCreator通过名称的方式,将类和Advisor绑定在一起,名称可以使用*作为通配符,这样就可以匹配多个类.
上面讲解了advice和advisor,这样有助于理解AOP的源码.

下面分析AOP的源码,Spring在引入组件的是常用的一种是@EnableXXXX,下面就从
@EnableAspectJAutoProxy入手分析源码
@EnableAspectJAutoProxy的import注解
@Import(AspectJAutoProxyRegistrar.class)
AspectJAutoProxyRegistrar接口继承了ImportBeanDefinitionRegistrar
在springioc容器源码的时候分析过,继承ImportBeanDefinitionRegistrar会调用
registerBeanDefinitions方法
那么在AspectJAutoProxyRegistrar的registerBeanDefinitions方法中会调用
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
代码最终将AnnotationAwareAspectJAutoProxyCreator.class注册进beanDefinitionMap中
AnnotationAwareAspectJAutoProxyCreator类继承图
[图片上传失败...(image-4f9378-1632042893525)]
可以看到AnnotationAwareAspectJAutoProxyCreator继承了很多的Bean的后置处理器,
我们分析过bean的后置处理器的9处调用,AOP的advisor包装和创建cglib动态代理都是在bean的后置处理器中完成的

  1. InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation方法的调用.
    真正执行AnnotationAwareAspectJAutoProxyCreator#postProcessBeforeInstantiation
    其主要的作用是创建Advisor,并缓存起来
@Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
//缓存,不用重复的查找,第一次为空  

Object cacheKey = getCacheKey(beanClass, beanName);

 if (!StringUtils.*hasLength*(beanName) || !this.targetSourcedBeans.contains(beanName)) { if (this.advisedBeans.containsKey(cacheKey)) { return null; }

// advisedBeans成员变量,如果为false是不需要代理的,比如Advice的子类或者标注了@Aspect的类,本身是服务于代理类的,当然是不需要代理的

// isInfrastructureClass(beanClass)判断beanClass不是Advice,Pointcut,Advisor,AopInfrastructureBean类及子类,

//重点shouldSkip方法,获取beanDefinitionMap中关于AOP的类(Advice的实现类和标注了@Aspect注解的类),我们这里只关注了是标注@Aspect注解的类, shouldSkip下面会分析 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.*FALSE*);
 return null; }
 } // Create proxy here if we have a custom TargetSource.
 // Suppresses unnecessary default instantiation of the target bean:
 // The TargetSource will handle target instances in a custom fashion. TargetSource targetSource = getCustomTargetSource(beanClass, 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; }

shouldSkip方法中的findCandidateAdvisors()方法,寻找Advice的实现类和标注了@Aspect的类, findCandidateAdvisors()被重写了,那我们关注重写的方法
AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
super. findCandidateAdvisors寻找beanDefinitionMap中所有Advisor的子类
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());查找标注了@AsceptJ注解的类,并把所有找到的类包装为Advisor类,那我们就分析
this.aspectJAdvisorsBuilder.buildAspectJAdvisors()方法

public List<Advisor> buildAspectJAdvisors() {
//从缓存中获取标注了@Aspect的类
   List<String> aspectNames = this.aspectBeanNames;

   if (aspectNames == null) {
//线程安全,防止多线程加载@Aspect
      synchronized (this) {
         aspectNames = this.aspectBeanNames;
//单例模式中的双重校验,提高效率
         if (aspectNames == null) {
            List<Advisor> advisors = new ArrayList<>();
            aspectNames = new ArrayList<>();
//从bean定义Map中获取Object的子集,也就是获取所有的bean定义
            String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                  this.beanFactory, Object.class, true, false);
            for (String beanName : beanNames) {
               if (!isEligibleBean(beanName)) {
                  continue;
               }
               // We must be careful not to instantiate beans eagerly as in this case they
               // would be cached by the Spring container but would not have been weaved.
//获取类
               Class<?> beanType = this.beanFactory.getType(beanName, false);
               if (beanType == null) {
                  continue;
               }
//判断类是否标注了@Aspect注解
               if (this.advisorFactory.isAspect(beanType)) {
                  aspectNames.add(beanName);
                  AspectMetadata amd = new AspectMetadata(beanType, beanName);
                  if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                     MetadataAwareAspectInstanceFactory factory =
                           new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//将类中标注了Pointcut.class, Around.class, Before.class, After.class, //AfterReturning.class, AfterThrowing.class 注解的方法,经过组合,封装成
//InstantiationModelAwarePointcutAdvisorImpl的实例集合
//每个InstantiationModelAwarePointcutAdvisorImpl包含Advice和PointCut
//方法不跟进去了,主要脉络是首先找到除标注@Pointcut注解的方法,再去掉Object自带
//方法(equal,hashCode,notify等),包装为Advisor
                     List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                     if (this.beanFactory.isSingleton(beanName)) {
//将Advisor缓存起来,key为bean的名称,这里是所有类的产出的Advisor缓存起来
                        this.advisorsCache.put(beanName, classAdvisors);
                     }
                     else {
                        this.aspectFactoryCache.put(beanName, factory);
                     }
                     advisors.addAll(classAdvisors);
                  }
                  else {
                     // Per target or per this.
                     if (this.beanFactory.isSingleton(beanName)) {
                        throw new IllegalArgumentException("Bean with name '" + beanName +
                              "' is a singleton, but aspect instantiation model is not singleton");
                     }
                     MetadataAwareAspectInstanceFactory factory =
                           new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                     this.aspectFactoryCache.put(beanName, factory);
                     advisors.addAll(this.advisorFactory.getAdvisors(factory));
                  }
               }
            }
            this.aspectBeanNames = aspectNames;
            return advisors;
         }
      }
   }
//将得到的InstantiationModelAwarePointcutAdvisor存放到缓存中
   if (aspectNames.isEmpty()) {
      return Collections.emptyList();
   }
   List<Advisor> advisors = new ArrayList<>();
   for (String aspectName : aspectNames) {
      List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
      if (cachedAdvisors != null) {
         advisors.addAll(cachedAdvisors);
      }
      else {
         MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
         advisors.addAll(this.advisorFactory.getAdvisors(factory));
      }
   }
   return advisors;
}

shouldSkip方法在判断类是否需要跳过(跳过就是map中的value为false不需要代理的意思)的同时,找到@Aspect和Advice的子类,并存放到缓存中

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;
}
  1. BeanPostProcessor# postProcessorsAfterInitialization后置处理器
    真正执行的是AbstractAutoProxyCreator#postProcessorsAfterInitialization
    其主要作用遍历bean定义,与Advisor匹配,如果匹配成功则创建动态代理
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (this.earlyProxyReferences.remove(cacheKey) != bean) {
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}

warpIfNecessary是重要方法

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.
//如果类中只要有一个方法满足了Advisor,这该类需要代理,下面会分析到
   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;
}

调用的是AbstractAdvisorAutoProxyCreator重写的方法
AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
继续调用List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
下面为findEligibleAdvisors方法

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
   //获取所有的Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//判断类是否满足AspectJ的切点表达式,主要分两步初步筛选和精确筛选
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
//添加了自带的Advisor
   extendAdvisors(eligibleAdvisors);
//进行排序,如果beanClass满足了两个AspectJ标注的类,比如都有@Before,那用@Order
//来判断前后,是一种包裹的关系 比如  before1前置  before2 前置 after2后置 
//after1后置 1把2包裹起来
   if (!eligibleAdvisors.isEmpty()) {
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
}

当beanClass匹配至少一个Advisor就可以创建代理了
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new
SingletonTargetSource(bean));
createProxy创建代理类后续继续分析

上一篇 下一篇

猜你喜欢

热点阅读