解析Spring Boot的AOP原理

10 篇文章 1 订阅

目录

一、概述

二、示例

三、Spring AOP如何进行初始化?

1.添加@EnableAspectJAutoProxy注解

2.IOC容器初始化,执行refresh()方法

3.执行registerBeanPostProcessor()

4.执行finishBeanFactoryInitialization(beanFactory)

4.1. 情况一:如果此时的bean是切面类(标注@Aspect)。

4.2. 情况二:此时的bean是需要被切的类(即@Pointcut("a.b.c")中a.b.c覆盖到的类)

四、Spring AOP是如何起作用的?

五、总结


一、概述

AOP(Aspect-Oriented Programming) 面向切面编程。Spring Aop是Spring三大核心思想之一,其应用场景化非常多,比如日志、事务、安全、缓存等功能。分析Spring AOP之前,建议先提前了解下什么是spring容器和容器初始化,这样对以下的Spring AOP的分析更有帮助。 Spring AOP的原理,简单的说,可以从两个方面着手,即Spring AOP如何进行初始化?Spring AOP是如何起作用的?围绕这两点,我们展开分析,首先举个简单的例子,这样对分析更具有实质性,也更容易理解。

二、示例

以下使用的spring Boot版本为:2.3.5.RELEASE

/**
 * spring boot启动类
 * 添加@EnableAspectJAutoProxy注解,它提供了spring aop初始化的核心功能
 */
@SpringBootApplication
@EnableAspectJAutoProxy
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }
​
}
/**
 *  切面类
 **/
@Aspect
@Component
public class LogAspects {
​
    //抽取公共的切入点表达式
    @Pointcut("execution(public Integer com.micro.provider.service.UserService.*(..))")
    public void pointCut(){};
​
    @Before("pointCut()")
    public void logStart(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+ Arrays.asList(args)+"}");
    }
​
    @After("pointCut()")
    public void logEnd(JoinPoint joinPoint){
        System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");
    }
​
    //JoinPoint一定要出现在参数表的第一位
    @AfterReturning(value="pointCut()",returning="result")
    public void logReturn(JoinPoint joinPoint,Object result){
        System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
    }
​
    @AfterThrowing(value="pointCut()",throwing="exception")
    public void logException(JoinPoint joinPoint,Exception exception){
        System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");
    }
}
/**
 * 应用切面类的接口
 */
public interface UserService {
​
    /**
     * 加法运算
     * @param x
     * @param y
     * @return
     */
    Integer add(Integer x,Integer y);
}
/**
 * 接口实现类
 */
@Service
public class UserServiceImpl implements UserService {
​
    @Override
    public Integer add(Integer x, Integer y) {
        if(x==null||y==null){
            throw  new NullPointerException("参数不能为空");
        }
        return x+y;
    }
}
/**
 * 访问入口
 */
@Controller
@RequestMapping("/user")
public class UserController {
​
    @Autowired
    private UserService userService;
​
    @ResponseBody
    @RequestMapping("/testaop")
    public Integer testaop(Integer x,Integer y){
        Integer result = userService.add(x, y);
        return result;
    }
}

访问http://localhost:8081/cloud-provider/user/testaop?x=1&&y=2之后,返回结果如下:

add运行。。。@Before:参数列表是:{[1, 2]}
add正常返回。。。@AfterReturning:运行结果:{3}
add结束。。。@After

可以看出切面类被应用到了,这个结果是怎么得出的呢,来我们具体分析下。

三、Spring AOP如何进行初始化?

Spring AOP如何进行初始化,它的初始化步骤分为以下几点。

1.添加@EnableAspectJAutoProxy注解

如上面的示例,在启动类添加@EnableAspectJAutoProxy注解,看下他的内部实现。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false;
​
    boolean exposeProxy() default false;
}
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    ...
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
        ...
    }
}
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
    return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, (Object)null);
}
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
    return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
        ...
    } else {
        RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
        beanDefinition.setSource(source);
        beanDefinition.getPropertyValues().add("order", -2147483648);
        beanDefinition.setRole(2);
        registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
        return beanDefinition;
    }
}

