spring源码浅析

spring

官方文档:spring

IOC

IOC也称DI,IOC所提供的功能是由DI来实现的,可以认为它们是对同一个概念的不同角度的描述;

控制反转(IOC):将设计好的对象交给容器控制,而不是在对象内部直接控制;

依赖注入(DI):组件之间的依赖关系由容器在运行期决定;

容器加载

IOC加载过程(以AnnotationConfigApplicationContext注解扫描容器作为入口说明,容器的顶层接口是BeanFactory):

创建容器对象:在创建容器的过程会创建这些对象:

  • PathMatchingResourcePatternResolver:用于解析类路径或者文件系统中的资源文件;
  • DefaultListableBeanFactory:也是一个容器,实现了BeanDefinitionRegistryBeanFactory等接口;
  • AnnotatedBeanDefinitionReader:解析class为bean定义,用于扫描class下的bean定义;
  • ClassPathBeanDefinitionScanner:功能同上一个,用于扫描包下的bean定义;

注册bean定义:调用容器的register方法注册bean定义,实际就是调用上边AnnotatedBeanDefinitionReader对象的register方法,具体过程如下:

  • 注册bean定义的过程中会解析LazyPrimaryDependsOnRoleDescription等注解信息并保存到AnnotatedBeanDefinition对象中;
  • 将解析到的bean定义信息保存到BeanDefinitionHolder
  • 判断ScopedProxyMode
  • 注册bean定义到容器中(registerBeanDefinition方法注册);
    • 校验bean定义;
    • 判断容器中是否已有这个bean定义,如果有的话,根据allowBeanDefinitionOverriding配置确实覆盖bean定义还是抛异常;
  • 获取并保存bean定义的别名

