Spring的AOP流程

        一种技术的诞生,主要是思维模式的改变,有C的 面向过程,到C++/java的面向对象,到面向类,面向方法编程的AOP,最后到面向服务编程的微服务。
        Spring的优秀设计之一就是AOP,通过一个注解就可以实现对某个方法的执行前后的功能增强。面向切面编程,提供另外一个角度来思考程序的结构,是一种编程思想,程序模块化思维,找出多个模块或者方法之间有一定规律的代码,开发时将其拆开,运行时将其再合并,解决了面向对象编程的不足。
 

1、AOP基本概念

  • (1). A spect 【切面】:通常是一个类,里面可以定义切入点和通知;
  • (2). JointPoint 【连接点】:程序执行过程中明确的点,一般是方法的调用;
  • (3). Advice 【通知】:AOP在特定的切入点上执行的增强的处理,有before/after/around/afterRetuing/afterThrowing;
  • (4). PointCut (切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式。
  • (5). Excution 表达式:定义切入点规则,多个方法形成一个切面;
 
AOP之Execution表达式解释
例:execution(* *.*(..))
  • 第一个*:代表的是方法返回的类型
  • 第二个*: 代表扫描的包路径;
  • 第三个*:包路径下的方法名,(..)代表方法的参数;
例如:
@Around("@annotation(com.king..LogAspect)")                                 //容器中加了LogAspect注解的类才拦截;
@Before("execution(public int com.king.aop.Calc.div(int,int))")             //拦截div(intent)方法,返回参数是int;
@Before("execution(public int com.king.aop.Calc.*(..))")                    //拦截包下的所有的方法;
@Around("execution(public int com.king.aop.Calc.*(..)) && @annotation(log)")  //将注解 DoSomething作为一个参数传递进来

2、AOP应用场景

  • Spring中各种注解功能的实现,例如事务@Transactional/@Async/@Aspect等等太多,使业务和功能代码解耦,进行无侵入性的代码增强;
  • 统一请求、参数校验,日志和异常处理;
  • 权限验证,数据源的切换等等;
    主要作用:将业务和非业务功能代码分离,提高代码的复用性,使代码逻辑简单可读,让开发人员能更好的专注于业务开发而不是非业务技术代码;

3、AOP的实践

实例演示:切面类
@Component
@Aspect
public class LogAspect {

    //抽取公共切入点表达式
    //1 如果是该应用内,只需要@Before("pointCut()")
    //2 如果是其他切面类需要引用,需要写上切面类的路径和方法
    @Pointcut("execution(public int com.king.aop.Calc.*(..))")
    public void pointCut() {
    }

    @Before("execution(public int com.king.aop.Calc.div(int,int))")
    public void logStart(JoinPoint joinPoint) {
        System.out.println("Before 除法运行开始,方法名:" + joinPoint.getSignature().getName() + "  参数列表: {" +
                Arrays.asList(joinPoint.getArgs()) + "}");

    }

    @After("pointCut()")
    public void logEnd() {
        System.out.println("After 除法运行结束。。。。");

    }

    @AfterReturning(value = "com.king.aop.LogAspect.pointCut()", returning = "result")
    public void logReturn(Object result) {
        System.out.println("AfterReturning  除法正常返回,结果为:" + result);

    }
        //测试分母为0的异常情况
    @AfterThrowing(value = "pointCut()", throwing = "exception")
    public void logAfterThrowing(Exception exception) {
        System.out.println("AfterThrowing 除法运算异常 " + exception);

    }

    @Around(value = "pointCut() && @annotation(logAnnotation)  ")
    public Object logAround(ProceedingJoinPoint proceedingJoinPoint,BaseLog logAnnotation) {
        System.out.println("logAround 执行目标方法之前: ");
        try {//这里必须手动调用
            Object obj = proceedingJoinPoint.proceed();
            System.out.println("logAround 目标方法执行之后: ");
            return obj;

        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

        return -1;

    }
}

切面注解

解析注解的类信息:
注解分为 3 类:
@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface BaseLog {
}
  • 一类是 java 自带的标准注解:包括常用的@Controller @Service @Repository
  • 二类是元注解,元注解是用于定义注解的注解,包括
    • @Retention(表明注解被保留的阶段) 源代码-编译器 - 运行期 什么作用范围,生命周期?
    • @targe(标明注解使用的范围) 什么范围使用?
    • @Inherited(标明注解可继承) 能否被继承?
    • @Documented(标明是否生成javadoc文档) 是否包含在javadoc中? 
  • 三类是自定义注解,根据自己的定义需求注解
注解的作用域:
  • source:存在java代码级别,编译为class就无效了;  @Override,格式检查,是否覆盖实现了接口的方法
  • class:编译期级别,帮我们生成get和set方法; lambook @Data
  • Runtime类型:运行期间产生作用 @Service,很常见

拦截方法

public class Calc {
    //业务逻辑
    @BaseLog
    public int div(int i, int j) {
        
        return i / j;
    }
}

配置类

@Configuration
@EnableAspectJAutoProxy
public class ConfigAop {

    @Bean
    public Calc getCalc(){
        return new Calc();
    }

    @Bean
    public LogAspect getAspect(){
        return new LogAspect();
    }

}

测试类:

@Test
public void aopTest() {
    AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(com.aop.ConfigAop.class);
    Calc calc = app.getBean(Calc.class);
    System.out.println("result: "+ calc.div(8, 2));
}

正常运行结果8/2:

logAround 执行目标方法之前:
Before 除法运行开始,方法名:div  参数列表: {[8, 2]}
div running
logAround 目标方法执行之后:
After 除法运行结束。。。。
AfterReturning  除法正常返回,结果为:4
result: 4

异常运行:输入2/0的结果:

logAround 执行目标方法之前:
Before 除法运行开始,方法名:div  参数列表: {[2, 0]}
div running
java.lang.ArithmeticException: / by zero
    at com.enjoy.aop.aop.Calc.div(Calc.java:15)
After 除法运行结束。。。。
AfterReturning  除法正常返回,结果为:-1
reslut: -1

通过调试,你会发现Calc是经过增强的Bean,它其实变成了一个实现了Advised接口的代理类,并不是原生的Calc类,所以才会运行自己编写的切面类。

4、AOP 切面执行顺序分析

从上面的例子可以看出,AOP执行顺序:
try
{
     1、 环绕前置通知;@Around 
     2、 前置通知;   @Before      
     3、 执行目标方法; method.invoke()
     4、 环绕后置通知;@Around
     5、 执行返回通知;@After
}catche(Exception e){
     5.1、执行异常通知;@AfterThrowing  没有异常不打印,有异常替换@After
}finally{
     6、执行后置通知;@AfterReturning
}

AOP的执行流程图如下:

思考:如果同一个方法被两个Aspect所拦截,那么它们的先后顺序怎么确定呢,关系会根据调用顺序嵌套执行?
[Aspect-1] logAround 执行目标方法之前:
[Aspect-1] Before 除法运行开始:div  参数列表: {[8, 2]}

[Aspect-2] logAround 执行目标方法之前:
[Aspect-2] Before 除法运行开始:div  参数列表: {[8, 2]}
Ok
[Aspect-2] logAround 目标方法执行之后:
[Aspect-2] After 除法运行结束。。。。
[Aspect-2] AfterReturning  除法正常返回,结果为:4

[Aspect-1] logAround 目标方法执行之后:
[Aspect-1] After 除法运行结束。。。。
[Aspect-1] AfterReturning  除法正常返回,结果为:4

如果要确定两个切面的执行顺序,可以给aspect添加@Order注解,值越小优先级越高。

@Order(1)
@Component
@Aspect
public class ParamCheckAspect1 {
    // ...
}


@Order(2)
@Component
@Aspect
public class LogAspect2 {
    // ...
}

这样就先执行参数校验的切面ParamCheckAspect1,然后执行日志打印的切面拦截LogAspect2,控制了其执行顺序。

5、AOP使用注意事项

1、要使用 spring的AOP功能一定要对代理的对象进行增强,否则注解就会失效,例如事务的本地的this调用,没有增强就会失效;例如执行如下:
@Test
public void aopTest() {
    AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(com.aop.ConfigAop.class);
    Calc calc = new Calc();
    System.out.println("result: "+ calc.div(8, 2)); //这时候日志的切面是不生效的,没有被spring代理,没有增强;
}

2、Final方法不能被通知,因为它final不能被重写,动态代理的CGlib不能重写final方法;

3、对于@Around这个注解,不管它有没有返回值,内部都必须要调用一下pjp.proceed(),否则目标方法将不会执行,也就是@Before无法执行;如果我们去掉这个执行方法,运行结果如下:

注释掉://Object obj = proceedingJoinPoint.proceed();

@Before和目标方法不会执行,运行结果:
logAround 执行目标方法之前:
logAround 目标方法执行之后:
After 除法运行结束。。。。
AfterReturning  除法正常返回,结果为:-1
reslut: -1

可以看到,结果打印没有方法的执行。

 

6、AOP的设计思想

核心思路就是: @EnableAspectJAutoProxy开启aop功能;
  • 第一步:首先创建AOP后置处理器- AnnotationAwareAspectJAutoProxyCreator,加工增强我们的bean;因为它要对业务bean的创建进行拦截,必须先创建;
  • 第二步:然后再创建剩余的单实例bean,业务bean;
  • 第三步:接着在创建单实例业务bean进行初始化的时候,通过后置处理器postProcessor就会对其做增强;
  • 第四步:通过动态代理的到一个增强的代理对象;
  • 第五步:通过代理对象来执行目标方法 CglibAopProxy. intercept() + proceed();
    • (1) 得到目标方法的拦截器链(增强器包装成拦截器 MethodInterceptor );
    • (2) 利用拦截器链式机制,一次进入每一个拦截器进行执行;
    • (3) 执行结果顺序:
      • 正常执行:环绕前置通知AroundBefore -> 前置通知Before-> 环绕后置通知AroundAfter  -> 目标方法invoke()  -> 后置通知After  -> 返回通知 AfterReturning
      • 异常执行:环绕前置通知 AroundBefore -> 前置通知 Before -> 环绕后置通知 AroundAfter  -> 目标方法 invoke() -> 异常通知 AfterThrowing

7、源码解析

一切从入口开启AOP的注解开始:
@Configuration
@EnableAspectJAutoProxy
public class ConfigAop {
    @Bean
    public Calc getCalc(){
        return new Calc();
    }
    @Bean
    public LogAspect getAspect(){
        return new LogAspect();
    }

}

7.1、后置处理器AnnotationAwareAspectJAutoProxyCreator的创建

查看EnableAspectJAutoProxy源码实现:
@Target(ElementType.TYPE)           //在什么地方使用?方法/类/字段
@Retention(RetentionPolicy.RUNTIME) //什么时间生效?class文件 @override- - 编译期间 lambook- 运行期间
@Documented                         //是否加入到javaDoc中
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
   
   //判断是用jdk还是CGLib动态代理
   boolean proxyTargetClass() default false;
   
   //是否暴露aop动态代理,在同类中动态代理的方法调用的时候就需要用到它;
   boolean exposeProxy() default false;

}

继续查看AspectAutoProxyRegistrar源码,发现其通过ImportBeanDefinitionRegistrar向容器中注入了一个十分重要的组件:AnnotationAwareAspectJAutoProxyCreator.class,它贯穿了整个aop的全过程;

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);
      AnnotationAttributes enableAspectJAutoProxy =
            AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
      if (enableAspectJAutoProxy != null) {
         if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
         }
         if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
            AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
         }
      }
   }

}@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
      BeanDefinitionRegistry registry, @Nullable Object source) {
        //开始向容器中注入组件:AnnotationAwareAspectJAutoProxyCreator
   return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
看一下AnnotationAwareAspectJAutoProxyCreator的作用?
这里先看一下它的继承关系:
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
    public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
        public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
            public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
                      implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {

从这里可以看出,它是一个后置处理器;主要关注我们的bean初始化的前后需要做的事情,自动装配BeanFactory

BeanFactory : Spring容器的顶层接口,实现Bean的创建,获取,生命周期的管理等等;
SmartInstantiationAwareBeanPostProcessor :Bean的后置处理器,也是一个很重要的组件,主要用来对业务方法进行Bean的代理增强;
 

7.2、增强业务Bean的创建

思考:如何用后置处理器和动态代理来生成我们增强的bean实例呢?
重点分析div()方法是如何跟AnnotationAwareAspectJAutoProxyCreator相结合的。
public class Calc {
    //业务逻辑
    @BaseLog
    public int div(int i, int j) {
        return i / j;
    }
}

一切从容器的启动refresh开始:

@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Prepare the bean factory for use in this context.
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         postProcessBeanFactory(beanFactory);

         // Invoke factory processors registered as beans in the context.
         //调用所有注册的BeanFactoryPostProcessor的Bean定义信息,但是未创建未初始化;
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         //BeanPostProcessor是Bean后置处理器的创建,用于监听容器触发的事件aop相关bean的创建,aop相关的bean就是在这里注册创建实例化;
         //AnnotationAwareAspectJAutoProxyCreator.class就是在这里创建实例化;
         registerBeanPostProcessors(beanFactory);

         // Check for listener beans and register them.
         registerListeners();

         // Instantiate all remaining (non-lazy-init) singletons.
         //相关业务bean的创建,也就是计算类calc类的创建
         finishBeanFactoryInitialization(beanFactory);

         // Last step: publish corresponding event.
         finishRefresh();
      }
创建剩余的保留的单实例bean:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
   // Initialize conversion service for this context.
   if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
         beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(
            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
   }

   // Instantiate all remaining (non-lazy-init) singletons.
   beanFactory.preInstantiateSingletons();
}

