Spring 源码(10)Spring Bean 的创建过程(1)
Spring Bean的创建刚开始进行了一些准备工作,比如转换服务的初始化,占位符解析器的初始化,BeanDefinition元数据的冻结等操作,都是为了在创建Bean的过程中保证Bean的正确的创建,接下来开始进行对Bean的创建进行解析。
Bean 的创建步骤
在Spring源码中对Bean的创建遵循一个步骤就是:getBean --> doGetBean --> createBean --> doCreateBean ,常规的Bean的创建过程都是按照这个步骤执行,然后反射实例化,属性填充,初始化,放到一级缓存中。那么非常规的有可能就不遵循这个步骤,比如FactoryBean,InstantiationAwareBeanPostProcessor 等。
上源码:
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
// 遍历所有的beanName
for (String beanName : beanNames) {
// 获取RootBeanDefinition 从缓存中,第一个放入缓存是在 AbstractApplicationContext#invokeBeanFactoryPostProcessors 中的getBeanNamesForType方法中
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 如果不是抽象的,是单例的,是非懒加载的,则进行bean的创建,否则直接跳过
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 是否是FactoryBean
if (isFactoryBean(beanName)) {
// 获取bean实例
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
// 判断获取的Bean是否是FactoryBean
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
// 是否是饥饿初始化,默认是false
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());
}
// 如果是饥饿初始化,则进行bean的创建
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 获取bean
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
// 触发 所有Bean初始化后的回调
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
// 获取单例对象,如果是SmartInitializingSingleton 则调用afterSingletonsInstantiated
// 在监听器中使用@EventListener注解标记的方法就是在这个方法中进行监听器的添加的,会创建一个监听器的适配器
// 调用类为 EventListenerMethodProcessor
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
// 权限检查
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
通过源码可以知道,Spring前期在进行XML进行loadBeanDefinitions加载或者BeanFactoryPostProcessor子类BeanDefinitionRegistryPostProcessor的实现类ConfigurationClassPostProcessor注解解析 出来的BeanDefinition放入两个集合BeanDefinitionMap 和BeanDefinitionNames,这里遍历的是BeanDefinitionNames这个集合,存放的是beanName。
首先是进行了BeanDefinition的合并处理,最终返回的全是RootBeanDefinition,进入源码可以看到这里是从缓存中获取的,如果有则直接取出来,否则再去解析。
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
// 从缓存中获取
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null && !mbd.stale) {
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
那么第一次进行调用时什么地方呢?是在进行BeanFactoryPostProcessor 的执行和解析时调用的,在解析BeanFactoryPostProcessor时调用了 getBeanNamesForType方法,然后调用doGetBeanNamesForType时进行了BeanDefinitionNames集合的遍历合并Bean:
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List<String> result = new ArrayList<>();
// Check all bean definitions.
// 遍历所有的BeanDefinitionNames集合
for (String beanName : this.beanDefinitionNames) {
// Only consider bean as eligible if the bean name is not defined as alias for some other bean.
if (!isAlias(beanName)) {
try {
// 从本地缓存中获取合并的BeanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete.
if (!mbd.isAbstract() && (allowEagerInit ||
(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
// 是否是FactoryBean
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
boolean matchFound = false;
boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));
boolean isNonLazyDecorat
// 省略代码....
}
}
}
}
所以在执行preInstantiateSingletons 预实例化单例时获取的RootBeanDefinition基本是从缓存中获取的。
接着是判断如果是单例的并且不是抽象的,不是懒加载的,那么就进行Bean的创建,然后又判断是否是FactoryBean,如果是那么就进行下一步逻辑。
FactoryBean 是什么?
FactoryBean是用来创建Bean对象的,他是一个接口,方法:
getObject获取bean对象getObjectType获取bean的类型isSingleton是否是单例的,默认是true
在创建对象时,你可以直接在getObject方法中进行new,或者反射,或者是其他都可以,非常的灵活。接下来使用FactoryBean进行自定义的Bean的创建。
定义一个FactoryBean的实现类:
/**
* @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
* @since 1.0
**/
public class MyFactoryBean implements FactoryBean<MyUser> {
@Override
public MyUser getObject() throws Exception {
// 直接new一个对象
return new MyUser();
}
@Override
public Class<?> getObjectType() {
return MyUser.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
定义MyUser
/**
* @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
* @since 1.0
**/
public class MyUser {
}
xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="myFactoryBean" class="com.redwinter.selffactorybean.MyFactoryBean"/>
</beans>
测试类:
/**
* @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
* @since 1.0
**/
public class FactoryBeanTest {
@Test
public void test(){
MyClassPathXmlApplicationContext context = new MyClassPathXmlApplicationContext("spring-factory.xml");
Object myFactoryBean = context.getBean("myFactoryBean");
System.out.println(myFactoryBean);
Object myFactoryBean2 = context.getBean("&myFactoryBean");
System.out.println(myFactoryBean2);
}
}
输出:
com.redwinter.test.selffactorybean.MyUser@2d554825
com.redwinter.test.selffactorybean.MyFactoryBean@68837a77
这里可以看到FactoryBean 创建Bean的时候,xml注册的是一个FactoryBean的实现,但是获取出来又是具体的MyUser对象,这里Spring使用了懒加载的机制,在Spring 对Bean进行初始化时,实际上只将FactoryBean的实现类注册到了Spring容器中,当我们需要使用的时候,才去判断,如果是FactoryBean类型的,那么就去调用getObject方法去创建对象。如果是第二次去获取Bean,那么是从缓存中获取的,如果是获取&前缀的Bean,那就直接返回。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
// 判断是否是&前缀标识
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
// 从缓存中获取
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
// 判断是否是合成的Bean,是否是应用程序本身设置的,比如某些aop 就是合成的Bean
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 执行getObject方法获取Bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}

BeanFactory 和FactoryBean 的区别?
根据前面的文章介绍,我们知道BeanFactory是一个Bean的创建工厂,比如AbstractApplicationContext就是BeanFactory的实现类,这个类就是用来创建Bean的,创建出来的Bean放在缓存中。而FactoryBean就是Bean实例,是由BeanFactory创建的,并且FactoryBean也是用来创建Bean对象,使用getObject方法进行创建,也是会放在缓存中供下次直接获取,而且如果在使用时需要使用FactoryBean的实例时需要以&前缀才能获取到,比如getBean("&myFactoryBean"); 如果是获取通过getObject方法创建的对象时,就不需要添加&前缀,比如getBean("myFactoryBean"); 总结一下:
相同点:
- 都是用来创建对象的
- 都是创建出来之后放入缓存中供下次直接使用
不同点:
BeanFactory是一个对象创建工厂,而FactoryBean是一个Bean实例BeanFactory创建的对象一般来说都是使用反射调用构造函数创建的,而FactoryBean创建对象是调用getObject方法创建,并且创建方式不一定是通过反射,可以是直接new对象或者其他方式FactoryBean在获取对象时,可以获取到两个对象,一个是存放在BeanFactory创建的缓存中,通过&beanName获取的FactoryBean的实现类对象,一个是调用getObject创建的,通过beanName获取的具体对象。

Bean的创建过程非常复杂,下一篇继续。
Spring 源码(10)Spring Bean 的创建过程(1)的更多相关文章
- Spring源码分析之Bean的创建过程详解
前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...
- Spring源码-IOC部分-Bean实例化过程【5】
实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...
- Spring 源码分析之 bean 依赖注入原理(注入属性)
最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spri ...
- 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加载流程概览
代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...
- 【Spring源码分析】Bean加载流程概览(转)
转载自:https://www.cnblogs.com/xrq730/p/6285358.html 代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. ...
- Spring源码分析:Bean加载流程概览及配置文件读取
很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事的都是Java Web的工作,对于程序员来说,一个Web项目用到Spring,只是配置一下配置文件而已 ...
- Spring 源码分析之 bean 实例化原理
本次主要想写spring bean的实例化相关的内容.创建spring bean 实例是spring bean 生命周期的第一阶段.bean 的生命周期主要有如下几个步骤: 创建bean的实例 给实例 ...
- 初探Spring源码之Spring Bean的生命周期
写在前面的话: 学无止境,写博客纯粹是一种乐趣而已,把自己理解的东西分享出去,不意味全是对的,欢迎指正! Spring 容器初始化过程做了什么? AnnotationConfigApplication ...
随机推荐
- Redis 的持久化机制是什么?各自的优缺点?
Redis 提供两种持久化机制 RDB 和 AOF 机制: 1.RDBRedis DataBase)持久化方式: 是指用数据集快照的方式半持久化模式) 记录 redis 数据库的所有键值对,在某个时间 ...
- Redis 是单进程单线程的?
Redis 是单进程单线程的,redis 利用队列技术将并发访问变为串行访问,消 除了传统数据库串行控制的开销.
- 简单vue项目脚手架
简单vue项目脚手架 github地址 使用技术栈 webpack(^2.6.1) webpack-dev-server(^2.4.5) vue(^2.3.3) vuex(^2.3.1) vue-ro ...
- C2678 二进制“<”: 没有找到接受“const ***”类型的左操作数的运算符解决办法
正确代码如下:#include<iostream> #include<string> #include<map> using namespace std; /*仿函 ...
- java集合(arraylist详解)
一.ArrayList概述 ArrayList是实现List接口的动态数组,所谓动态就是它的大小是可变的.实现了所有可选列表操作,并允许包括 null 在内的所有元素.除了实现 List 接口外,此类 ...
- Javascript中数组的判断方法
摘要: 1.数组检测的方法: 1) typeof . 2) instanceof . 3) constructor . 4) Object.prototype.toString. 5) Array.i ...
- three车辆自由转弯(vue 极品飞车)
//最近没有时间整理代码,就这样吧 <template> <div> <div id="map"></div> </div&g ...
- 初识react中高阶组件
高阶组件并不是一个组件,而是一个函数 这个函数返回值是一个组件,并且接受一个组件做为参数:并且返回一个新组件: function HighOC(WrapComponent){ //定义一个高阶组件 , ...
- 让我们写一个 Win32 文本编辑器吧 - 2. 计划和显示
让我们写一个 Win32 文本编辑器吧 - 2. 计划和显示 如果你已经阅读了简介,相信你已经对我们接下来要做的事情有所了解. 本文,将会把简介中基础程序修改为一个窗体应用程序.并对编辑器接下来的编辑 ...
- .NET如何快速比较两个byte数组是否相等
目录 前言 评测方案 几种不同的方案 For循环 Memcmp 64字长优化 SIMD Sse Avx2 SequenceCompare 总结 参考文献 前言 之前在群里面有群友问过一个这样的问题,在 ...