刷新容器:调用容器的refresh方法刷新容器,这个方法是整个容器加载的核心方法,大致流程如下:

  • 使用synchronized对整个方法加锁;
  • 容器预处理,包含设置开始时间、容器状态、初始化配置的钩子方法、校验environment配置、初始化监听器容器(就是个空Set);
  • 获取BeanFactory,就是上面创建容器时创建的DefaultListableBeanFactory
  • 预处理BeanFactory,主要设置一些参数,具体在[这里](# beanFactory预处理);
  • 预处理BeanFactory后置处理器:一个空的钩子函数;
  • 执行BeanFactory后置处理器:BeanFactoryPostProcessor,这一步会将大量的bean定义加入到容器中,具体流程看[这里](# BeanFactory后置处理器);
  • 注册Bean后置处理器:BeanPostProcessor,注册过程在[这里](# Bean后置处理器)
  • 初始化messageSource:如果容器中有,则从容器中获取,如果没有,则创建DelegatingMessageSource,并放到容器中,用于国际化处理;
  • 初始化事件分发器;
  • 执行空的钩子方法onRefresh;springboot中就是扩展的这个方法启动web容器;
  • 注册监听器;
  • 实例化所有非懒加载的单实例bean,创建Bean的核心方法,在[这里](# Bean实例化);
  • 发布相应的事件;
  • 清除容器加载过程中的缓存信息,主要时反射元数据缓存;

beanFactory

功能说明

spring容器在创建容器对象时会创建一个beanFactory内置在容器中,本文是DefaultListableBeanFactory,这个保存bean定义、注册并执行后置处理器等很多地方都有用到;

beanFactory预处理

beanFactory预处理内容:

  • 类加载器;
  • 表达式解析器(spel);
  • 属性配置编辑器注册器:ResourceEditorRegistrar
  • 后置处理器:ApplicationContextAwareProcessorApplicationListenerDetectorLoadTimeWeaverAwareProcessor
  • 忽略的Aware接口:EnvironmentAwareEmbeddedValueResolverAwareResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAwareApplicationContextAware
  • 可用于解析的自动装配:BeanFactoryResourceLoaderApplicationEventPublisherApplicationContext
  • 配置信息等;

BeanFactory后置处理器

执行流程

BeanFactory后置处理器执行流程如下(这里的beanFactory就是容器创建时创建的容器):

  • 获取容器对象中设置的beanFactoryPostProcessors作为入参;
  • 判断beanFactory是否实现了BeanDefinitionRegistry接口(这里都是实现了的);
  • 先处理入参的后置处理器,找到实现了BeanDefinitionRegistryPostProcessor接口的后置处理器,执行postProcessBeanDefinitionRegistry方法;
  • 再处理容器中的后置处理器;
  • 先通过beanFactory.getBeanNamesForType方法获取所有实现了BeanDefinitionRegistryPostProcessor接口的bean名称
  • 从这些后置处理器的bean中找到实现了PriorityOrdered接口的处理器,排序后依次执行postProcessBeanDefinitionRegistry方法;(这里有一个重要的后置处理器ConfigurationClassPostProcessor,业务中常用的@ComponentScan@PropertySources@Configuration@Bean@Component@Import等注解就是在这里添加到beanDefinition中的,主要实现逻辑在:org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass
  • 按上一步的逻辑处理实现了Ordered接口的后置处理器
  • 再对剩下的BeanDefinitionRegistryPostProcessor进行类似的排序并执行;
  • 然后执行上面这些后置处理器的postProcessBeanFactory方法;
  • 从beanFactory中获取所有实现了BeanFactoryPostProcessor接口的bean;
  • 剔除掉上面已经执行过的BeanDefinitionRegistryPostProcessor
  • 按上面类似的逻辑对这些后置处理器,分为实现了PriorityOrdered接口的、实现了Ordered接口的和没有实现排序接口的三个list;
  • 对这三个list依次排序并执行postProcessBeanFactory方法;
  • 最后清理临时变量,执行结束;

小结

spring5.2.x中顶层的BeanFactoryPostProcessor接口有两个:

BeanFactoryPostProcessor:在bean定义注册之后,bean创建之前执行,具体在上面的源码步骤分析中有;

接口定义,该接口有一个抽象方法,参数就是上面的BeanFactory,可以在这个方法中完成对Bean定义的修改以及属性的修改等,例如CustomAutowireConfigurer就是通过这个接口添加@Qualifier注解功能的,另外,强烈不建议在这里实例化bean,如果需要实例Bean,可以在BeanPostProcessor中完成:

@FunctionalInterface
public interface BeanFactoryPostProcessor {
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

BeanDefinitionRegistryPostProcessor:这个接口继承BeanFactoryPostProcessor,也具有相应功能,其继承方法优先执行,同时它自身的抽象方法会在postProcessBeanFactory方法之前执行;

接口定义,参数是BeanDefinitionRegistry,可以完成对bean定义的增删改查,上面提到过ConfigurationClassPostProcessor就是通过这个方法完成Bean定义的扫描的:

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}

Bean实例化

在spring容器中,单实例的非懒加载的bean的创建过程如下:

  • 设置值解析器 —— 用于解析配置文件;
  • 初始化LoadTimeWeaverAware;
  • 设置参数(临时类加载器、允许缓存bean定义元数据);
  • 遍历bean名称,执行后续步骤;
  • 获取bean定义;
  • 判断bean:不是抽象类、是单实例、不是懒加载、不是FactoryBean;
    • 满足条件则调用getBean方法继续创建bean;
    • 如果是FactoryBean,则工厂bean名称前加&,原bean名称代表工厂bean返回的bean;
  • 调用getBean方法开始获取bean
  • 解析bean名称 —— 处理有别名的情况;
  • 尝试获取bean,获取到则直接返回这个bean,否则继续;
    • 尝试从一级缓存获取bean(一级缓存实际就是个ConcurrentHashMap
    • 如果获取失败并且bean正在创建中,则尝试从二级缓存获取(是一个HashMap);
    • 如果又获取失败并且允许提前引用,则尝试从三级缓存获取(也是一个HashMap)—— 三个缓存是个ObjectFactory,在获取bean时会先执行后置处理器的getEarlyBeanReference方法,给后置处理器一个增强bean的机会;然后添加到二级缓存,然后将三级缓存的这个bean清除;
  • 如果获取失败,则检查bean是否正在创建,如果是则代表有循环依赖,抛出异常,否则继续创建;
  • 检查bean定义是否存在父工厂中,如果是则调用父工厂的getBean方法,若不是则继续;
  • 标记bean正在创建中;
  • 获取并检查bean定义;
  • 获取dependsOn,如果有,先检查如果有循环依赖,则抛出异常,否则对依赖的bean调用getBean方法;
  • 判断是否单例bean,这里只讨论单例bean的情况,即调用getSingleton方法获取或创建bean;
    • 加锁
    • 尝试从一级缓存获取,成功则返回,否则继续
    • 判断容器状态,如果已被销毁则抛异常;
    • 如果是循环创建,则抛异常,否则继续;
    • 调用入参对象ObjectFactory的getObject方法(入参是个lambda表达式,它是通过调用createBean方法创建bean,这个方法在后面单独分析)获取或者创建bean;
    • 去掉bean创建中的标记
    • 将bean从二、三级缓存中删除并添加到一级缓存,同时添加到已注册的bean列表中;
  • 判断是否FactoryBean,如果是最终会调用getObject方法获取bean,否则直接返回当前bean;
  • 到此,一个bean就创建完成,可以开始创建下一个bean了;
  • 再遍历一次bean:判断是否实现了SmartInitializingSingleton接口,若是则执行afterSingletonsInstantiated方法
  • 到此,单实例非懒加载的bean就创建完成了;

这里再简单分析下创建bean的方法的大概流程:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])

  • 解析并检查bean定义;
  • 遍历所有的BeanPostProcessor
  • 如果找到InstantiationAwareBeanPostProcessor后置处理器,则执行postProcessBeforeInstantiation方法;
  • 如果后置处理器方法返回值不为空,则直接返回后置处理器返回的对象,然后继续遍历BeanPostProcessor执行postProcessAfterInitialization,改方法返回值作为最终bean返回 —— 相当于该方式创建的bean不需要在初始化了;否则继续调用doCreateBean方法创建bean,后面的步骤都是在这个方法中实现的;
  • 检查是否是public的bean;
  • 检查instanceSupplier、getFactoryMethodName等;
  • 判断是否有SmartInstantiationAwareBeanPostProcessor后置处理器,如果有则执行determineCandidateConstructors方法获取构造器
  • 如果找到了构造器会设置解析构造参数赋值然后创建对象,这里不深入讨论,如果没有找到合适的构造器,则继续调用instantiate方法实例化对象;
  • instantiate方法中,会判断bean中是否有覆盖方法(即是否有实现接口):
    • 没有:通过Class对象获取构造方法,然后通过BeanUtils.instantiateClass方法实例化对象;
    • 有:通过CglibSubclassCreator静态内部类创建cglib代理对象;
  • 将创建好的对象包装到BeanWrapper对象中
  • 遍历找到MergedBeanDefinitionPostProcessor后置处理器,执行postProcessMergedBeanDefinition方法
  • 将bean封装到ObjectFactory(重写getObject方法,使用getEarlyBeanReference方法封装,使得在获取bean之前会执行SmartInstantiationAwareBeanPostProcessor后置处理器的getEarlyBeanReference方法,AOP代理就是利用这个方法解决循环依赖下的增强对象),并添加到三级缓存,将bean名称添加注册表;
  • 后面开始初始化bean;
  • 获取InstantiationAwareBeanPostProcessor后置处理器并执行postProcessAfterInstantiation方法
  • 获取InstantiationAwareBeanPostProcessor后置处理器并执行postProcessProperties方法(这里有一个重要的后置处理器AutowiredAnnotationBeanPostProcessor,就是在这个方法中完成注入的,逻辑比较长,大概的注入步骤就是解析依赖封装到InjectedElement,然后判断并检查依赖类型,然后调用上面的getBean方法获取Bean,即回到了上面的第7步(调用getBean获取bean),然后反射赋值:ReflectionUtils.makeAccessible(field);field.set(bean, value);
  • 如果bean实现了BeanNameAwareBeanClassLoaderAwareBeanFactoryAware接口,则调用对应方法;
  • 找到BeanPostProcessor后置处理器,执行postProcessBeforeInitialization方法
  • 执行初始化方法:先判断如果实现了InitializingBean接口,则执行afterPropertiesSet方法;在判断如果有初始化方法,则执行初始化方法;
  • 找到BeanPostProcessor后置处理器,执行postProcessAfterInitialization方法
  • 再次尝试从缓存中获取当前bean;用于验证缓存中是不是当前bean;
  • 判断是否DisposableBean,是的话就注册;
  • 到此一个bean的创建步骤就完成了

从上面的过程中可以看出,当产生循环依赖时,原始对象会拥有循环依赖的代理对象,代理对象只会持有原始对象,使用spring注入的对象都是代理对象;另外当调用代理对象方法时,代理对象最终会调用原始对象的方法,在原始对象中this是指向自己的,因此直接使用this调用会导致代理失效;具体如图:

在这里插入图片描述

Bean后置处理器

注册过程

注册过程(这里的beanFactory也是容器创建时创建的容器):

  • 通过beanFactory.getBeanNamesForType方法获取容器中所有的后置处理器;
  • 按照执行BeanFactory后置处理器的类似逻辑对这些bean,分为实现了PriorityOrdered接口的、实现了Ordered接口的和没有实现排序接口的三个list;
  • 依次对这三个list排序,然后注册到beanFactory中(注册过程实际就是调用beanFactory.addBeanPostProcessor方法添加到成员变量中);
  • 最后将ApplicationListenerDetector后置处理器也注册到beanFactory;

beanPostProcessor是在创建bean的过程中执行的,在上面bean的创建过程中其实已经设计到其执行过程,这里做一些小结;

小结

spring5.2.x中顶层的BeanPostProcessor接口有五个:

BeanPostProcessor:有两个抽象方法,分别是在调用初始化方法之前和之后执行,后面的几个后置处理器接口都继承自这个接口;

接口定义:

public interface BeanPostProcessor {
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

InstantiationAwareBeanPostProcessor:实例化bean后置处理器,其包含4个抽象方法:

  • postProcessBeforeInstantiation:会在创建bean对象之前执行,如果这个方法返回值不为空,则会将该返回值作为bean注册到容器中,跳过原始bean创建步骤中的实例化和初始化过程;也就是说这个方法给后置处理器一个机会来提前创建自定义的bean;
  • postProcessAfterInstantiation:在bean对象被创建并封装到ObjectFactory后执行;其返回值代表后续是否需要为这个bean的属性赋值,也就是是否需要初始化;
  • postProcessProperties:可以bean的属性值进行修改,上面提到的AutowiredAnnotationBeanPostProcessor后置处理器,就是在这个方法中调用metadata.inject(bean, beanName, pvs);完成注入的;
  • postProcessPropertyValues:5.1以后已被弃用,用上面的方法代替;

SmartInstantiationAwareBeanPostProcessor:这个接口继承自InstantiationAwareBeanPostProcessor接口,添加了3个抽象方法:

  • predictBeanType:用于预测bean的类型
  • determineCandidateConstructors:在实例化bean之前如果有这个方法,会尝试通过这个方法选择合适的构造器
  • getEarlyBeanReference:从三级缓存中获取bean之前就会执行这个方法;这个方法在处理循环依赖、代理对象时非常有用

MergedBeanDefinitionPostProcessorAutowiredAnnotationBeanPostProcessor这个重要的后置处理器也实现了这个接口,他有两个方法:

  • postProcessMergedBeanDefinition:在bean实例化后,放入三级缓存之前执行;一般可以用于获取当前bean及其父类中的所有信息;AutowiredAnnotationBeanPostProcessor就是在里获取和检查InjectionMetadata信息的;
  • resetBeanDefinition:用于清除bean定义信息;

DestructionAwareBeanPostProcessor:bean销毁前回调的后置处理器,有两个方法:

  • postProcessBeforeDestruction:bean销毁之前的回调处理方法
  • requiresDestruction:决定当前bean是否需要销毁

常用注解小结

bean注解

bean常用注解:

  • @Bean:配置bean,id默认是方法名
    • @Scope:设置作用域,
    • @Lazy-bean:设置懒加载(第一次调用时加载)
    • initMethod:指定初始化方法(单实例:默认启动时执行,多实例:在获取时执行)
    • destroyMethod:指定销毁方法(单实例:在关闭时执行(默认会检测close和shutdown方法),多实例:不执行)
  • @Conditional:按照条件注册bean(使用方式是实现Condition接口,在matches方法中编写具体条件,springboot中大量使用的注解,且扩展许多类似功能的注解,如@ConditionalOnBean@ConditionalOnClass@ConditionalOnMissingBean等);
  • @Import:快速导入bean,功能类似@Bean,id默认是全类名
    • value除了可以有要导入的类,还可以有实现了ImportSelector接口或者ImportBeanDefinitionRegistrar接口的实现类,用于筛选或添加要导入的bean;
  • @PostConstruct:用在方法上,表示该方法会在bean会在创建并赋值完成后执行;
  • @PreDestroy:用在方法上,表示该方法会在销毁bean之前执行;

赋值注解

赋值常用注解:

  • @Value:赋值,主要有下面三种用法:
    • 直接配置值;
    • spel表达式赋值(#{});
    • 取配置文件中的值(${});
  • @PropertySource:加载外部配置文件;
  • @Profile:可以根据当前环境动态的激活和切换组件功能;
    • 用在bean上,表示满足指定环境时才注入Bean
    • 用在类上,表示满足指定环境时才加载类;
    • 没有环境标识注解,则在任何环境下都加载;
    • 可以通过启动参数:-Dspring.profiles.active=指定环境;
    • 也可以调用容器的setActiveProfiles方法设置环境(几乎不用);

注入注解

注入常用注解:

  • @Autowired:自动注入依赖,
    • 默认优先按照类型在容器中查找对应组件,如果找到多个,则将属性名称作为id在容器中查找;
    • 默认至少要有一个可注入的bean,否则会报错(可以关闭);
    • @Qualifier:按名称注入bean;
    • 可以用在属性、普通方法、@bean方法(可以省略)、构造方法(如果只有一个有参构造方法,则可以省略)上;
    • spring底层组件也可以注入
  • @Primary@Autowired注入时,默认首选要装配的bean;
  • @Resource:按名称注入(Java规范注解);
  • @Inject:同@Autowired(Java规范注解,需要javax.inject依赖);

其他常见接口

bean

bean创建相关的常用接口:

  • FactoryBean:也可以注册Bean,使用方法是实现FactoryBean接口并配置到容器中,然后在getObject方法中返回实际需要注册的Bean即可(此时通过id调用getBean方法就可以返回对应的bean,如果要获取BeanFactory,需要在id前加&);
  • InitializingBean:实现该接口的bean会在创建并赋值完成后调用afterPropertiesSet方法初始化bean;
  • DisposableBean:实现该接口的bean会在bean销毁时调用destroy方法;
  • BeanPostProcessor:bean的后置处理器,即在初始化前后执行(创建并赋值后,init方法的前后执行);(这个接口在spring源码中有多处使用,如上面的@PostConstruct生命周期注解、@Autowired注解、Aware接口、参数校验、bean赋值等);
  • BeanFactoryPostProcessor:beanFactory后置处理器,在BeanFactory初始化之后执行,即,所有bean已经加载但还未创建的时候执行;可以使用这个接口添加一些自定义的bean到容器中;
  • ApplicationListener:监听容器中的发布事件;

Aware

Aware:如果想在自定义组件中使用spring底层组件,可以实现对应的xxxAware接口,实现相关方法即可:

  • ApplicationContextAware:注入容器对象;
  • BeanNameAware:注入bean的名字;
  • EmbeddedValueResolverAware:注入spring字符串解析器(解析功能类似@Value);
  • ApplicationEventPublisherAware:容器事件发布器
  • ServletContextAware:用于web容器,注入ServletContext;
  • ServletConfigAware:用于web容器,注入ServletConfig
  • MessageSourceAware:用于国际化处理
  • ResourceLoaderAware:注入资源加载器
  • BeanFactoryAware:注入beanFactory;
  • BeanFactoryAware:注入环境变量,可用于读取配置;
  • ImportAware:注入AnnotationMetadata,可以处理一些注解信息;
  • BeanClassLoaderAware:注入加载bean的类加载器:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值