继续初始化bean:

@Override
public void preInstantiateSingletons() throws BeansException {

    String FACTORY_BEAN_PREFIX = "&";

   //得到所有的bean的名字
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

   // Trigger initialization of all non-lazy singleton beans...
   for (String beanName : beanNames) {
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
         if (isFactoryBean(beanName)) {
            Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            if (bean instanceof FactoryBean) {
               final FactoryBean<?> factory = (FactoryBean<?>) bean;
               boolean isEagerInit;
               if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                  isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                              ((SmartFactoryBean<?>) factory)::isEagerInit,
                        getAccessControlContext());
               }
               else {
                  isEagerInit = (factory instanceof SmartFactoryBean &&
                        ((SmartFactoryBean<?>) factory).isEagerInit());
               }
               if (isEagerInit) {
                  getBean(beanName);
               }
            }
         }
         else {//循环获取这个bean
            getBean(beanName);
         }
      }
   }
继续getBean():
@Override
public Object getBean(String name) throws BeansException {
   return doGetBean(name, null, null, false);
}

这里主要关注 Calculator的创建,是如何增强的?

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

   final String beanName = transformedBeanName(name);
   Object bean;

   // Eagerly check singleton cache for manually registered singletons.
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
        // Create bean instance. //创建bean实例
        if (mbd.isSingleton()) {
            //第一次根据bean name去拿单实例bean,肯定没有
           sharedInstance = getSingleton(beanName, () -> {
              try {//创建bean实例
                     return createBean(beanName, mbd, args);
                  }
           }

获取calculator的bean,并判断有无增强处理:

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {

   try {
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
     //给个机会返回代理类对象;
     //对bean的前置处理器,遍历出所有的postProcessBean;
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        //第一步:创建一个单实例bean;普通的实例bean
      if (bean != null) {
         return bean;
      }
   }    
    try { //第二步:后置处理器返回一个动态代理
       Object beanInstance = doCreateBean(beanName, mbdToUse, args);
       if (logger.isTraceEnabled()) {
          logger.trace("Finished creating instance of bean '" + beanName + "'");
       }
       return beanInstance;
}

@Nullable  //初始化之前判断是否有后置处理器的增强;
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
   Object bean = null;
   if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
      // Make sure bean class is actually resolved at this point.
        //判断该bean Calcutor是否是实现了BeanPostProcessor,显然满足条件是一个后置处理,加了aop的功能
      if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
         Class<?> targetType = determineTargetType(beanName, mbd);
         if (targetType != null) {
            //前置处理器
            bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
            if (bean != null) { 
            //后置处理器
               bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
            }
         }
      }
      mbd.beforeInstantiationResolved = (bean != null);
   }
   return bean;
}


