所有文章

https://www.cnblogs.com/lay2017/p/11478237.html

正文

spring的两大核心就是ioc和aop。在关于ioc依赖注入的文章中,我们了解了如何根据BeanDefinition创建Bean,然后在BeanPostProcessor中处理@Autowired和@Resource两个注解,自动注入Bean。

本文将讲解另外一块核心内容,aop切面。

AOP自动配置

首先,aop切面基于springboot的自动配置。如果不了解自动配置,请参考自动配置机制的文章。

为此,我们先找到aop自动配置的类AopAutoConfiguration

@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration { @Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration { } @Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
public static class CglibAutoProxyConfiguration { } }

我们将以Cglib为主要的了解对象,可以看到CglibAutoProxyConfiguration上注解了一个@EnableAspectJAutoProxy,它意味着开启切面代理,我们打开该注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy { //
}

我们看到,@Import注解导入了AspectJAutoProxyRegistrar。在自动配置的文章中,我们了解到ConfigurationClassParser将会处理@Import注解。这里我们不再关注如何处理@Import注解,直接打开AspectJAutoProxyRegistrar类看看

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 注册自动切面代理的创建器
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); // 省略
} }

跟进registerAspectJAnnotationAutoProxyCreatorIfNecessary

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}

继续跟进registerAspectJAnnotationAutoProxyCreatorIfNecessary

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) { return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

我们看到,调用registerOrEscalateApcAsRequired方法指定了一个类AnnotationAwareAspectJAutoProxyCreator,这个类将作为创建代理的类

跟进registerOrEscalateApcAsRequired方法

private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) { //
// 构建BeanDefinition
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 注册到Bean容器
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}

可以看到,最终是注册到了Bean容器中,作为BeanDefinition存在。我们可以认为aop的自动配置过程就是为了创建AnnotationAwareAspectJAutoProxyCreator这个类的BeanDefinition。

注册AnnotationAwareAspectJAutoProxyCreator

首先,我们先看看AnnotationAwareAspectJAutoProxyCreator的继承结构

可以看到,AnnotationAwareAspectJAutoProxyCreator最终是实现了BeanPostProcessor,那BeanPostProcessor是什么时候被创建为Bean的呢?

这里,我们得回到refresh容器过程的refresh方法中,跟进AbstractApplicationContext的refresh方法

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// try {
// // 注册BeanDefinition到容器
invokeBeanFactoryPostProcessors(beanFactory); // 注册后置处理器到容器
registerBeanPostProcessors(beanFactory); //
}
//
}
}

在注册BeanDefinition之后,就会把BeanPostProcessor的BeanDefinition转化为了Bean注册到容器中。registerBeanPostProcessors结束以后,AnnotationAwareAspectJAutoProxyCreator就以Bean的形式存在于BeanFactory中了。

触发AnnotationAwareAspectJAutoProxyCreator

接着,我们再看AnnotationAwareAspectJAutoProxyCreator被注册为Bean以后,是在什么位置被触发的。前面,ioc依赖注入的文章中我们提到过createBean方法,将会根据BeanDefinition创建Bean。

跟进AbstractAutowireCapableBeanFactory的createBean方法

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException { // try {
// BeanPostProcessors 调用
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
// try {
// 创建实例对象
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
//
return beanInstance;
}
//
}

我们看到,在doCreateBean之前,先触发resolveBeforInstantiation方法,调用了AnnotationAwareAspectJAutoProxyCreator。

切面解析

跟进resolveBeforeInstantiation

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
//
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
//
}
}
//
}
return bean;
}

继续跟进applyBeanPostProcessorBeforeInstantiation方法

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 触发postProcesBeforeInstantiation
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}

继续跟进AbstractAutoProxyCreator的postProcessBeforeInstantiation方法

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName); if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
//
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
} //
return null;
}

isInfrastructureCLass将返回false,跟进AspectJAwareAdvisorAutoProxyCreator的shouldSkip

protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// 返回所有的通知,如@Before @After @AfterThrowing @Round
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}

这里的findCandidateAdvisors方法,将会从beanFactory中获得注解了@Aspect的类元数据,然后获取其中定义的Advisor。

到这一步,我们就已经获得了完成了切面部分的解析工作。

代理增强

回到AbstractAutowireCapableBeanFactory的createBean方法

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException { // try {
// BeanPostProcessors 调用
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
// try {
// 创建实例对象
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
//
return beanInstance;
}
//
}

获取了Advisor,那么再看看Advisor被增强到Bean上的过程,跟进doCreateBean

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// if (instanceWrapper == null) {
// 创建实例对象
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// Object exposedObject = bean;
try {
// 自动注入
populateBean(beanName, mbd, instanceWrapper);
// 初始化Bean,创建代理的入口
exposedObject = initializeBean(beanName, exposedObject, mbd);
} //
return exposedObject;
}

我们找到initializeBean,这个初始化Bean的入口,将从这里开始关注代理增强部分,跟进initializeBean方法

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
//
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
} return wrappedBean;
}

继续跟进applyBeanPostProcessorsAfterInitialization方法

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException { Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}

