一、功能要求
自定义简易版SpringBoot,实现SpringBoot MVC及内嵌Tomcat启动、DispatcherServlet注册和组件扫描功能
程序通过main方法启动,可以自动启动tomcat服务器 可以自动创建和加载DispatcherServlet组件到ServletContext中 可以自动通过@ComponentScan扫描Controller等组件 Controller组件可以处理浏览器请求,返回响应结果二、实现思路分析
传统SpringMVC框架web.xml的配置内容:
org.springframework.web.context.ContextLoaderListener contextConfigLocation /WEB-INF/app-context.xml app org.springframework.web.servlet.DispatcherServlet contextConfigLocation 1 app /app/*
Spring官方文档中给出了基于Servlet3.0规范如何使用Java代码实现web.xml配置的example
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletCxt) {
// Load Spring web application configuration
//通过注解的方式初始化Spring的上下文
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
//注册spring的配置类(替代传统项目中xml的configuration)
ac.register(AppConfig.class);
ac.refresh();
// Create and register the DispatcherServlet
//基于java代码的方式初始化DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
当实现了Servlet3.0规范的容器(比如Tomcat7及以上版本)启动时
- 会通过SPI扩展机制自动扫描所有jar包里meta-INF/services/javax.servlet.ServletContainerInitializer文件中指定的全路径类(该类需实现ServletContainerInitializer接口)
- 实例化该类
- 回调类中的onStartup方法
- 在onStartup方法中,可以回调WebApplicaitonInitializer的onStartup方法
- 在WebApplicaitonInitializer的onStartup方法中 进行传统SpringMVC框架web.xml的 内容配置
(1)创建maven工程,导入以下依赖:
org.springframework spring-web 5.0.8.RELEASE org.apache.tomcat.embed tomcat-embed-core 8.5.32 org.apache.tomcat.embed tomcat-embed-jasper 8.5.32 org.springframework spring-context 5.0.8.RELEASE org.springframework spring-webmvc 5.0.8.RELEASE
(2)创建SpringApplication类,编写run方法(方法中要求完成tomcat的创建及启动)
public class SpringApplication {
public static void run(){
//创建tomcat实例
Tomcat tomcat = new Tomcat();
//设置tomcat端口
tomcat.setPort(8888);
try {
//设置项目文件路径
tomcat.addWebapp("/", "G:\");
//启动tomcat
tomcat.start();
// 监听关闭端口,阻塞式。没有这一句,方法执行完会直接结束
tomcat.getServer().await();
} catch (LifecycleException e) {
e.printStackTrace();
} catch (ServletException e) {
e.printStackTrace();
}
}
}
(3)创建spring的配置类 AppConfig该类上要通过@ComponentScan来进行包扫描
@Configuration
@ComponentScan("com.dabing")
public class AppConfig {
{
System.out.println("ComponentScan...........");
}
}
(4)创建MyWebApplicationInitializer实现WebApplicationInitializer接口,重写onstartup方法(WebApplicationInitializer实现web.xml的配置)
public class MyWebApplicationInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
System.out.println("初始化 MyWebApplicationInitializer");
//通过注解的方式初始化Spring的上下文
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
//注册spring的配置类(替代传统项目中xml的configuration)
ac.register(AppConfig.class);
// Create and register the DispatcherServlet
//基于java代码的方式初始化DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletContext.addServlet("/", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/*");
}
}
(5)编写一个Controller测试类及目标方法,响应输出“hello”即可
@RestController
public class TestController {
@RequestMapping("/test/hello")
public String test(){
System.out.println("--- hello ---");
return "hello";
}
}
(6)编写一个启动类Main,通过执行main方法启动服务
public class Main {
public static void main(String[] args) {
SpringApplication.run();
}
}
(7)通过浏览器对目标方法进行方法
(1)创建maven工程,导入以下依赖:
org.springframework spring-web 5.0.8.RELEASE org.apache.tomcat.embed tomcat-embed-core 8.5.32 org.apache.tomcat.embed tomcat-embed-jasper 8.5.32 org.springframework spring-context 5.0.8.RELEASE org.springframework spring-webmvc 5.0.8.RELEASE
(2)创建SpringApplication 类,编写run方法(方法中要求完成tomcat的创建及启动)
public class SpringApplication {
public static void run(){
//创建tomcat实例
Tomcat tomcat = new Tomcat();
//设置tomcat端口
tomcat.setPort(8888);
try {
//设置项目文件路径
tomcat.addWebapp("/", "G:\");
//启动tomcat
tomcat.start();
// 监听关闭端口,阻塞式。没有这一句,方法执行完会直接结束
tomcat.getServer().await();
} catch (LifecycleException e) {
e.printStackTrace();
} catch (ServletException e) {
e.printStackTrace();
}
}
}
(3)创建spring的配置类 AppConfig该类上要通过@ComponentScan来进行包扫描
@Configuration
@ComponentScan("com.dabing")
public class AppConfig {
{
System.out.println("ComponentScan...........");
}
}
(4)创建MySpringServletContainerInitializer,实现ServletContainerInitializer接口,重写onstartup方法,方法中调用第4步中MyWebApplicationInitializer的onstartup方法
@HandlesTypes(MyWebApplicationInitializer.class)
public class MySpringServletContainerInitializer implements ServletContainerInitializer {
public void onStartup(Set> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
System.out.println("初始化 MySpringServletContainerInitializer");
List initializers = new linkedList();
if (webAppInitializerClasses != null) {
for (Class> waiClass : webAppInitializerClasses) {
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer)
ReflectionUtils.accessibleConstructor(waiClass).newInstance());
} catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
System.out.println("for--------------");
initializer.onStartup(servletContext);
}
}
}
(5)创建文件:meta-INF/services/javax.servlet.ServletContainerInitializer,在该文件中配置ServletContainerInitializer的实现类MySpringServletContainerInitializer
com.dabing.web.MySpringServletContainerInitializer
(6)创建MyWebApplicationInitializer实现WebApplicationInitializer接口,重写onstartup方法(WebApplicationInitializer实现web.xml的配置)
public class MyWebApplicationInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
System.out.println("初始化 MyWebApplicationInitializer");
//通过注解的方式初始化Spring的上下文
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
//注册spring的配置类(替代传统项目中xml的configuration)
ac.register(AppConfig.class);
// Create and register the DispatcherServlet
//基于java代码的方式初始化DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletContext.addServlet("/", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/*");
}
}
(7)编写一个Controller测试类及目标方法,响应输出“hello”即可
@RestController
public class TestController {
@RequestMapping("/test/hello")
public String test(){
System.out.println("--- hello ---");
return "hello";
}
}
(8)编写一个启动类Main,通过执行main方法启动服务
public class Main {
public static void main(String[] args) {
SpringApplication.run();
}
}
(9)通过浏览器对目标方法进行方法