// 找到Calcutor的后置处理器 AnnotationAwareAspectJAutoProxyCreator 进行增强;
//前置处理器主要是 拿到@Aspect中的所有切面方法
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    //拿到bean的名字,cachekey ==Calcutor 
   Object cacheKey = getCacheKey(beanClass, beanName);
   TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
   if (targetSource != null) {
      if (StringUtils.hasLength(beanName)) {
         this.targetSourcedBeans.add(beanName);
      }
       //找到 Calcutor 的增强器,主要是拦截的4个切面类
      Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
      Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
      this.proxyTypes.put(cacheKey, proxy.getClass());
      return proxy; //至此-返回一个代理对象,但是before不会产生任何代理
   }

}

//找 Calcutor的增强器
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
        //获取合适的增强器,就是我们编写的before - after - around的切面类
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
   extendAdvisors(eligibleAdvisors);
   if (!eligibleAdvisors.isEmpty()) {
        //对增强器进行排序,因为方法调用是有时机顺序的,前面也提到验证过,before-after-return
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
}

通过反射创建一个增强的代理bean,最后生成的这个Bean就是加入切面类增强的Bean。

*/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {

   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }    // 第一步:通过反射创建bean
   if (instanceWrapper == null) {
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
    Object exposedObject = bean;
    try {
       //第二步:给实例bean赋值
       populateBean(beanName, mbd, instanceWrapper);
       //第三步:给bean初始化
       exposedObject = initializeBean(beanName, exposedObject, mbd);
    }

进入到后置处理器:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {

   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {//初始化前置处理器
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   try { //调用方法
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }
   if (mbd == null || !mbd.isSynthetic()) {//初始化后置处理器
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }

   return wrappedBean;
}

进入后置处理器,后置处理器的作用:

  • 拿到所有的通知方法;
  • 创建增强的动态代理对象;Calcutor对象;
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   if (bean != null) {
      //从缓存中拿到bean的名字
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (!this.earlyProxyReferences.contains(cacheKey)) {
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}

如果对象有增强,找到增强器,因为切面类不是实现的接口,所以开始通过Cglib创建代理对象:

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

   // Create proxy if we have advice. //先获取排好序的通知类bean,创建增强代理对象
   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;
}
//创建动态代理类,创建aop增强bean的创建
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

   @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)) {
            //方式一:如果有接口,就使用 jdk动态代理;
            return new JdkDynamicAopProxy(config);
         }
            //方式二:如果没有接口,就使用CGLib动态代理
         return new ObjenesisCglibAopProxy(config);
      }
      else {
         return new JdkDynamicAopProxy(config);
      }
   }

}

