- 前言
- 第一部分 基础应用开发
- 第 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 框架最引人注目的地方。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论