其本质就是往bean定义注册表中注册AnnotationAwareAspectJAutoProxyCreator类,该类是个后置处理器,继承关系为AnnotationAwareAspectJAutoProxyCreator->AspectJAwareAdvisorAutoProxyCreator->AbstractAdvisorAutoProxyCreator->AbstractAutoProxyCreator->SmartInstantiationAwareBeanPostProcessor->InstantiationAwareBeanPostProcessor->BeanPostProcessor。

AbstractAutoProxyCreator里面实现了识别切面类、应用切面类以及创建代理对象的逻辑。

InstantiationAwareBeanPostProcessor是一个后置处理器,它的作用就是使IOC容器初始化的时候可以应用到AbstractAutoProxyCreator里面的逻辑,完成spring aop的初始化工作。

2.IOC容器初始化,执行refresh()方法

public void refresh() throws BeansException, IllegalStateException {
   // 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
   synchronized (this.startupShutdownMonitor) {
 
      // 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
      prepareRefresh();
 
      // 这步比较关键,这步完成后,配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中,
      // 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了,
      // 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 Map)
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 
      // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
      // 这块待会会展开说
      prepareBeanFactory(beanFactory);
 
      try {
         // 【这里需要知道 BeanFactoryPostProcessor 这个知识点,Bean 如果实现了此接口,
         // 那么在容器初始化以后,Spring 会负责调用里面的 postProcessBeanFactory 方法。】
 
         // 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化
         // 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事
         postProcessBeanFactory(beanFactory);
         // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
         invokeBeanFactoryPostProcessors(beanFactory);
 
         // 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
         // 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
         // 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化
         registerBeanPostProcessors(beanFactory);
 
         // 初始化当前 ApplicationContext 的 MessageSource,国际化这里就不展开说了,不然没完没了了
         initMessageSource();
 
         // 初始化当前 ApplicationContext 的事件广播器,这里也不展开了
         initApplicationEventMulticaster();
 
         // 从方法名就可以知道,典型的模板方法(钩子方法),
         // 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
         onRefresh();
 
         // 注册事件监听器,监听器需要实现 ApplicationListener 接口。这也不是我们的重点,过
         registerListeners();
 
         // 重点,重点,重点
         // 初始化所有的 singleton beans,并将它们放入Spring容器的缓存中(缓存底层为ConcurrentHashMap结构)
         //(lazy-init 的除外)
         finishBeanFactoryInitialization(beanFactory);
 
         // 最后,广播事件,ApplicationContext 初始化完成
         finishRefresh();
      }
 
      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }
 
         // Destroy already created singletons to avoid dangling resources.
         // 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
         destroyBeans();
 
         // Reset 'active' flag.
         cancelRefresh(ex);
 
         // 把异常往外抛
         throw ex;
      }
 
      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
      }
   }
}

这里我们重点关注与aop初始化关联的主要逻辑,registerBeanPostProcessor和finishBeanFactoryInitialization。

3.执行registerBeanPostProcessor()

注册后置处理器(只是创建了这个对象:AnnotationAwareAspectJAutoProxyCreator)

<!-- ===========================以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程=================================== -->

4.执行finishBeanFactoryInitialization(beanFactory)

循环实例化所有的未实例化的单例bean:

4.1. 情况一:如果此时的bean是切面类(标注@Aspect)。

4.1.1. 实例化bean之前