至此,我们的增强bean Calc就创建完成了。

7.3、调用执行阶段

此时调用会调用动态代理增强的实例bean,所以进入拦截方法,注意如果不是从容器获取的增强的bean是aop是无效的。
进入拦截类方法: CglibAopProxy.interceptor();
//通过cglib创建动态代理类,获取相关的切面拦截方法
class CglibAopProxy implements AopProxy, Serializable {

   // Constants for CGLIB callback array indices
   private static final int AOP_PROXY = 0;
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
   Object oldProxy = null;
   boolean setProxyContext = false;
   Object target = null;
    //第一步:拿到我们的目标类:calculator类;
   TargetSource targetSource = this.advised.getTargetSource();
   try {//暴露动态代理,同类里调用事务注解失效就是在这里设置解决的;
      if (this.advised.exposeProxy) {
         // Make invocation available if necessary.
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      }
      // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
      target = targetSource.getTarget();
      Class<?> targetClass = (target != null ? target.getClass() : null);
        //第二步:拿到拦截链
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      Object retVal;
      // Check whether we only have one InvokerInterceptor: that is,
      // no real advice, but just reflective invocation of the target.
      if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = methodProxy.invoke(target, argsToUse);
      }
      else {
         // We need to create a method invocation… 
         //第三步:调用具体的方法,around的时候需要手动的调用我们的方法,proceed()就是调用方法本身;
         retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
      }
      retVal = processReturnType(proxy, target, method, retVal);
      return retVal;
   }
   finally {
      if (target != null && !targetSource.isStatic()) {
         targetSource.releaseTarget(target);
      }
      if (setProxyContext) {
         // Restore old proxy.
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

获取拦截链的拦截通知方法,也就是Aspect中写的拦截方法,这里获取到:


@Override//拿到所有的通知方法
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
      Advised config, Method method, @Nullable Class<?> targetClass) {

   // This is somewhat tricky... We have to process introductions first,
   // but we need to preserve order in the ultimate list.
   AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
   Advisor[] advisors = config.getAdvisors();
    //第一步:拿到通知方法的长度
   List<Object> interceptorList = new ArrayList<>(advisors.length);
   Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
   Boolean hasIntroductions = null;

   for (Advisor advisor : advisors) {
      if (advisor instanceof PointcutAdvisor) {
         // Add it conditionally.
            if (mm instanceof IntroductionAwareMethodMatcher) {
               if (hasIntroductions == null) {
                  hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
               }
            if (match) {
                //第二步:将Inteceptor转换为MethodInterceptor
               MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
               if (mm.isRuntime()) {
                  // Creating a new object instance in the getInterceptors() method
                  // isn't a problem as we normally cache created chains.
                  for (MethodInterceptor interceptor : interceptors) {
                     interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                  }
               }


   return interceptorList; 
}
 
栈式调用我们具体通知方法:
@Override
@Nullable
public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
    //第一步:通过i++来取我们的通知拦截方法
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }

   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // Evaluate dynamic method matcher here: static part will already have
      // been evaluated and found to match.
      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 {
         // Dynamic matching failed.
         // Skip this interceptor and invoke the next in the chain.
         return proceed();
      }
   }
   else {
      // It's an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
      //第二步:栈式方法调用
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

     到此,我们创建和执行阶段就完全解析完了。虽然搞了好久,不过好似打通了任督二脉,舒坦。

8、小结

        其实Spring中放眼望去,大部分都是基于注解实现的功能,例如@Transactional/@Async/@Controller/@Component/@Service@/Respositoy等等,其设计思路和aop的实现的思路大致一样,都是遵循同样的套路。
AOP注解切面编程的实现套路:
  • 第一步:通过@Enablexxxx来为容器中先注册一个有关功能的代理创建器@xxxAutoProxyCreator,一般这个处理器会实现我们的后置处理器接口postProcessor;
  • 第二步:实例化我们的业务bean,通过后置处理器postProcessor在bean初始化后的afterInitialized对bean进行增强;通过动态代理创建增强bean注入到容器;
  • 第三步:通过动态代理调用我们的增强的bean代理对像,实现增强的业务功能;
 
 
水滴石穿,积少成多。学习笔记,内容简单,用于复习,梳理巩固。
 
 
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值