这里将会调用AbstractAutoProxyCreator的postProcessAfterInitialization方法,跟进方法

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;
}

继续跟进wrapIfNecessary

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// // 获取适用于当前Bean的Advisors
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;
}

getAdvicesAndAdvisorsForBean方法将会获取到可以增强到该Bean的Advisor,然后createProxy将会创建代理类,并一路返回,如果是单例,则注册到缓存中

跟进createProxy看看创建代理

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) { // // 获取可用的advisor
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors); //
// 创建并返回代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}

跟进getProxy

public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}

createAopProxy将会根据条件返回Cglib实现或者jdk动态代理的实现,然后调用它们的getProxy方法去获取代理对象

总结

本文省略了不少细节内容,大体逻辑是从:aop自动配置 -> 解析@Aspect切面对象 -> 代理增强,这么一个逻辑行文的。

自动配置的核心就是为了导入一个AnnotationAwareAspectJAutoProxyCreator,该类实现了BeanPostProcessor。所以在创建Bean实例对象之前会触发解析@Aspect切面对象,获取Advisor。在生成Bean实例对象之后,会再触发该类对Bean实例对象做代理增强,增强的Advisor来自之前的解析结果。代理增强的实现有cglib和jdk动态代理两种。

最后,增强过的代理Bean如果是单例,将跟以前一样添加到缓存对象中。

springboot启动流程(十一)aop切面处理过程的更多相关文章

  1. springboot启动流程(目录)

    springboot出现有段时间了,不过却一直没有怎么去更多地了解它.一方面是工作的原因,另一方面是原来觉得是否有这个必要,但要持续做java似乎最终逃不开要去了解它的命运.于是考虑花一段时间去学习一 ...

  2. SpringBoot启动流程分析(一):SpringApplication类初始化过程

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  3. SpringBoot启动流程分析(四):IoC容器的初始化过程

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  4. SpringBoot启动流程及其原理

    Spring Boot.Spring MVC 和 Spring 有什么区别? 分别描述各自的特征: Spring 框架就像一个家族,有众多衍生产品例如 boot.security.jpa等等:但他们的 ...

  5. SpringBoot 启动流程

    SpringBoot 启动流程 加载 resources/META-INF/spring.factories 中配置的 ApplicationContextInitializer 和 Applicat ...

  6. SpringBoot启动流程分析(六):IoC容器依赖注入

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  7. SpringBoot启动流程解析

    写在前面: 由于该系统是底层系统,以微服务形式对外暴露dubbo服务,所以本流程中SpringBoot不基于jetty或者tomcat等容器启动方式发布服务,而是以执行程序方式启动来发布(参考下图ke ...

  8. SpringBoot启动流程分析(五):SpringBoot自动装配原理实现

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  9. SpringBoot启动流程分析(二):SpringApplication的run方法

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  10. SpringBoot启动流程分析(三):SpringApplication的run方法之prepareContext()方法

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

随机推荐

  1. SurfaceView双缓冲技术引入

    package com.loaderman.customviewdemo; import android.content.Context; import android.graphics.Canvas ...

  2. SSM基于Token的登录认证

    1.什么是token token的意思是“令牌”,是服务端生成的一串字符串,作为客户端进行请求的一个标识. 当用户第一次登录后,服务器生成一个token并将此token返回给客户端,以后客户端只需带上 ...

  3. 123457123456#0#-----com.yuming.FromPuzzleGame01--前拼后广--宝宝农场拼图cym

    com.yuming.FromPuzzleGame01--前拼后广--宝宝农场拼图cym

  4. python 中 logging 模块的 log 函数以及坑

    记录下吧,一个日志的函数,但有个坑是在调用函数时需要先将函数实例化为一个变量,否则进入某个循环时会多次刷新日志: """ 日志模块 """ ...

  5. python 基础之确认文件是否存在

    def check_exist_bills(): file_dir=os.listdir('../db') bills_db_list=[] for item in file_dir: if item ...

  6. PAT 甲级 1041 Be Unique (20 分)(简单,一遍过)

    1041 Be Unique (20 分)   Being unique is so important to people on Mars that even their lottery is de ...

  7. easyui datagrid设置一开始不加载数据

    解决办法就是:一开始的url属性设置为空,例如: <table id="dg" title="用户管理" class="easyui-datag ...

  8. ELK之在CentOS7.5上使用rpm包安装配置ELK7版本

    一,安装环境查看 二,软件版本选用 jdk 1.8.0_171 elasticsearch 7.1.1 kibana 7.1.1 logstash 7.1.1 三,安装配置 1,安装JDK 过程不详述 ...

  9. self-attention详解

    编写你自己的 Keras 层 对于简单.无状态的自定义操作,你也许可以通过 layers.core.Lambda 层来实现.但是对于那些包含了可训练权重的自定义层,你应该自己实现这种层. 这是一个 K ...

  10. 【c# 学习笔记】阻止派生类重写虚成员

    使用sealed 关键字可以防止一个类被其他类继承.同样,也可以使用sealed关键字来阻止派生类重写虚成员.如,我们希望Horse的继承类不再具有扩展Voice方法的行为.(上一章链接:https: ...