->执行resolveBeforeInstantiation->InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    ...
    beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
    if (beanInstance != null) {
        return beanInstance;
    }
    ...
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = this.determineTargetType(beanName, mbd);
            if (targetType != null) {
                //主要进行AbstractAutoProxyCreator.postProcessBeforeInstantiation操作
                bean = this.applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    //如果有返回对象(上面返回的是包含切面逻辑的该bean的代理对象),继续执行实例化后置通知方法
                    bean = this.applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = bean != null;
    }
    return bean;
}
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    Object cacheKey = this.getCacheKey(beanClass, beanName);
    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        //advisedBeans用于存储不可代理的bean,如果包含直接返回
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        //判断当前bean是否可以被代理,然后存入advisedBeans
        if (this.isInfrastructureClass(beanClass) || this.shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }
    //获取当前bean的TargetSource对象,如果不存在,则直接退出当前方法,否则从TargetSource中获取当前bean对象,并且判断是否需要将切面逻辑应用在当前bean上
    TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        // 获取能够应用当前bean的切面逻辑
        Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        //创建包含切面逻辑的该bean的代理对象
        Object proxy = this.createProxy(beanClass, beanName, specificInterceptors, targetSource);
        //把生成的代理对象进行缓存
        this.proxyTypes.put(cacheKey, proxy.getClass());
        //返回该代理对象,在上一级方法中,有做后置通知方法的处理
        return proxy;
    } else {
        return null;
    }
}
protected boolean isInfrastructureClass(Class<?> beanClass) {
    return super.isInfrastructureClass(beanClass) || this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass);
}
protected boolean isInfrastructureClass(Class<?> beanClass) {
    //如果bean继承自Advice、Pointcut、Advisor、AopInfrastructureBean
    boolean retVal = Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass) || AopInfrastructureBean.class.isAssignableFrom(beanClass);
    if (retVal && this.logger.isTraceEnabled()) {
        this.logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
    }
​
    return retVal;
}
public boolean isAspect(Class<?> clazz) {
    //如果bean带有@Aspect注解,并且不能被Ajc(AspectJ编译器)编译
    return this.hasAspectAnnotation(clazz) && !this.compiledByAjc(clazz);
}

(1)判断当前bean是否在advisedBeans中(保存了所有需要增强bean,使用Boolean区分是否可以被代理。false可以理解为切面类,不需要代理的;如果是true,表示被切的类,表明已经生成过代理了(即切面逻辑已经应用到该bean));

(2)判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean、判断是否是切面(是否实现了注解@Aspect)、判断是否需要跳过; 注:因为是切面类(标注@Aspect),则会advisedBeans.put(cacheKey, Boolean.FALSE),加入到增强Bean的map集合中,并返回null,然后到上一级程序继续执行下一步。

(3)如果用户使用了自定义的TargetSource对象,则直接使用该对象生成目标对象,而不会使用Spring的默认逻辑生成目标对象,并且这里会判断各个切面逻辑是否可以应用到当前bean上,如果可以,则直接应用,也就是说TargetSource为使用者在Aop中提供了一个自定义生成目标bean逻辑的方式,并且会应用相应的切面逻辑。即在这一步就已经把切面逻辑应用在了该bean上,并生成了代理对象。在这之后直接返回该bean,createBean方法结束。

4.1.2. 初始化bean之后

->执行doCreateBean->initializeBean->InstantiationAwareBeanPostProcessor.postProcessBeforeInitialization 未作特别处理,可忽略 ->执行doCreateBean->initializeBean->InstantiationAwareBeanPostProcessor.postProcessAfterInitialization->wrapIfNecessary 判断该bean是否需要增强,如果需要增强,则创建一个该bean的代理对象。因为是切面类,所以不需要增强,返回bean

补充:在实例化bean前后使用的后置处理器并不一定是一个,而是会把所有的后置处理器(每个后置处理器方法都有before和after,处理时机不同)都遍历一遍(处理器按照一定顺序)来处理当前的bean。

4.2. 情况二:此时的bean是需要被切的类(即@Pointcut("a.b.c")中a.b.c覆盖到的类)

4.2.1. 实例化bean之前

执行resolveBeforeInstantiation->InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(执行方法同上面切面类里的方法)

(1)判断当前bean是否在advisedBeans中(保存了所有需要增强bean);

