前言
相信每一个 Java
开发者对于 Spring Boot 都不会陌生, Spring Boot 的出现,极大的简化了我们开发 web 应用的难度。此外,Spring Boot 还具有如下优势:
简化配置:Spring Boot 提供了默认配置,减少了开发人员需要进行手动配置的工作,从而提高了开发效率。
快速开发:Spring Boot 提供了许多开箱即用的功能和模板,使开发人员能够快速构建应用程序,减少了样板代码的编写。
内嵌式服务器:Spring Boot 支持内嵌式服务器(如 Tomcat、Jetty 等),无需额外配置,可以轻松部署应用程序。
自动化配置:Spring Boot 提供了自动配置机制,可以根据项目的依赖自动配置应用程序,减少了手动配置的繁琐工作。
一言以概之,Spring Boot 是基于 Spring 开发的一种轻量级的全新框架,不仅继承了 Spring 框架原有的优秀特性,而且还通过简化配置来进一步简化应用的搭建和开发过程。
run
方法
在 Spring Boot 框架下,通常会按照如下所示的逻辑来编写启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* SpringBoot应用启动类
*/
@SpringBootApplication
public class StartSpringBootApplication {
public static void main(String[] args) {
// 启动SpringBoot
SpringApplication.run(StartSpringBootApplication.class, args);
}
}
提供一个 SpringBoot 的启动类
StartSpringBootApplication
(注:启动类的名称可任意指定)在启动类上标注一个
@SpringBootApplication
注解编写一个
main
方法,调用SpringApplication
中的run
方法
接着,通过运行上述的 main
方法就可完成一个 Spring Boot 应用的启动。不难发现,启动一个 Spring Boot 应用非常简单。
正如之前分析的那样,Spring Boot 应用启动的核心秘密都在于 run
方法。
public ConfigurableApplicationContext run(String... args) {
// .......省略其他无关代码
listeners.starting();
try {
// 构建一个应用参数解析器
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 加载系统的属性配置信息
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 用于控制是否忽略BeanInfo的配置
configureIgnoreBeanInfo(environment);
// 打印banner信息
Banner printedBanner = printBanner(environment);
// 创建一个容器,类型为ConfigurableApplicationContext
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 容器准备工作 (可暂时忽略)
prepareContext(context, environment, listeners,
// 解析传入参数信息
applicationArguments, printedBanner);
// 容器刷新 (重点关注)
refreshContext(context);
afterRefresh(context, applicationArguments);
}
// .......省略其他无关代码
return context;
}
进一步,上述方法可总结为下图所示内容:
手写 Spring Boot 启动逻辑
引入依赖
Spring Boot 基于 Spring 架构,需要在 Spring Boot 模块中依赖 Spring
Spring Boot 也支持 Spring MVC 功能,依赖 Spring MVC 和 Tomcat 等
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.60</version>
</dependency>
实现 Spring Boot 简单功能
@SpringBootApplication
注解@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Configuration @ComponentScan public @interface BerSpringBootApplication { }
SpringApplication
启动类public class SpringApplication { public static void run(Class clazz) { // 1. 创建Spring 容器 AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext(); applicationContext.register(clazz); applicationContext.refresh(); // 2. 创建并启动Tomcat startTomcat(applicationContext); } private static void startTomcat(WebApplicationContext applicationContext) { // 2.1 创建tomcat对象 Tomcat tomcat = new Tomcat(); Server server = tomcat.getServer(); Service service = server.findService("Tomcat"); Connector connector = new Connector(); // 设置默认tomcat启动端口 connector.setPort(8023); Engine engine = new StandardEngine(); engine.setDefaultHost("localhost"); Host host = new StandardHost(); host.setName("localhost"); String contextPath = ""; Context context = new StandardContext(); context.setPath(contextPath); context.addLifecycleListener(new Tomcat.FixContextListener()); host.addChild(context); engine.addChild(host); service.setContainer(engine); service.addConnector(connector); // 2.2 创建DispatcherServlet对象,并与Spring容器绑定,并将DispatcherServlet对象添加至Tomcat中 tomcat.addServlet(contextPath, "dispatcher", new DispatcherServlet(applicationContext)); context.addServletMappingDecoded("/*", "dispatcher"); // 2.3 启动tomcat try { tomcat.start(); } catch (LifecycleException e) { e.printStackTrace(); } } }
在 Spring MVC 中,DispatcherServlet
就起到这个前端控制器的作用。DispatcherServlet
需要绑定一个 Spring 容器,当 DispatcherServlet
接收到请求后,就可以从绑定的 Spring 容器中找到所匹配的 Controller,并执行对应的方法。
因此,在 run
方法中实现了:
创建一个 Spring 容器
创建了一个
AnnotationConfigApplicationContext
容器,并通过传入的 clazz 作为容器的配置类。
创建并启动 Tomcat
创建 tomcat 对象
创建 DispatcherServlet 对象,并与 Spring 容器绑定,并将 DispatcherServlet 对象添加至 Tomcat 中
启动 Tomcat
那么,是如何将 clazz 作为配置类的呢?如下:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class);
}
}
将 DemoApplication.class
传入 run
方法,DemoApplication
类就是 AnnotationConfigWebApplicationContext
容器的配置类。
配置过程:
创建并启动 Tomcat
在 startTomcat()
方法中,创建了 tomcat 对象,并对 tomcat 进行配置,如默认端口 8023,创建和配置 Tomcat 引擎和主机等。然后再创建 DispatcherServlet
对象,并与 Spring 容器绑定,并将 DispatcherServlet
对象添加至 Tomcat 中。
当运行 DemoApplication
启动类时,调用 SpringApplication
类中的 run
方法,所以在 run
方法中调用 startTomcat()
方法。