Spring Boot零配置实现原理及模拟实现
利用Spring Boot可以快速的构建一个Spring应用,尤其是Web应用,Spring Boot内嵌了Tomcat容器,项目开发完成后打包成一个可执行的Jar包直接就能运行,大大减少了项目构建和部署的成本。Spring Boot非常强大,它是如何实现的?过去的步骤在没有用Spring Boot之前,是这么做的:1、在web.xml手动配置Spring配置文件和DispatcherSe...
利用Spring Boot可以快速的构建一个Spring应用,尤其是Web应用,Spring Boot内嵌了Tomcat容器,项目开发完成后打包成一个可执行的Jar包直接就能运行,大大减少了项目构建和部署的成本。
Spring Boot非常强大,它是如何实现的?
过去的步骤
在没有用Spring Boot之前,是这么做的:
1、在web.xml手动配置Spring配置文件和DispatcherServlet。
<!-- Spring MVC配置 -->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Spring配置 -->
<listener>
<listenerclass>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- 指定Spring Bean的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/applicationContext.xml</param-value>
</context-param>
2、将项目打包放到Tomcat容器中运行。
3、Tomcat启动时,解析web.xml,Spring通过ContextLoaderListener来完成上下文环境的初始化。
4、Tomcat将web.xml中配置的前端控制器DispatcherServlet注册到Servlet中。
总结一下启动服务做了哪些事情:
- 启动了一个Tomcat服务
- 初始化Spring上下文环境
- 注册DispatcherServlet
Spring Boot要想达到零配置,这些问题必须要解决。
解决方案
- 启动Tomcat -> 内嵌解决
- 初始化Spring上下文环境 -> 利用SPI机制
- 动态注册DispatcherServlet -> 初始化时一并做掉
模拟实现
1、新建一个maven项目,添加如下依赖:
只是依赖了Spring、MVC和Tomcat,并没有依赖SpringBoot。
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--tomcat-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>8.5.45</version>
</dependency>
</dependencies>
2、创建Spring初始化上下文环境的配置类。
@Configuration
@ComponentScan("com.ch")
public class AppConfig {
}
3、编写一个测试的Controller,后面测试用。
@RestController
public class MyController {
@RequestMapping("/test")
public String test(){
return "Hello world!";
}
}
4、创建一个内嵌Tomcat的启动类。
public class TomcatStart {
public static int TOMCAT_PORT = 8080;
public static String WEBAPP_PATH = "moni-spring-boot/src/main";
public static String CONTEXT_PATH = "/";
public static void run(){
String s = System.getProperty("user.dir") + File.separator + WEBAPP_PATH;
System.out.println(s);
Tomcat tomcat = new Tomcat();
tomcat.setPort(TOMCAT_PORT);
//创建上下文
StandardContext myCtx = (StandardContext) tomcat
.addWebapp(CONTEXT_PATH, System.getProperty("user.dir") + File.separator + WEBAPP_PATH);
try {
tomcat.start();
} catch (LifecycleException e) {
e.printStackTrace();
}
tomcat.getServer().await();
}
}
5、创建应用程序的启动类。
实际上就是启动一个Tomcat。
public class App {
public static void main(String[] args) throws LifecycleException {
TomcatStart.run();
}
}
到这里并没有结束,目前只是能启动一个Tomcat,但是Spring上下文环境并没有初始化,DispatcherServlet也还没有注册。
如何让Tomcat启动时完成Spring上下文的初始化和注册filter???
6、编写应用系统初始化类。
/**
* @Author: pch
* @Date: 2019/12/14 19:37
* @Description: App上下文环境初始化
*/
public class MyAppContextInit implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
//初始化Spring上下文环境
System.out.println("*****SpringContext初始化...*****");
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
context.refresh();
System.out.println("*****SpringContext初始化完成.*****");
//注册DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration = servletContext.addServlet("myApp", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/");
}
}
这样还不够,只是编写了这个类,Tomcat凭什么启动时去执行它???
这设计到Java的SPI机制,具体可以看笔者以前的博客:Java SPI机制。
7、在resources目录下创建以下文件,文件内容为应用初始化类的全限定名:
META-INF/services/javax.servlet.ServletContainerInitializer
com.ch.support.MyAppContextInit
现在运行main方法,会惊奇的发现,Tomcat启动时会自动执行MyAppContextInit中的onStartup()方法,Spring上下文环境初始完毕,DispatcherServlet也成功注册。
8、测试服务是否正常可用。
访问:http://localhost:8080/test
返回如下:
Hello world!
服务成功可用,基于零配置了实现了类似Spring Boot的基本功能。
更多推荐
所有评论(0)