采用ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
方式构建Spring容器并查看其内部运行过程.php
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
复制代码
public class User {
private String username;
private String password;
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
复制代码
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="user" class="com.jimisun.learnspringboot.web.User">
<constructor-arg index="0" value="jimisun"/>
<constructor-arg index="1" value="jimisun"/>
</bean>
</beans>
复制代码
public class Main {
public static void main(String[] args) {
// 用咱们的配置文件来启动一个 ApplicationContext
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
System.out.println("context 启动成功");
User user = context.getBean(User.class);
System.out.println(user.toString());
}
}
复制代码
ApplicationContext 启动过程当中,会建立SPring Bean容器,而后初始化相关Bean,再向Bean中注入其相关依赖。html
因此咱们仅仅须要Debug跟踪Main方法中ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
这一句代码,查看Spring是如何建立ApplicationContext容器并将xml中的配置信息装配进容器的.java
功能:设置此应用程序上下文的配置文件位置,若是未设置;Spring能够根据须要使用默认值web
setConfigLocations(configLocations);spring
在Main方法Debug启动进入断点,按F7跟进入其方法查看,会进入ClassPathXmlApplicationContext
类的构造方法中数组
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
private Resource[] configResources;
// 若是已经有 ApplicationContext 并须要配置成父子关系,那么调用这个构造方法
public ClassPathXmlApplicationContext(ApplicationContext parent) {
super(parent);
}
...
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
// 根据提供的路径,处理成配置文件数组(以分号、逗号、空格、tab、换行符分割)
setConfigLocations(configLocations);
if (refresh) {
refresh(); // 核心方法 剩余的全部步骤都在此方法中!!!
}
}
...
}
复制代码
首先执行"设置配置位置setConfigLocations"
的方法,解析SpringXML配置文件
地址存储到configLocations
属性中。缓存
public void setConfigLocations(@Nullable String... locations) {
//判断配置路径是否为null
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
//循环将配置文件路径存储到属性configLocations中
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
复制代码
注意:除了第一步设置XML配置文件路径,剩余的步骤都在该类的refresh();这个方法中执行,因此咱们须要Debug跟进入这个方法springboot
refresh();方法以下所示;由于整个SpringApplication的构建都在这个方法 里面因此就如今这里展示一下和你们混个脸熟.架构
public void refresh() throws BeansException, IllegalStateException {
 //对下面的代码块添加同步锁
synchronized (this.startupShutdownMonitor) {
 //第二步: 执行建立容器前的准备工做 :记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
prepareRefresh();
  //第三步:建立Bean容器,加载XML配置信息 : 若是存在容器进行销毁旧容器,建立新容器,解析XML配置文件为一个个BeanDefinition定义注册到新容器(BeanFactory)中,注意Bean未初始化
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//第四步: 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
prepareBeanFactory(beanFactory);
try {
//第五步:加载并执行后置处理器
postProcessBeanFactory(beanFactory);
//执行postProcessBeanFactory()方法
invokeBeanFactoryPostProcessors(beanFactory);
// 实例化拦截Bean建立的后置处理器beanPostProcessors
registerBeanPostProcessors(beanFactory);
//第六步: 初始化Spring容器的消息源
initMessageSource();
//第七步:初始化Spring容器事件广播器
initApplicationEventMulticaster();
// 空方法
onRefresh();
//第八步:注册事件监听器 
registerListeners();
//第九步核心方法:初始化(构造)全部在XML文件中配置的单例非延迟加载的bean
finishBeanFactoryInitialization(beanFactory);
//第十步:清理缓存,若是容器中存Bean名为lifecycleProcessor的Bean 对其进行注册,若是不存在建立一个DefaultLifecycleProcessor进行注册
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 摧毁已经建立的单身人士以免悬空资源。
destroyBeans();
// 重置'有效'标志。
cancelRefresh(ex);
// 向调用者传播异常。
throw ex;
}
finally {
//重置Spring核心的工具类的缓存
resetCommonCaches();
}
}
}
复制代码
第二步的主要工做:准备工做,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符,初始化事件属性。app
prepareRefresh();
protected void prepareRefresh() {
// 记录启动时间,
// 将 active 属性设置为 true,closed 属性设置为 false,它们都是 AtomicBoolean类型
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
//打印Logger
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// 在上下文环境中初始化任何占位符属性源 空方法 默认状况下不执行任何操做。
initPropertySources();
// 校验 xml 配置文件
getEnvironment().validateRequiredProperties();
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
复制代码
主要工做:进行销毁旧容器,建立新容器,加载BeanDefinition到BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
@Override
protected final void refreshBeanFactory() throws BeansException {
// 若是ApplicationContext中已经的BeanFactory属性已经有值,销毁此BeanFactory全部 Bean,关闭 BeanFactory,从新建立一个新的Bean容器设置给ApplicationContext的beanFactory属性
if (hasBeanFactory()) {
//销毁容器
destroyBeans();
//建立类型为DefaultListableBeanFactory新容器放入BeanFactory变量中
closeBeanFactory();
}
try {
//建立类型为DefaultListableBeanFactory新容器放入BeanFactory变量中
DefaultListableBeanFactory beanFactory = createBeanFactory();
//设置BeanFactory的序列化ID也就是其类名
beanFactory.setSerializationId(getId());
// 设置 BeanFactory 的两个配置属性:是否容许 Bean 覆盖、是否容许循环引用
customizeBeanFactory(beanFactory);
//这个方法将根据配置,加载各个Bean,而后放到 BeanFactory 中 注意:这里的加载并非初始化这个Bean 而是以Key-value的形式存储在beanFactory; beanName-> beanDefinition 的 map
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
复制代码
主要工做:在Bean容器建立完毕会"手动"注册一些特殊的 bean。官网这样解释: " 配置工厂的标准上下文特征,例如上下文的ClassLoader和后处理器 "。
具体方法 : prepareBeanFactory(factory) ;
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 这里设置为加载当前 ApplicationContext 类的类加载器
beanFactory.setBeanClassLoader(getClassLoader());
// 设置 Bean的表达式解析器
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
//默认添加一个ApplicationContextAwareProcessor的BeanPostProcessor,实现了ApplicationContextAware接口的Bean,Spring会将上下文ApplicationContext注入Bean属性中
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 下面几行的意思就是,若是某个 bean 依赖于如下几个接口的实现类,在自动装配的时候忽略它们,
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
/** * 下面几行就是为特殊的几个 bean 赋值,若是有 bean 依赖了如下几个,会注入这边相应的值, * 以前咱们说过,"当前 ApplicationContext 持有一个 BeanFactory",这里解释了第一行 * ApplicationContext 还继承了 ResourceLoader、ApplicationEventPublisher、MessageSource * 因此对于这几个依赖,能够赋值为 this,注意 this 是一个 ApplicationContext * 那这里怎么没看到为 MessageSource 赋值呢?那是由于 MessageSource 被注册成为了一个普通的 bean */ beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
//注册早期后处理器以检测内部bean做为ApplicationListeners
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 若是检测到LoadTimeWeaver 准备编织 不是咱们本章的重点无需关注
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
//默认注册 environment systemEnvironment systemProperties的Bean 咱们能够选择覆盖
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
```
复制代码
主要功能:实例化在XML配置中实现了BeanFactoryPostProcessor和BeanPostProcessors接口的Bean并执行其回调方法.注意:此时普通的Bean仍然并无初始化
//实例化并调用XML配置中实现了BeanFactoryPostProcessors接口的的回调
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
//实例化并调用XML配置中实现了BeanPostProcessors接口的的回调
registerBeanPostProcessors(beanFactory);
复制代码
//注解:这里在建立完成Bean容器后执行BeanFactoryPostProcessors接口的回调,咱们能够在Bean容器初始化完成的时候完成咱们本身的业务逻辑(不多用),而后是registerBeanPostProcessors(beanFactory)方法,此方法的官方解释是:"Register bean processors that intercept bean creation(若是存在则注册拦截bean建立的bean后置处理器)"
复制代码
主要功能: 初始化MessageSource。若是在此上下文中未定义,则使用parent。
// 初始化ApplicationContext的消息源。
initMessageSource();
复制代码
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//判断beanFactory中是否有messageSource的Bean
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// 使MessageSource知道父MessageSource
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
//若是没有父MessageSource,则此消息源设置为父MessageSource
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using MessageSource [" + this.messageSource + "]");
}
}
else {
// 若是没有则建立一个默认的DelegatingMessageSource消息源
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isTraceEnabled()) {
logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
}
}
}
复制代码
PS : 在实际项目中咱们不多会用到Spring的事件广播器,由于如今都是分布式应用了局部通信不多使用了 一篇很棒的关于Spring容器的事件讲解 juejin.im/post/5a543c…
主要功能 : 注册Spring的事件广播器用于广播Spring的内置事件和自定义事件
initApplicationEventMulticaster();
protected void initApplicationEventMulticaster() {
//初始化ApplicationEventMulticaster
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
//若是在上下文中没有定义,则建立一个默认的SimpleApplicationEventMulticaster。
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
复制代码
主要功能 : 实例化实现ApplicationListener接口的bean。
// 注册监听器
finishBeanFactoryInitialization(beanFactory);
复制代码
protected void registerListeners() {
//首先注册静态指定的侦听器
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
//下面是咱们自定义的监听器,Spring文档中给出的建议是 "不要在这里初始化FactoryBeans:咱们须要保留全部常规bean"
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
//使用已经注册的事件广播器,发布早期的应用程序事件......
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
复制代码
功能:执行到这一步,Spring.xml配置文件中的特殊的Bean该注册的也注册了,该调用的也调用了,就剩下了普通的Bean了,在这一步就都实例化了.(仅仅是非延迟实例化的单例Bean),也就是说这一步就已经完成了Bean工厂(ApplicationContext)的初始化了.
// 实例化全部SPring.xml配置文件中配置的非延迟实例化的单例Bean
finishBeanFactoryInitialization(beanFactory);
复制代码
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 初始化此上下文的转换服务
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
//若是没有bean后处理器,则注册默认的嵌入值解析器(例如PropertyPlaceholderConfigurer bean)以前注册过;此时,主要用于注释属性值的分辨率。
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// 尽早初始化LoadTimeWeaverAware bean以容许尽早注册其变换器。
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// 中止使用临时ClassLoader进行类型匹配。
beanFactory.setTempClassLoader(null);
// 容许缓存全部bean定义元数据,而不指望进一步的更改。
beanFactory.freezeConfiguration();
// 实例化全部剩余(非延迟初始化)单例。
beanFactory.preInstantiateSingletons();
}
复制代码
功能:进行相关的容器建立完成时的操做,回收相关资源
finishRefresh();
resetCommonCaches();
复制代码
protected void finishRefresh() {
//清除上下文级资源缓存(例如来自扫描的ASM元数据)。
clearResourceCaches();
//为此上下文初始化生命周期处理器。
initLifecycleProcessor();
// 首先将刷新传播到生命周期处理器。
getLifecycleProcessor().onRefresh();
// 广播最终事件
publishEvent(new ContextRefreshedEvent(this));
// 若是处于活动状态,请参与LiveBeansView
LiveBeansView.registerApplicationContext(this);
}
复制代码
//清除一些单例的工具类的缓存
protected void resetCommonCaches() {
ReflectionUtils.clearCache();
AnnotationUtils.clearCache();
ResolvableType.clearCache();
CachedIntrospectionResults.clearClassLoader(getClassLoader());
}
复制代码
能够看到Bean容器中的Bean定义映射关系的Map中存放的是key(String)
->GenericBeanDefinition
的映射,那么GenericBeanDefinition
又是什么呢?
BeanDefinition
中保存了咱们的 Bean 信息
,好比这个 Bean 指向的是哪一个类、是不是单例的、是否懒加载、这个 Bean 依赖了哪些 Bean 等等。
经过Debug
的过程当中咱们能够看到咱们使用ClassPathXmlApplicationContext
构造的ApplicationContext
对象其实在内部维护了一个属性名为beanFactory
,咱们的SpringBean都被定义在这个属性里面,也就是说beanFactory
这个属性才是容器,ApplicationContext
仅仅是作了一层包装.那么beanFactory
又是什么呢?
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
...
}
复制代码
能够看到DefaultListableBeanFactory
类也是Bean容器,并且是继承了全部其余的容器的功能,能够说是最为强大的容器;例如具备(分层,获取多个容器,注入功能....)
第一次参阅源码写的比较慎重,其中因为身体抱恙又有所当误,因此在发布本章的时候也是几天后了,总的来讲本章并无什么重点,仅仅是把Spring的IOC容器的启动过程进行了标注,并未作过多底层的深度剖析,例如loadBeanDefinitions(beanFactory)Spring如何将XMl文件的配置装载入Bean工厂
,以及后面的每一个注释均可以新开一篇长篇大论的文章,后面尽量的在Spring Framework深度剖析专栏中更为详细的学习Spring总体架构源码,本文是根据原文https://juejin.im/post/5bc5c88df265da0b001f5dee的学习笔记,将步骤更为清晰的展示
该教程所属Java工程师之Spring Framework深度剖析专栏,本系列相关博文目录 Java工程师之Spring Framework深度剖析专栏