
1、bean与BeanFactory的关系

2、BeanFactory与ApplicationContext区别
BeanFactory是Spring框架中IoC容器的顶层接口,它只是用来定义一些基础功能,定义一些基础规范,而 ApplicationContext是它的一个子接口,所以ApplicationContext是具备BeanFactory提供的全部功能的。
通常,我们称BeanFactory为Spring IoC的基础容器,ApplicationContext是容器的高级接口,比 BeanFactory要拥有更多的功能,比如说国际化支持和资源访问(xml,java配置类)等等。

3、启动 IoC 容器的方式
3.1 Java环境下启动IoC容器
ClassPathXmlApplicationContext:从类的根路径下加载配置文件(推荐使用)FileSystemXmlApplicationContext:从磁盘路径上加载配置文件AnnotationConfigApplicationContext:纯注解模式下启动Spring容器3.2 Web环境下启动IoC容器
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--配置Spring ioc容器的配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--使用监听器启动Spring的IOC容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--告诉ContextloaderListener知道我们使用注解的方式启动ioc容器-->
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<!--配置启动类的全限定类名-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.riemann.SpringConfig</param-value>
</context-param>
<!--使用监听器启动Spring的IOC容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
1、lazy-Init 延迟加载
1.1 Bean的延迟加载(延迟创建)
ApplicationContext 容器的默认行为是在启动服务器时将所有 singleton bean 提前进行实例化。提前实例化意味着作为初始化过程的一部分,ApplicationContext 实例会创建并配置所有的singleton bean。
比如:
<bean id="testBean" class="com.riemann.LazyBean" />
该bean默认的设置为:
<bean id="testBean" calss="com.riemann.LazyBean" lazy-init="false" />
lazy-init="false",立即加载,表示在spring启动时,立刻进行实例化。
如果不想让一个singleton bean 在 ApplicationContext实现初始化时被提前实例化,那么可以将bean
设置为延迟实例化。
<bean id="testBean" calss="com.riemann.LazyBean" lazy-init="true" />
设置 lazy-init 为 true 的 bean 将不会在 ApplicationContext 启动时提前被实例化,而是第一次向容器
通过 getBean 索取 bean 时实例化的。
如果一个 bean 的 scope 属性为 scope="pototype" 时,即使设置了 lazy-init="false",容器启动时也不会实例化bean,而是调用 getBean 方法实例化的。
1.2 应用场景
Bean 设置延迟加载,这样偶尔使用的时候再加载,不必要从一开始该 Bean 就占用资源2、FactoryBean 和 BeanFactory
BeanFactory接口是容器的顶级接口,定义了容器的一些基础行为,负责生产和管理Bean的一个工厂,具体使用它下面的子接口类型,比如ApplicationContext。
此处我们重点分析FactoryBean:
Spring中Bean有两种,一种是普通Bean,一种是工厂Bean(FactoryBean),FactoryBean可以生成
某一个类型的Bean实例(返回给我们),也就是说我们可以借助于它自定义Bean的创建过程。
Bean创建的三种方式中的静态方法和实例化方法和FactoryBean作用类似,FactoryBean使用较多,尤
其在Spring框架一些组件中会使用,还有其他框架和Spring框架整合时使用。
我们下面来看个例子:
FactoryBean接口:
// 可以让我们自定义Bean的创建过程(完成复杂Bean的定义)
public interface FactoryBean<T> {
@Nullable
// 返回FactoryBean创建的Bean实例,如果isSingleton返回true,则该实例会放到Spring容器 的单例对象缓存池中Map
T getObject() throws Exception;
@Nullable
// 返回FactoryBean创建的Bean类型
Class<?> getObjectType();
// 返回作用域是否单例
default boolean isSingleton() {
return true;
}
}
Company类:
@Data
public class Company {
private String name;
private String address;
private int scale;
}
CompanyFactoryBean类:
public class CompanyFactoryBean implements FactoryBean<Company> {
private String companyInfo; // 公司名称,地址,规模
public void setCompanyInfo(String companyInfo) {
this.companyInfo = companyInfo;
}
@Override
public Company getObject() throws Exception {
// 模拟创建复杂对象Company
Company company = new Company();
String[] strings = companyInfo.split(",");
company.setName(strings[0]);
company.setAddress(strings[1]);
company.setScale(Integer.parseInt(strings[2]));
return company;
}
@Override
public Class<?> getObjectType() {
return Company.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
xml配置:
<bean id="companyBean" class="com.riemann.factory.CompanyFactoryBean">
<property name="companyInfo" value="腾讯,南山科技园,60000"/>
</bean>
测试,获取FactoryBean产生的对象:
Object companyBean = applicationContext.getBean("companyBean"); System.out.println("bean:" + companyBean);
// 结果如下
bean:Company{name='腾讯', address='南山科技园', scale=60000}
测试,获取FactoryBean,需要在id之前添加“&”:
Object companyBean = applicationContext.getBean("&companyBean");
System.out.println("bean:" + companyBean);
// 结果如下
bean:com.riemann.factory.CompanyFactoryBean@53f6fd09
3、后置处理器
Spring提供了两种后处理bean的扩展接口,分别为 BeanPostProcessor 和
BeanFactoryPostProcessor,两者在使用上是有所区别的。
工厂初始化(BeanFactory)—> Bean对象
BeanFactory初始化之后可以使用BeanFactoryPostProcessor进行后置处理做一些事情Bean对象实例化(并不是Bean的整个生命周期完成)之后可以使用BeanPostProcessor进行后置处理做一些事情注意:对象不一定是springbean,而springbean一定是个对象
3.1 BeanPostProcessor
BeanPostProcessor是针对Bean级别的处理,可以针对某个具体的Bean。
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;
}
}
该接口提供了两个方法,分别在Bean的初始化方法前和初始化方法后执行,具体这个初始化方法指的是 什么方法,类似我们在定义bean时,定义了init-method所指定的方法。
定义一个类实现了BeanPostProcessor,默认是会对整个Spring容器中所有的bean进行处理。如果要对具体的某个bean处理,可以通过方法参数判断,两个类型参数分别为Object和String,第一个参数是每个bean的实例,第二个参数是每个bean的name或者id属性的值。所以我们可以通过第二个参数,来判断我们将要处理的具体的bean。
注意:处理是发生在Spring容器的实例化和依赖注入之后。
3.2 BeanFactoryPostProcessor
BeanFactory级别的处理,是针对整个Bean的工厂进行处理,典型应用:PropertyPlaceholderConfigurer
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
此接口只提供了一个方法,方法参数为ConfigurableListableBeanFactory,该参数类型定义了一些方法:

