上篇写了探索SpringBoot-结合idea搭建Maven工程 续(五),好了,基本上关于Idea
这块暂时先告一个段落了。下面正式来探索下Spring Boot
相关的内容。java
在learn-spring-framework-2.x
中的pom文件中,加上最新的spring-context
依赖。表示在这个模块中,咱们使用的依赖是spring2.x
。spring
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>2.0.8</version>
</dependency>
复制代码
由于spring2.x
时,必须须要编写xml
文件来加载spring上下文
。因此,咱们除了启动类以后,还打算编写三个xml
文件。bash
在configurable-context.xml
中,咱们使用import
和Java的System Property
来引入不一样环境所须要的上下文。ide
<import resource="classpath:/META-INF/${env}-context.xml"/>
复制代码
在dev-context.xml
和prod-context.xml
中分别引入相同名称的Bean
,可是这个Bean
的存在不一样的属性值。函数
dev-context.xml
post
<!-- dev 环境 value Bean 定义-->
<bean id="name" class="java.lang.String">
<constructor-arg>
<value>shane</value>
</constructor-arg>
</bean>
复制代码
prod-context.xml
学习
<!-- prod 环境 name Bean 定义-->
<bean id="name" class="java.lang.String">
<constructor-arg>
<value>微秒</value>
</constructor-arg>
</bean>
复制代码
最后定义启动类,启动类显示加载Spring
上下文,并输出id
为name
的Bean
的属性值。固然会根据System Property
的内容来动态加载不一样环境下的Bean
,而且输出不一样的值。this
这么作,也是为了演示Spring
最最基础的功能,做为一个对象工厂的能力。idea
ConfigurableApplicationContextBootstrap.java
spa
public class ConfigurableApplicationContextBootstrap {
static {
// 调整系统属性 "env",实现 "name" bean 的定义切换
// envValue 可能来自于 "-D" 命令行启动参数
// 参数当不存在时,使用 "prod" 做为默认值
String envValue = System.getProperty("env", "dev");
System.setProperty("env", envValue);
}
public static void main(String[] args) {
// 定义 XML ApplicationContext
// 先留意下这个location的方式,不须要写classpath的前缀
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/configurable-context.xml");
// "name" bean 对象
String value = (String) context.getBean("name");
// "name" bean 内容输出
System.out.println("Bean 'name' 的内容为:" + value);
// 关闭上下文
context.close();
}
复制代码
控制台输出
思考下Spring
在这个过程当中,作了什么事情呢?
xml
文件,初始化Spring上下文
Spring上下文
中的对象咱们进入到ClassPathXmlApplicationContext(String)
构造函数中,能够发现调用了另一个构造函数ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
并且设置了refresh
参数为true
,parent
参数为null
。
/** * Create a new ClassPathXmlApplicationContext, loading the definitions * from the given XML file and automatically refreshing the context. * @param configLocation resource location * @throws BeansException if context creation failed */
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
/** * Create a new ClassPathXmlApplicationContext with the given parent, * loading the definitions from the given XML files. * @param configLocations array of resource locations * @param refresh whether to automatically refresh the context, * loading all bean definitions and creating all singletons. * Alternatively, call refresh manually after further configuring the context. * @param parent the parent context * @throws BeansException if context creation failed * @see #refresh() */
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
复制代码
经过注释能够知道构造函数的做用是用给定的parent建立一个ClassPathXmlApplicationContext,而且根据XML文件加载定义的对象
bean
定义而且建立全部的单例对象Spring
是存在父子上下文的,以后有机会讲到)构造函数首先解析了资源文件并设置为上下文的一个属性,以后进入到了关键的refresh
函数中。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing. [1.为refresh准备上下文]
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.[2.告知子类refresh内部bean工厂]
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.[3.准备须要在本次上文中使用的bean工厂]
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.[4.容许上下文子类的bean工厂调用初始化函数]
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.[5.调用在上下文的注册的工厂处理器]
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.[6.注册在bean建立的过程当中的拦截处理器]
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.[7.初始化消息源]
initMessageSource();
// Initialize event multicaster for this context.[8.初始化事件多播机制]
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.[9.在这个特定的上下文子类中初始化其余特殊的beans]
onRefresh();
// Check for listener beans and register them.[10.检查监听器的beans而且注册他们]
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.[11.初始化存在的单例,不包括懒加载的对象]
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.[12.最后一步:发布相关的事件]
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
beanFactory.destroySingletons();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
复制代码
看个人中文注释
,总共有12步核心步骤来初始化ClassPathXmlApplicationContext
。下面咱们在一步步来分析。
首先看prepareRefresh()
函数。
/** * Prepare this context for refreshing, setting its startup date and * active flag. */
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
synchronized (this.activeMonitor) {
this.active = true;
}
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
}
复制代码
能够看到就只有两步核心操做。首先记录了当前的时间,而后尝试获取activeMonitor
的锁。能够activeMonitor
的做用后面联系起来再分析。
下一篇分析obtainFreshBeanFactory()
函数,一步步来,毕竟是探索系列
嘛,不知道的内容,不断地探索
,咱们才能将其转换为咱们知道的东西,这就是学习。
固然这是Spring
部分的核心的源代码,不过由于SpringBoot
实际上是构建在Spring
基础之上的,因此Spring
的部分源代码也会有讲解。
之后这里天天都会写一篇文章,题材不限,内容不限,字数不限。尽可能把本身天天的思考都放入其中。
若是这篇文章给你带来了帮助,能请你写下是哪一个部分吗?有效的反馈是对我最大的帮助。
我是shane。今天是2019年8月11日。百天写做计划的第十八天,18/100。