- 前言
- 第一部分 基础应用开发
- 第 1 章 Spring Boot 入门
- 第 2 章 在 Spring Boot 中使用数据库
- 第 3 章 Spring Boot 界面设计
- 第 4 章 提高数据库访问性能
- 第 5 章 Spring Boot 安全设计
- 第二部分 分布式应用开发
- 第 6 章 Spring Boot SSO
- 第 7 章 使用分布式文件系统
- 第 8 章 云应用开发
- 第 9 章 构建高性能的服务平台
- 第三部分 核心技术源代码分析
- 第 10 章 Spring Boot 自动配置实现原理
- 第 11 章 Spring Boot 数据访问实现原理
- 第 12 章 微服务核心技术实现原理
- 附录 A 安装 Neo4j
- 附录 B 安装 MongoDB
- 附录 C 安装 Redis
- 附录 D 安装 RabbitMQ
- 结束语
10.1 Spring Boot 主程序的功能
代码清单 10-1 是 Spring Boot 应用的一个典型主程序,它看起来非常简单,使用了一个同样看起来非常简单的注解 @SpringBootApplication,并用一个非常普通的 main 方法运行 SpringApplication 的 run 方法。这个简单的主程序将会加载一个应用所需的所有资源和配置,最后启动一个应用实例。
代码清单 10-1 Spring Boot 应用主程序
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
10.1.1 SpringApplication 的 run 方法
Spring Boot 的主程序有什么神奇的地方呢?可以从 SpringApplication 的 run 方法说起,这是应用主程序开始运行的方法,它的源代码如代码清单 10-2 所示。这个方法让我们能够看清楚 Spring Boot 的一切秘密所在,它首先开启一个 SpringApplicationRun-Listeners 监听器,然后创建一个应用上下文 ConfigurableApplicationContext,通过这个上下文加载应用所需的类和各种环境配置等,最后启动一个应用实例。
代码清单 10-2 SpringApplication 中 run 的源代码
package org.springframework.boot;
......
public class SpringApplication {
......
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.started();
try {
DefaultApplicationArguments ex = newDefaultApplicationArguments(args);
context = this.createAndRefreshContext(listeners, ex);
this.afterRefresh(context, (ApplicationArguments)ex);
listeners.finished(context, (Throwable)null);
stopWatch.stop();
if(this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted
(this.getApplicationLog(), stopWatch);
}
return context;
} catch (Throwable var6) {
this.handleRunFailure(context, listeners, var6);
throw new IllegalStateException(var6);
}
}
......
}
如果你使用过 Spring 框架,就会更加清楚这种加载应用的实现机制。在 Spring 中,加载一个应用,主要是通过一些复杂的配置来实现的。这样看来,Spring Boot 只不过是把这些本来由程序员做的工作,事先帮我们实现罢了。
10.1.2 创建应用上下文
一个应用能够正常运行起来,需要一些环境变量、各种资源和一些相关配置等,从创建应用上下文 ConfigurableApplicationContext 的源代码中,我们可以看到这种实现机制,如代码清单 10-3 所示。其中,this.load(context,sources.toArray(new Object[sources.size()]))将调用 BeanDefinitionLoader 来加载应用定义的和需要的类及各种资源。
代码清单 10-3 创建应用上下文——createAndRefreshContext 的源代码
package org.springframework.boot;
......
public class SpringApplication {
......
private ConfigurableApplicationContext createAndRefreshContext(SpringApp
licationRunListeners listeners, ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
this.configureEnvironment(environment, applicationArguments.getSource
Args());
listeners.environmentPrepared(environment);
if(this.isWebEnvironment(environment) && !this.webEnvironment) {
environment = this.convertToStandardEnvironment(environment);
}
if(this.bannerMode != Mode.OFF) {
this.printBanner(environment);
}
ConfigurableApplicationContext context = this.createApplicationContext();
context.setEnvironment(environment);
this.postProcessApplicationContext(context);
this.applyInitializers(context);
listeners.contextPrepared(context);
if(this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
Set sources = this.getSources();
Assert.notEmpty(sources, "Sources must not be empty");
this.load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
this.refresh(context);
if(this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException var7) {
;
}
}
return context;
}
......
}
10.1.3 自动加载
在 BeanDefinitionLoader 中,有一个 load(Class<?>source)方法用来加载类定义,如代码清单 10-4 所示。这里的 source 就是代码清单 10-1 中定义的 Application.class。在程序中通过 isComponent 检查是否存在注解,如果有注解,则调用注解相关的类定义。这样注解 @SpringBootApplication 将被调用,它不但会导入一系列自动配置的类,还会加载应用中一些自定义的类。
代码清单 10-4 BeanDefinitionLoader 中 load(Class<?>source)源代码
package org.springframework.boot;
......
class BeanDefinitionLoader {
......
private int load(Class<?> source) {
if(this.isGroovyPresent() && BeanDefinitionLoader.GroovyBeanDefinition
Source.class.isAssignableFrom(source)) {
BeanDefinitionLoader.GroovyBeanDefinitionSource loader = (Bean
DefinitionLoader.GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, BeanDefinitionLoader.GroovyBeanDefinitionSource.class);
this.load(loader);
}
if(this.isComponent(source)) {
this.annotatedReader.register(new Class[]{source});
return 1;
} else {
return 0;
}
}
......
private boolean isComponent(Class<?> type) {
return AnnotationUtils.findAnnotation(type, Component.class) != null?
true:!type.getName().matches(".*\\$_.*closure.*") && !type.isAnonymousClass() && type.getConstructors() != null && type.getConstructors().length != 0;
}
......
}
从以上分析可知,一个简单的 Spring Boot 主程序,通过运行一个 run 方法,就将引发一系列复杂的内部调用和加载过程,从而初始化一个应用所需的配置、环境、资源及各种类定义等。特别是导入了一系列自动配置类,实现了强大的自动配置功能,这是 Spring Boot 框架最引人注目的地方。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论