(2)判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean、判断是否是切面(是否实现了注解@Aspect)、判断是否需要跳过;

(3)如果用户使用了自定义的TargetSource对象,则直接使用该对象生成目标对象,而不会使用Spring的默认逻辑生成目标对象,并且这里会判断各个切面逻辑是否可以应用到当前bean上,如果可以,则直接应用,也就是说TargetSource为使用者在Aop中提供了一个自定义生成目标bean逻辑的方式,并且会应用相应的切面逻辑。

注:因为是需要被切的类,所以以上三个条件都不满足,既不在advisedBeans中,也不是基础类等,更不是自定义的TargetSource对象,所以这个过程未作特别处理,返回null。

4.2.2. 初始化bean之后

->执行doCreateBean->initializeBean->InstantiationAwareBeanPostProcessor.postProcessBeforeInitialization 未作特别处理,可忽略 ->执行doCreateBean->initializeBean->InstantiationAwareBeanPostProcessor.postProcessAfterInitialization->wrapIfNecessary

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return this.wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
​
    return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    //如果是targetSourcedBeans存放已经增强过的bean,则不需要再次处理
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    } else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        //advisedBeans的key为cacheKey,value为boolean类型,表示是否进行过代理
        //已经处理过的(切面)bean,不需要再次进行处理,节省时间
        return bean;
    } else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
        //如果不是内部基础设置类Class && 不需要跳过(即配置了该bean需要代理,则不需要跳过)
        Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        } else {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    } else {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }
}

(1)未被增强处理过,且未被代理过,且不是基础方法,且不需要跳过的,才能执行下一步; (2)执行getAdvicesAndAdvisorsForBean,获取当前对象所有适用的Advisor(即切面类实例),主要处理两件事。具体逻辑如下,

protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    List<Advisor> advisors = this.findEligibleAdvisors(beanClass, beanName);
    return advisors.isEmpty() ? DO_NOT_PROXY : advisors.toArray();
}
​
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    //找到Spring中Advisor的实现类(findCandidateAdvisors)
    //将所有拥有@Aspect注解的类转换为advisors(aspectJAdvisorsBuilder.buildAspectJAdvisors)
    List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
    //找到当前对象适合的所有Advisor
    List<Advisor> eligibleAdvisors = this.findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    //添加一个默认的advisor,执行时用到
    this.extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = this.sortAdvisors(eligibleAdvisors);
    }
​
    return eligibleAdvisors;
}

第一步,执行findCandidateAdvisors(),其中执行父级findCandidateAdvisors,找到Spring中Advisor的实现类(已经存在的Advisor);然后执行aspectJAdvisorsBuilder.buildAspectJAdvisors,将所有拥有@Aspect注解的类转换为advisors(转换的过程,其实就是创建Advisor的过程,本质是创建InstantiationModelAwarePointcutAdvisorImpl对象);最终把所有的切面类实例advisors放到list中。具体逻辑如下,