其中有个方法名为getBeanDefinition的方法,我们可以根据此方法,找到我们定义bean 的 BeanDefinition对象。然后我们可以对定义的属性进行修改,以下是BeanDefinition中的方法:

方法名字类似我们bean标签的属性,setBeanClassName对应bean标签中的class属性,所以当我们拿到BeanDefinition对象时,我们可以手动修改bean标签中所定义的属性值。
BeanDefinition对象:我们在 XML 中定义的 bean标签,Spring 解析 bean 标签成为一个 JavaBean, 这个JavaBean 就是 BeanDefinition。
注意:调用 BeanFactoryPostProcessor 方法时,这时候bean还没有实例化,此时 bean 刚被解析成 BeanDefinition对象。
1、Spring IoC容器初始化主体流程
1.1 Spring IoC的容器体系
IoC容器是Spring的核心模块,是抽象了对象管理、依赖关系管理的框架解决方案。Spring 提供了很多的容器,其中 BeanFactory 是顶层容器(根容器),不能被实例化,它定义了所有 IoC 容器必须遵从的一套原则,具体的容器实现可以增加额外的功能,比如我们常用到的ApplicationContext,其下更具体的实现如 ClassPathXmlApplicationContext 包含了解析 xml 等一系列的内容,AnnotationConfigApplicationContext 则是包含了注解解析等一系列的内容。Spring IoC 容器继承体系非常聪明,需要使用哪个层次用哪个层次即可,不必使用功能大而全的。
BeanFactory 顶级接口方法栈如下:

BeanFactory 容器继承体系如下:

