源代码版本 Spring 1.5.8.RELEASE
1.获取 SpringApplicationRunListener
实例
比如 EventPublishingRunListener
// 内部使用SpringFactoriesLoader 加载所有定义的 SpringApplicationRunListener并构造实例
// 可以将 SpringApplicationRunListeners 理解为一组这样的实例的集合
SpringApplicationRunListeners listeners = getRunListeners(args);
2.向所有 SpringApplicationRunListener
实例通知事件 ApplicationStartedEvent
listeners.starting();
3. 准备环境 Environment
// 准备 Environment : 创建并配置 Enviroment
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 向所有 SpringApplicationRunListener 实例通知事件 ApplicationEnvironmentPreparedEvent
listeners.environmentPrepared(environment);
if (!this.webEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
return environment;
}
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
if (this.webEnvironment) {
// 如果是 Web 环境,创建 StandardServletEnvironment 对象
return new StandardServletEnvironment();
}
// 如果是非 Web 环境,创建 StandardEnvironment 对象
return new StandardEnvironment();
}
protected void configureEnvironment(ConfigurableEnvironment environment,
String[] args) {
configurePropertySources(environment, args);
configureProfiles(environment, args);
}
4. 向所有 SpringApplicationRunListener
实例通知事件 ApplicationEnvironmentPreparedEvent
5. 创建 ApplicationContext
/**
* 非web环境应用上下文的实现类
* The class name of application context that will be used by default for non-web
* environments.
*/
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext";
/**
* web环境应用上下文的实现类
* The class name of application context that will be used by default for web
* environments.
*/
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";
// 初始化过程中已经推断过当前应用是否Web应用环境,
//下面根据当前应用是否Web应用环境找到相应的ApplicationContext实现类,
//AnnotationConfigEmbeddedWebApplicationContext对应非Web环境
//或者 ConfigurableWebApplicationContext对应Web环境
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
contextClass = Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
// 创建 ApplicationContext 实例
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}
ApplicationContext
对象实例化的过程只是做了一个Java
对象创建的动作吗 ? 并不是那么简单,以缺省Web
应用的情况来看 :
public AnnotationConfigEmbeddedWebApplicationContext() {
//创建一个AnnotatedBeanDefinitionReader,注解Bean类程序方式注册的便捷工具,和
//classpath Bean定义扫描器ClassPathBeanDefinitionScanner互为补充,采用同样的
//注解解决机制,但是只针对显式注册的类
//AnnotatedBeanDefinitionReader()构造方法内部会进一步调用工具类
//AnnotationConfigUtils. registerAnnotationConfigProcessors(registry)
//注册 6个BeanPostProcessor Bean定义,这也是容器中最早出现的一组Bean定义:
//1. annotation.internalConfigurationAnnotationProcessor
//2. annotation.internalAutowiredAnnotationProcessor
//3. annotation.internalRequiredAnnotationProcessor
//4. annotation.internalCommonAnnotationProcessor
//5. event.internalEventListenerProcessor
//6. event.internalEventListenerFactory
this.reader = new AnnotatedBeanDefinitionReader(this);
// Bean definition 扫描器 :
// 扫描classpath上的Bean定义并注册到 ApplicationContext 或者 BeanFactory
// Q : 什么样的会被认为是候选Bean定义 ?
// A : @Component, @Repository,@Service,@Controller等Spring注解定义的类,或者
// Java EE 6's javax.annotation.ManagedBean,JSR-330 javax.inject.Named
// 注解定义的类
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
6. 准备 ApplicationContext
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 关联 ApplicationContext 和 Environment
context.setEnvironment(environment);
// 1.如果外部指定了 Bean 名称生成器,将其作为单例Bean注册到容器,
// 2.如果外部指定了资源加载器,设置 ApplicationContext 的资源加载器和相应的类加载器
postProcessApplicationContext(context);
// 执行每个 ApplicationContextInitializer 实例的初始化 initialize(context)
applyInitializers(context);
// 向所有 SpringApplicationRunListener 实例通知事件 ApplicationEnvironmentPreparedEvent
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 加载 Bean 定义, 只根据源类型将源设置到具体的 Bean定义加载器,并没有全面执行Bean定义加载.
// 这里 sources 指定的类,如果有注解@Component,则会被作为Bean定义添加到容器中,比如当前
// SpringApplication的入口类,因为有注解@SpringBootConfiguration,内含了注解@Component,
// 所以它会作为作为一个Bean被注册进容器;
load(context, sources.toArray(new Object[sources.size()]));
// 1.向所有 SpringApplicationRunListener 实例通知事件 ApplicationPreparedEvent
// 2.关联 ApplicationContext 和所有 ApplicationContextAware 的 ApplicationListener
listeners.contextLoaded(context);
}
7.刷新 ApplicationContext
((AbstractApplicationContext) applicationContext).refresh();
8.执行 ApplicationContext
刷新后任务 : 执行 Runners
SpringApplication.run()
中的代码片段。
afterRefresh(context, applicationArguments);
/**
* Called after the context has been refreshed.
* @param context the application context
* @param args the application arguments
*/
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
callRunners(context, args);
}
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
// 找出所有的 ApplicationRunner Bean
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
// 找出所有的 CommandLineRunner Bean
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// 排序
AnnotationAwareOrderComparator.sort(runners);
// 调用所有的 Runner
for (Object runner : new LinkedHashSet<Object>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
9.向所有 SpringApplicationRunListener
实例通知事件 ApplicationReadyEvent
// SpringApplicationRunListener 会进一步将此事件通知到 ApplicationContext 中去
// Listeners have been registered to the application context so we should
// use it at this point if we can
context.publishEvent(event);