protected List<Advisor> findCandidateAdvisors() {
    // Add all the Spring advisors found according to superclass rules
    List<Advisor> advisors = super.findCandidateAdvisors();
    if (this.aspectJAdvisorsBuilder != null) {
        // Build Advisors for all AspectJ aspects in the bean factory
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
​
    return advisors;
}

super.findCandidateAdvisors()方法最终调用advisorRetrievalHelper.findAdvisorBeans(),逻辑如下,

public List<Advisor> findAdvisorBeans() {
        String[] advisorNames = this.cachedAdvisorBeanNames;
        if (advisorNames == null) {
            // 获取当前BeanFactory中所有实现了Advisor接口的bean的名称
            advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);
            this.cachedAdvisorBeanNames = advisorNames;
        }
​
        if (advisorNames.length == 0) {
            return new ArrayList();
        } else {
            List<Advisor> advisors = new ArrayList();
            String[] var3 = advisorNames;
            int var4 = advisorNames.length;
            // 对获取到的实现Advisor接口的bean的名称进行遍历
            for(int var5 = 0; var5 < var4; ++var5) {
                String name = var3[var5];
                // isEligibleBean()是提供的一个hook方法,用于子类对Advisor进行过滤,这里默认返回值都是true
                if (this.isEligibleBean(name)) {
                    // 如果当前bean还在创建过程中,则略过,其创建完成之后会为其判断是否需要织入切面逻辑
                    if (this.beanFactory.isCurrentlyInCreation(name)) {
                        if (logger.isTraceEnabled()) {
                            logger.trace("Skipping currently created advisor '" + name + "'");
                        }
                    } else {
                        try {
                            // 将当前bean添加到advisors结果中
                            advisors.add(this.beanFactory.getBean(name, Advisor.class));
                        } catch (BeanCreationException var11) {
                            // 对获取过程中产生的异常进行封装
                            Throwable rootCause = var11.getMostSpecificCause();
                            if (rootCause instanceof BeanCurrentlyInCreationException) {
                                BeanCreationException bce = (BeanCreationException)rootCause;
                                String bceBeanName = bce.getBeanName();
                                if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
                                    if (logger.isTraceEnabled()) {
                                        logger.trace("Skipping advisor '" + name + "' with dependency on currently created bean: " + var11.getMessage());
                                    }
                                    continue;
                                }
                            }
​
                            throw var11;
                        }
                    }
                }
            }
​
            return advisors;
        }
    }

aspectJAdvisorsBuilder.buildAspectJAdvisors()会触发ReflectiveAspectJAdvisorFactory中的getAdvisors方法,逻辑如下,

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    //从 aspectMetadata 中获取 Aspect()标注的类 class对象
    Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    //获取Aspect()标注的类名
    String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
    this.validate(aspectClass);
    // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
    // so that it will only instantiate once.
    MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
    List<Advisor> advisors = new ArrayList();
    //遍历该类所有方法,根据方法判断是否能获取到对应 pointCut,如果有,则生成 advisor 对象
    Iterator var6 = this.getAdvisorMethods(aspectClass).iterator();
    while(var6.hasNext()) {
        Method method = (Method)var6.next();
        //这里继续看下面的解析
        Advisor advisor = this.getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }
	// If it's a per target aspect, emit the dummy instantiating aspect.
    if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        Advisor instantiationAdvisor = new ReflectiveAspectJAdvisorFactory.SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
        advisors.add(0, instantiationAdvisor);
    }

    Field[] var12 = aspectClass.getDeclaredFields();
    int var13 = var12.length;
	//获取 @DeclareParents 注解修饰的属性(并不常用)
    for(int var14 = 0; var14 < var13; ++var14) {
        Field field = var12[var14];
        Advisor advisor = this.getDeclareParentsAdvisor(field);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    return advisors;
}

getAdvisor的具体逻辑如下,

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) {
    this.validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
    AspectJExpressionPointcut expressionPointcut = this.getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    //构建InstantiationModelAwarePointcutAdvisorImpl对象
    return expressionPointcut == null ? null : new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

InstantiationModelAwarePointcutAdvisorImpl会触发getAdvice,具体逻辑如下,

public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    ...
    Object springAdvice;
    //根据注解类型,匹配对应的通知类型
    switch(aspectJAnnotation.getAnnotationType()) {
        //切面
        case AtPointcut:
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
            }
​
            return null;
        //环绕通知
        case AtAround:
            springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        //前置通知
        case AtBefore:
            springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        //最终通知
        case AtAfter:
            springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        //后置(正常)通知
        case AtAfterReturning:
            springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterReturning afterReturningAnnotation = (AfterReturning)aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                ((AbstractAspectJAdvice)springAdvice).setReturningName(afterReturningAnnotation.returning());
            }
            break;
        //异常通知
        case AtAfterThrowing:
            springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterThrowing afterThrowingAnnotation = (AfterThrowing)aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                ((AbstractAspectJAdvice)springAdvice).setThrowingName(afterThrowingAnnotation.throwing());
            }
            break;
        default:
            throw new UnsupportedOperationException("Unsupported advice type on method: " + candidateAdviceMethod);
        }
        ...
        return (Advice)springAdvice;
    }
}

