Spring 源码(14)Spring Bean 的创建过程(5)
到目前为止,我们知道Spring
创建Bean
对象有5中方法,分别是:
- 使用
FactoryBean
的getObject
方法创建 - 使用
BeanPostProcessor
的子接口InstantiationAwareBeanPostProcessor
的postProcessBeforeInstantiation
方法创建 - 设置
BeanDefinition
的Supplier
属性进行创建 - 设置
BeanDefinition
的factory-method
进行创建 - 使用全过程:
getBean-->doGetBean-->createBean-->doCreateBean
反射进行创建
前面4中已经介绍,接下来介绍第5种,我们知道如果使用反射创建,那么必然要知道使用构造函数进行实例化,因为使用构造函数能够将带有参数的设置进去。
SmartInstantiationAwareBeanPostProcessor 接口
在前面讲过InstantiationAwareBeanPostProcessor
是用来提前实例化对象的,而SmartInstantiationAwareBeanPostProcessor
是InstantiationAwareBeanPostProcessor
的子接口,他是用来干啥呢?
在createBeanInstance
方法中的源码:
// 省略代码....
// 明确构造器从BeanPostProcessor中,对应的是 AutowiredAnnotationBeanPostProcessor
// 他是 SmartInstantiationAwareBeanPostProcessor 的子类,使用determineCandidateConstructors进行
// 解析构造函数
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 省略代码....
点进去:
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
throws BeansException {
if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
// 决定候选的构造函数
Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {
return ctors;
}
}
}
}
return null;
}
可以看到这个接口是用来解析BeanClass
的构造函数的,SmartInstantiationAwareBeanPostProcessor
的实现类AutowiredAnnotationBeanPostProcessor
,这个类是用来解析确定合适的构造函数,重点解析了@Autowired
注解,并且还解析了@Value
注解和@Lookup
注解。
当解析出来构造函数之后,那么就调用autowireConstructor
方法进行实例化,解析时会new一个构造器解析器ConstructorResolver
,在解析factoryMehod
时也是使用的这个类使用的是instantiateUsingFactoryMethod
这个方法,并且解析factoryMethod
更加复杂,需要判断是否是静态的工厂创建还是实例工厂创建,而自动装配的构造解析相对来说简单一些,使用autowireConstructor
方法进行解析。
最终解析出构造方法和构造参数之后进行实例化:
// 使用合适的构造方法和构造参数进行实例化
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
实例化:
private Object instantiate(
String beanName, RootBeanDefinition mbd, Constructor<?> constructorToUse, Object[] argsToUse) {
try {
// 获取实例化策略,一般使用 CglibSubClassingInstantiationStrategy
InstantiationStrategy strategy = this.beanFactory.getInstantiationStrategy();
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedAction<Object>) () ->
strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse),
this.beanFactory.getAccessControlContext());
}
else {
// 开始实例化
return strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean instantiation via constructor failed", ex);
}
}
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
final Constructor<?> ctor, Object... args) {
if (!bd.hasMethodOverrides()) {
if (System.getSecurityManager() != null) {
// use own privileged to change accessibility (when security is on)
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(ctor);
return null;
});
}
// 实例化类,反射调用
return BeanUtils.instantiateClass(ctor, args);
}
else {
// 如果方法被覆盖,lookup-method 和 replace-method
return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
}
}
如果前面的解析都没有到Bean
,那么就会使用无参构造函数进行解析:
// 省略代码....
// Preferred constructors for default construction?
// 首选的构造器为默认的创建方式,使用了@Primary注解的为首选的创建对象方式
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
// 调用无参构造函数实例化对象
return instantiateBean(beanName, mbd);
实例化Bean
:
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
try {
Object beanInstance;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(
(PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),
getAccessControlContext());
}
else {
// 实例化对象,使用反射进行创建
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
}
// 创建一个Bean的包装器
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
// 初始化Bean的包装器
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
这里可以看到前面使用factoryMethod
和autowireConstructor
解析构造函数进行实例化还是使用无参构造函数进行实例化都是将Bean
进行了包装,那这个包装有啥作用呢?
BeanWrapper的作用
我们先来看下前面的方法是怎么创建BeanWrapper
的:
factory-method
解析,ConstructorResolver#instantiateUsingFactoryMethod
方法:
public BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
// 创建一个Bean的包装器
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
// factoryBean
Object factoryBean;
// factory 工厂类
Class<?> factoryClass;
// 标识是否是静态的工厂
boolean isStatic;
// 省略代码....
}
SmartInstantiationAwareBeanPostProcessor
子类AutowiredAnnotationBeanPostProcessor
解析出构造函数,然后使用ConstructorResolver#autowireConstructor
执行:
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
// 创建一个包装器
BeanWrapperImpl bw = new BeanWrapperImpl();
// 初始化包装器
this.beanFactory.initBeanWrapper(bw);
// 构造函数
Constructor<?> constructorToUse = null;
// 构造参数
ArgumentsHolder argsHolderToUse = null;
// 需要使用的构造参数
Object[] argsToUse = null;
// 明确的构造参数不为空,则赋值给将要执行实例化的构造参数
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
// 省略代码....
}
最终都是会进行转换服务ConversionService
和PropertyEditorRegistry
的注册,一个是用来进行属性类型转换的,一个是用来属性值解析的:
protected void initBeanWrapper(BeanWrapper bw) {
// 获取转换服务放到bean的包装器中
bw.setConversionService(getConversionService());
// 注册定制的属性编辑器
registerCustomEditors(bw);
}
在前面的文章中,介绍了这两个如何使用,而且还自定义了属性编辑器和类型转换,需要的小伙伴可以去看看:
https://www.cnblogs.com/redwinter/p/16167214.html 和 https://www.cnblogs.com/redwinter/p/16241328.html
到这里Bean的实例化就完成了,接着往下看源码:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
// 从缓存中获取FactoryBean的Bean对象
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 实例化对象
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 从包装器中获取Bean对象
Object bean = instanceWrapper.getWrappedInstance();
// 从包装器中获取Bean类型
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// 合并Bean
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
}
点进去:
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
// 执行合并BeanDefinition
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
可以看到这里出现了一个接口MergedBeanDefinitionPostProcessor
,这个接口也是BeanPostProcessor
的子接口,那他到底是干啥用的呢?
MergedBeanDefinitionPostProcessor 接口
点击发现这个接口的实现类全是跟注解相关的,而最重要的是CommonAnnotationBeanPostProcessor
实现类,在构造函数中设置了两个注解:@PostConstruct
和 @PreDestroy
,一个是在初始化完之后调用,一个是容器销毁时调用。
未完待续.....
Spring 源码(14)Spring Bean 的创建过程(5)的更多相关文章
- Spring源码分析之Bean的创建过程详解
前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...
- Spring 源码分析之 bean 依赖注入原理(注入属性)
最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spri ...
- Spring源码-IOC部分-Bean实例化过程【5】
实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...
- dubbo源码分析3-service bean的创建与发布
dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...
- Spring源码分析专题 —— IOC容器启动过程(上篇)
声明 1.建议先阅读<Spring源码分析专题 -- 阅读指引> 2.强烈建议阅读过程中要参照调用过程图,每篇都有其对应的调用过程图 3.写文不易,转载请标明出处 前言 关于 IOC 容器 ...
- 【Spring源码分析】Bean加载流程概览(转)
转载自:https://www.cnblogs.com/xrq730/p/6285358.html 代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. ...
- Spring源码分析:Bean加载流程概览及配置文件读取
很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事的都是Java Web的工作,对于程序员来说,一个Web项目用到Spring,只是配置一下配置文件而已 ...
- 【Spring源码分析】Bean加载流程概览
代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...
- Spring 源码分析之 bean 实例化原理
本次主要想写spring bean的实例化相关的内容.创建spring bean 实例是spring bean 生命周期的第一阶段.bean 的生命周期主要有如下几个步骤: 创建bean的实例 给实例 ...
- 初探Spring源码之Spring Bean的生命周期
写在前面的话: 学无止境,写博客纯粹是一种乐趣而已,把自己理解的东西分享出去,不意味全是对的,欢迎指正! Spring 容器初始化过程做了什么? AnnotationConfigApplication ...
随机推荐
- vue循环时设置多选框禁用状态,v-for
<div v-for="user in users" > <el-radio v-bind:disabled="user.id== ...
- 传染病模型(SIR模型)
- Linux下的cman中文帮助手册配置
Linux下的帮助命令man功能很强大,很好用,但显示的结果是英文,有时候看着还是吃力,就想着要是有man的中文显示结果该多好.网上搜寻一番后,终于找到解决方案,很简单,亲测有效.具体步骤如下: su ...
- circle_clock 简单canvas实现圆弧时钟
渣渣成品图:http://codepen.io/thewindswor... 最近对于圆形有种特别的感情呢...因为写了个cricle_process_bar就像到了用来做时钟大概会比较有趣吧,所以就 ...
- 原生ES6写的Web游戏:ES6-Mario,小美女,小帅哥快来玩啊~~
? ES6-Mario 这是一个用原生ES6语法和HTML5新特性写成的Web 游戏. 通过这个项目,你可以在实践中对ES6的主要内容.HTML Canvas 相关API以及Webpack的基础配置有 ...
- XXE漏洞——介绍及利用
什么是xxe XML外部实体注入,简称XXE漏洞.XML文档结构包括XML声明,DTD文档类型定义,文档元素. XML示例 <?xml version="1.0"?>X ...
- JavaScript 数组(Array)对象的方法
JavaScript 数组(Array)对象的方法 concat() 描述:用于连接两个或多个数组.该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本. 原型:arrayObject.conc ...
- Spring5-IOC容器实现方式
spring提供了两个接口实现IOC容器 (1)BeanFactory:IOC容器基本实现,是Spring内部使用的接口,不提倡开发人员使用 特点:加载配置文件时侯不会创建对象,在获取对象时才会创建对 ...
- 文件IO-Properties
java.lang.Object 继承者 java.util.Dictionary<K,V> 继承者 java.util.Hashtable<Object,Object> 继承 ...
- 时间篇之centos7修复ntpq: read: Connection refused
关于ntp同步时间, 由于是解决问题,所以理论性内容不多. 关于UTC NTP要提供准确的时间,就必须有准确的时间来源,那可以用格林尼治时间吗?答案是否定的. 因为格林尼治时间是以地球自转为基础的时间 ...