通过其接口设计,我们可以看到我们一贯使用的 ApplicationContext 除了继承BeanFactory的子接口, 还继承了ResourceLoader、MessageSource等接口,因此其提供的功能也就更丰富了。
下面我们以 ClasspathXmlApplicationContext 为例,深入源码说明 IoC 容器的初始化流程。
1.2 Bean生命周期关键时机点
思路:创建一个类 RiemannBean ,让其实现几个特殊的接口,并分别在接口实现的构造器、接口方法中 断点,观察线程调用栈,分析出 Bean 对象创建和管理关键点的触发时机。
RiemannBean类
public class RiemannBean implements InitializingBean, ApplicationContextAware {
private ItBean itBean;
public void setItBean(ItBean itBean) {
this.itBean = itBean;
}
public RiemannBean() {
System.out.println("RiemannBean 构造器...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("RiemannBean afterPropertiesSet...");
}
public void print() {
System.out.println("RiemannBean print方法业务逻辑执行...");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("RiemannBean setApplicationContext...");
}
}
BeanPostProcessor 接口实现类
public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor() {
System.out.println("BeanPostProcessor 实现类构造函数...");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if("riemannBean".equals(beanName)) {
System.out.println("BeanPostProcessor 实现类 postProcessBeforeInitialization 方法被调用中...");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if("riemannBean".equals(beanName)) {
System.out.println("BeanPostProcessor 实现类 postProcessAfterInitialization 方法被调用中...");
}
return bean;
}
}
BeanFactoryPostProcessor 接口实现类
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public MyBeanFactoryPostProcessor() {
System.out.println("BeanFactoryPostProcessor的实现类构造函数...");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryPostProcessor的实现方法调用中...");
}
}
applicationContext.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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
">
<bean id="riemannBean" class="com.riemann.RiemannBean">
<property name="ItBean" ref="itBean"/>
</bean>
<bean id="myBeanFactoryPostProcessor" class="com.riemann.MyBeanFactoryPostProcessor"/>
<bean id="myBeanPostProcessor" class="com.riemann.MyBeanPostProcessor"/>
<!--循环依赖问题-->
<bean id="itBean" class="com.riemann.ItBean">
<property name="riemannBean" ref="riemannBean"/>
</bean>
</beans>
IoC 容器源码分析用例
public class IocTest {
/**
* Ioc 容器源码分析基础案例
*/
@Test
public void testIoC() {
// ApplicationContext是容器的高级接口,BeanFacotry(顶级容器/根容器,规范了/定义了容器的基础行为)
// Spring应用上下文,官方称之为 IoC容器(错误的认识:容器就是map而已;准确来说,map是ioc容器的一个成员,
// 叫做单例池, singletonObjects,容器是一组组件和过程的集合,包括BeanFactory、单例池、BeanPostProcessor等以及之间的协作流程)
/**
* Ioc容器创建管理Bean对象的,Spring Bean是有生命周期的
* 构造器执行、初始化方法执行、Bean后置处理器的before/after方法:AbstractApplicationContext#refresh#finishBeanFactoryInitialization
* Bean工厂后置处理器初始化、方法执行:AbstractApplicationContext#refresh#invokeBeanFactoryPostProcessors
* Bean后置处理器初始化:AbstractApplicationContext#refresh#registerBeanPostProcessors
*/
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
RiemannBean riemannBean = applicationContext.getBean(RiemannBean.class);
System.out.println(riemannBean);
}
}
上面注释是我已经断点调试完验证的结果
1.3 小结
根据上面的调试分析,我们发现Bean对象创建的几个关键时机点代码层级的调用都在 AbstractApplicationContext 类 的 refresh 方法中,可⻅这个方法对于Spring IoC 容器初始化来说相当关键,汇总如下:
关键点 | 触发代码 |
|---|---|
构造器 | AbstractApplicationContext#refresh#finishBeanFactoryInitialization(beanFactory) |
BeanFactoryPostProcessor 初始化 | AbstractApplicationContext#refresh#invokeBeanFactoryPostProcessors(beanFactory) |
BeanFactoryPostProcessor 方法调用 | AbstractApplicationContext#refresh#invokeBeanFactoryPostProcessors(beanFactory) |
BeanPostProcessor 初始化 | AbstractApplicationContext#refresh#registerBeanPostProcessors(beanFactory) |
BeanPostProcessor 方法调用 | AbstractApplicationContext#refresh#finishBeanFactoryInitialization(beanFactory) |
2、Spring IoC容器初始化主流程源码剖析
由上分析可知,Spring IoC 容器初始化的关键环节就在 AbstractApplicationContext#refresh() 方法中 ,我们查看 refresh 方法来俯瞰容器创建的主体流程,主体流程下的具体子流程我们后面再来讨论。
@Override
public void refresh() throws BeansException, IllegalStateException {
/**
* 对象锁加锁
*/
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
/**
* 刷新前的预处理
* 表示在真正做refresh操作之前需要准备做的事情:
* 设置Spring容器启动时间
* 开启活跃状态,撤销关闭状态
* 验证环境信息里一些必须存在的属性
*/
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
/**
* 获取BeanFactory:默认实现是DefaultListableBeanFactory
* Bean获取并封装成BeanDefinition对象
* 加载BeanDefinition 并注册到BeanDefinitionRegistry
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
/**
* 获取BeanFactory的准备工作:BeanFactory进行一些设置,比如context的类加载器等。
*/
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
/**
* BeanFactory准备工作完成后进行的后置处理工作
*/
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
/**
* 实例化实现了BeanFactoryPostProcessor接口的Bean,并调用接口方法
*/
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
/**
* 注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执行
*/
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
/**
* 初始化MessageSource组件(做国际化功能、消息绑定、消息解析)
*/
initMessageSource();
// Initialize event multicaster for this context.
/**
* 初始化事件派发器
*/
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
/**
* 子类重写这个方法,在容器刷新的时候可以自定义逻辑,如创建Tomcat、Jetty等WEB服务器
*/
onRefresh();
// Check for listener beans and register them.
/**
* 注册应用的监听器,就是注册实现了ApplicationListener接口的监听器bean
*/
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
/**
* 初始化所有剩下的非懒加载的单例bean
* 初始化创建非懒加载方式的单例Bean实例(未设置属性)
* 填充属性
* 初始化方法调用(比如调用afterPropertiesSet方法、init-method方法)
* 调用BeanPostProcessor(Bean的后置处理器)对实例bean进行后置处理
*/
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
/**
* 完成context的刷新,主要是调用LifecycleProcessor的onRefresh()方法,并且发布事件(ContextRefreshEvent)
*/
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.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}欢迎大家关注我的公众号【老周聊架构】,AI、大数据、云原生、物联网等相关领域的技术知识分享。