其本质是根据@Aspect类中方法的注解类型,生成对应的advice,并通过通知的构造方法,将通知增强方法,切面表达式传入到通知当中。

第二步,执行findAdvisorsThatCanApply,找到当前对象适合的所有Advisor。整个过程比较简单:遍历所有的advisor,然后查看当前advisor的pointCut是否适用于当前对象,如果是,进入候选队列(其实就是放到一个list中),否则跳过。

(3)执行createProxy,创建代理对象。

具体实现逻辑如下,

protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass);
    }

    ProxyFactory proxyFactory = new ProxyFactory();
    //获取当前类中的属性
    proxyFactory.copyFrom(this);
    //检查proxyTargeClass设置以及preserveTargetClass属性  
    //决定对于给定的bean是否应该使用targetClass而不是他的接口代理
    if (!proxyFactory.isProxyTargetClass()) {
        if (this.shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        } else {
            //用来添加代理接口
            this.evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
    //加入增强器
    proxyFactory.addAdvisors(advisors);
    //设置要代理的类
    proxyFactory.setTargetSource(targetSource);
    //定制代理
    this.customizeProxyFactory(proxyFactory);
    //用来控制代理工厂被设置后是否还允许修改通知,缺省值为false
    proxyFactory.setFrozen(this.freezeProxy);
    if (this.advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    return proxyFactory.getProxy(this.getProxyClassLoader());
}

从上面代码我们看到对于代理类的创建及处理spring是委托给了ProxyFactory处理的,而在此函数中主要是对ProxyFactory的初始化操作,进而对创建代理做准备,这些初始化操作包括以下内容: 第一步,获取当前类中的属性 第二步,添加代理接口

下面是添加代理接口evaluateProxyInterfaces的函数:

protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
    Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.getProxyClassLoader());
    boolean hasReasonableProxyInterface = false;
    Class[] var5 = targetInterfaces;
    int var6 = targetInterfaces.length;
​
    int var7;
    Class ifc;
    for(var7 = 0; var7 < var6; ++var7) {
        ifc = var5[var7];
        if (!this.isConfigurationCallbackInterface(ifc) && !this.isInternalLanguageInterface(ifc) && ifc.getMethods().length > 0) {
            hasReasonableProxyInterface = true;
            break;
        }
    }
​
    if (hasReasonableProxyInterface) {
        var5 = targetInterfaces;
        var6 = targetInterfaces.length;
​
        for(var7 = 0; var7 < var6; ++var7) {
            ifc = var5[var7];
            proxyFactory.addInterface(ifc);
        }
    } else {
        proxyFactory.setProxyTargetClass(true);
    }
​
}

第三步,封装Advisor并加入到ProxyFactory中 ​ 第四步,设置要代理的类 ​ 第五步,在spring中还为子类提供了定制的函数customizeProxyFactory,子类可以在此函数中进行对ProxyFactory的进一步封装 ​ 第六步,进行获取代理操作

上面proxyFactory.getProxy中的createAopProxy()最终调用的是DefaultAopProxyFactory.createAopProxy()的实现逻辑如下,

public Object getProxy(@Nullable ClassLoader classLoader) {
    return this.createAopProxy().getProxy(classLoader);
}
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
        return new JdkDynamicAopProxy(config);
    } else {
        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.");
        } else {
            return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
        }
    }
}

注意:如果bean是需要被切的类(如开始举的UserServiceImpl例子),那么在bean缓存池中存放的就是带有切面逻辑的代理对象,该代理对象属性中包含advisors(结构是ArrayList,里面存放的是切点和通知,就是我们常用的@Aspect 注解标记的类),具体参考下面几张结果图,

 

如下可以看出,在beanPostProcessors后置处理器集合中,有AnnotationAwareAspectJAutoProxyCreator对象这里有userServiceImpl这个因被切而生成的代理对象(已经应用了切面逻辑)属性,并且使用的是CGLib代理。

如下图,可以看出在bean缓存池中,存放了userServiceImpl的代理对象(注意没有再单独的userServiceImpl对象了,因为userServiceImpl被切了,所以bean缓存吃中保存的只有userServiceImpl的代理对象),该代理对象下有切点和通知,在后续使用该bean的时候,会用到这里的其切点和通知,会转换成拦截器,并形成拦截器链,保证通知方法按顺序执行。

四、Spring AOP是如何起作用的?

如上面的userServiceImpl,实际存到bean缓存池中存放的就是带有切面逻辑的代理对象,如上的userServiceImpl就是一个cglib代理对象,在执行到该方法的时候,获取到的该bean就是这个cglib代理对象,所以执行他的方法的时候,首先会进入cglib代理对象的拦截器,即CglibAopProxy.intercept()拦截器,其中会获取即将执行的目标方法的拦截器链。具体逻辑如下,

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    Object target = null;
    TargetSource targetSource = this.advised.getTargetSource();
​
    Object var16;
    try {
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
​
        target = targetSource.getTarget();
        Class<?> targetClass = target != null ? target.getClass() : null;
        //根据ProxyFactory对象获取将要执行的目标方法拦截器链
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        //如果没有拦截器链,直接执行目标方法
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = methodProxy.invoke(target, argsToUse);
        } else {
            //如果有连接器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个CglibMethodInvocation对象
            retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
        }
​
        retVal = CglibAopProxy.processReturnType(proxy, target, method, retVal);
        var16 = retVal;
    } finally {
        if (target != null && !targetSource.isStatic()) {
            targetSource.releaseTarget(target);
        }
​
        if (setProxyContext) {
            AopContext.setCurrentProxy(oldProxy);
        }
​
    }
​
    return var16;
}
public Object proceed() throws Throwable {
    //从-1开始,下标=拦截器的长度-1的条件满足表示执行到了最后一个拦截器的时候,此时执行目标方法
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return this.invokeJoinpoint();
    } else {
        //获取第一个方法拦截器使用的是前++
        Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
            Class<?> targetClass = this.targetClass != null ? this.targetClass : this.method.getDeclaringClass();
            return dm.methodMatcher.matches(this.method, targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
        } else {
            return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
        }
    }
}

(1)执行advised.getInterceptorsAndDynamicInterceptionAdvice,

        1)List<Object> interceptionList保存所有拦截器5 一个默认的ExposeInvocationInterceptor 和 4个增强器。

        2)遍历所有的增强器,将每个增强器转为MethodInterceptor,具体为,每个增强其都执行registry.getInterceptors(advisor),其流程为:

如果是MethodInterceptor 直接加入到List<MethodInterceptor>集合中;

如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;

转换完成返回MethodInterceptor[]数组。

        3)如果没有拦截器链,直接执行目标方法; 拦截器链(每一个通知方法又被包装为方法拦截器,利用MethodInterceptor机制)

        4)如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个 CglibMethodInvocation 对象,并调用 Object retVal = mi.proceed();

        5)拦截器链的触发过程; 第一步,如果没有拦截器执行执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)执行目标方法; 第二步,链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行; 拦截器链的机制,保证通知方法与目标方法的执行顺序;

五、总结

(1)@EnableAspectJAutoProxy 开启AOP功能,即往bean定义注册表中注册AnnotationAwareAspectJAutoProxyCreator;

(2)AnnotationAwareAspectJAutoProxyCreator是一个后置处理器,这里提供了获取适用当前bean的切面逻辑,并把切面逻辑应用到该bean,最后创建一个代理对象的所有方法,所以他是spring提供aop功能的核心;

(3)IOC容器的创建流程(以下为与AOP初始化相关的逻辑):

        1)refresh.registerBeanPostProcessors()注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象

        2)finishBeanFactoryInitialization()初始化剩下的单实例bean

                1.如果是切面类,则advisedBeans.put(cacheKey, Boolean.FALSE),加入到增强Bean的map集合中;

                2.如果是自定义的TargetSource对象,则直接使用该对象生成目标对象,而不会使用Spring的默认逻辑生成目标对象,并且这里会判断各个切面逻辑是否可以应用到当前bean上,如果可以,则直接应用,也就是说TargetSource为使用者在Aop中提供了一个自定义生成目标bean逻辑的方式,并且会应用相应的切面逻辑。

                 3.如果是需要被切的类,则获取当前对象所有适用的Advisor(即切面类实例),并把Advisor应用到该bean,并最终创建一个代理对象,这个过程被成为增强;

(4)执行目标方法:

         1)代理对象执行目标方法

        2)CglibAopProxy.intercept();

                 1.得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)

                2.利用拦截器的链式机制,依次进入每一个拦截器进行执行;

                3.效果: 正常执行:前置通知-》目标方法-》返回通知-》后置通知 出现异常:前置通知-》目标方法-》异常通知-》后置通知

(5)AOP中几个重要的概念

        1)切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象,在Spring中意为所有通知方法所在的类,如上例中使用@Aspect注解的(LogAspects)切面类。

        2)连接点(Join point):被拦截到的点,因为 Spring 只支持方法类型的连接点,所以在 Spring 中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器,如上面被拦截到的userServiceImpl.add方法就是连接点。

        3)切入点(pointcut):与通知一起出现,使用专门的切点表达式决定在何处执行通知方法,如上例使用的@Pointcut注解设计到具体类或方法,就是切入点。

        4)通知(advice):所谓通知指的就是指拦截到连接点之后要执行的代码,共有5种类型,before(切点之前执行),around(环绕执行,即切点前后执行),After returning(切点正常执行完返回后执行),After throwing(切点抛出异常后执行),after(切点之后执行,不管是异常或正常结束),AOP拦截器链则为以上五种通知组成。我们可以在通知方法中获得我们需要的参数(返回值,异常信息,代理对象等)。

        5)目标对象(target object):代理的目标对象,如上例中的UserServiceImpl就是目标对象。

        6)织入(weaving):将切面应用到目标对象并导致代理对象创建的过程,Spring AOP是动态织入(运行时织入),AspectJ则是静态织入(编译时织入),如上例执行的wrapIfNecessary方法执行的过程就是织入。

        7)引入(introduction):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或属性,例如,可以使用引入来使一个bean实现isModified接口,以便简化缓存机制。

        8)AOP代理(AOP proxy):AOP代理对象,由JDK动态代理或CGLIB代理生成。

(6)扩展:spring boot中的事务处理,本质跟上面的AOP逻辑类似,

        1)Sringboot启动类上添加@EnableTransactionManagement,

@EnableTransactionManagement引入的是TransactionManagementConfigurationSelector。该类引入两个组件,分别是AutoProxyRegistrar和ProxyTransactionManagementConfiguration。

AutoProxyRegistrar会去创建InfrastructureAdvisorAutoProxyCreator的beandefinition,这个是bean的后置处理器,做的事情和上面的AOP的AnnotationAwareAspectJAutoProxyCreator类似。

ProxyTransactionManagementConfiguration它是一个配置类,里面包括有一些bean方法,在最后创建bean时,这些beanMethod返回的bean都会创建对象添加到iOC容器。其中包括有: BeanFactoryTransactionAttributeSourceAdvisor、AnnotationTransactionAttributeSource、TransactionInterceptor。作用其实就是个切面类,定义了一些切面逻辑。

        2)在需要使用事务的方法上加@Transactional,实现事务操作。

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值