SpringBoot注册Servlet的3种方法
- 注解@WebServlet(“/hello”)
- ServletRegistrationBean
- 动态注册:通过实现ServletContextInitializer接口
ServletContextInitializer原理【Spring中注册Servlet】
其实ServletRegistrationBean 也是ServletContextInitializer
@WebServlet原理
ServletComponentRegisteringPostProcessor中通过WebServletHandler来处理带@WebServlet的类
其本质也是,构造一个ServletRegistrationBean(ServletContextInitializer)
三种方式最终都是ServletContextInitializer。
【servlet3.0】ServletContainerInitializer帮我们摆脱web.xml
项目中没有web.xml,取而代之是ServletContainerInitializer。
容器会通过SPI调用ServletContainerInitializer#onStartup,并且将@HandlesTypes中的类型作为参数传递到c中。
SpringMVC中如何注册DispatcherServlet的?【WebApplicationInitializer(SpringServletContainerInitializer)】
上面我们知道ServletContainerInitializer#onStartup会在启动时运行。
SpringMVC实现的ServletContainerInitializer——SpringServletContainerInitializer
- 在spring-web包中,通过spi被加载
- 虽然被spi自动加载,但是WebApplicationInitializer需要我们自己定义。
SpringServletContainerInitializer中调用WebApplicationInitializer.onStartup()
-> 其中就有注册DispatcherServlet的WebApplicationInitializer【AbstractAnnotationConfigDispatcherServletInitializer】
AbstractAnnotationConfigDispatcherServletInitializer【WebApplicationInitializer】
【总结】servlet3.0注册DispatcherServlet总结
- SPI调用ServletContainerInitializer#onStartup,根据@HandlesTypes(WebApplicationInitializer.class),将WebApplicationInitializer.class()传入onStartup()方法。
AbstractDispatcherServletInitializer【WebApplicationInitializer】.onStartup() 中 registerDispatcherServlet(servletContext);注册DispatcherServlet。
【war包运行】SpringBoot打war包部署方法
步骤:
修改pom.xml文件将默认的jar方式改为war
- 继承org.springframework.boot.web.servlet.support.SpringBootServletInitializer(WebApplicationInitializer)
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
// @Override
// protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
// return application.sources(TestwarApplication.class);
// }
}
通常需要重写configure方法
当使用Application类继承的时候就不用,因为当判断source为空,会添加自身。
application.addPrimarySources(Collections.singleton(getClass()));
- Deploy a Spring Boot WAR into a Tomcat Server
为什么要继承SpringBootServletInitializer
SpringBootServletInitializer 是一个抽象类(没有实现类),不能实例化。
我们需要使用[servlet3.0标准的]SpringServletContainerInitializer(ServletContainerInitializer)来调用SpringBootServletInitializer(WebApplicationInitializer)中的onStartup() 方法。
在SpringBootServletInitializer.onStartup() 方法中会创建ApplicationContext等操作。
不用Application继承也行,可以另外写一个bean来继承,并注入到容器中
内嵌容器不支持ServletContainerInitializer,因此不能通过spi方式加载ServletContainerInitializer, 而是用TomcatStarter的onStartup,间接启动ServletContextInitializers,来达到ServletContainerInitializer的效果。
【好文】【好文】【好文】SpringBoot为什么没有web.xml了(转)- 深度好文 - EasyProgramming的个人空间 - OSCHINA
war启动简单总结
- SpringBootServletInitializer【抽象类,需要Application继承】 implement WebApplicationInitializer 作为参数传入到了SpringServletContainerInitializer implements ServletContainerInitializer
- SpringBootServletInitializer 启动了ServletWebServerApplicationContext
- ServletWebServerApplicationContext.onRefresh() 执行了ServletWebServerApplicationContext#ServletContextInitializer
- ServletWebServerApplicationContext#ServletContextInitializer 执行了一系列ServletContextInitializer(从BeanFactory中获得)
- DispatcherServletRegistrationBean(ServletContextInitializer)被执行注册Servlet
【jar运行】SpringBoot如何注册DispatcherServlet的?
- 内嵌容器,所有的BeanDefinition都在applicationContext中了,用的话直接getBean即可(从applicationContext中获取servlet、ServletContextInitializer))。
ServletWebServerApplicationContext重写onRefresh()方法。
最终调用ServletContextInitializer.onStartup()方法
其中有注册DispatcherServlet的ServletContextInitializer就是DispatcherServletRegistrationBean。
RegistrationBean#onStartup(ServletContext servletContext)注册Servlet到ServletContext
有了servlet,applicationContext何时注入到servlet中呢?
是实例化FrameworkServlet时注入。
DispatcherServlet如何初始化SpringMVC组件的?
- FrameworkServlet初始化期间构造ApplicationContext,并向其中添加ContextRefreshListener。
容器refresh完成会触发事件调用ContextRefreshListener。
FrameworkServlet#configureAndRefreshWebApplicationContext
- springboot是将applicationContext传入FrameworkServlet中(通过aware在构造FrameworkServlet时传入)。
springboot不会进入createWebApplicationContext()方法。所以不会添加listener。所以,下面的onRefresh()被调用,初始化springmvc组件。
SpringMVC调用createWebApplicationContext()。通过Listener来调用onRefresh()。
- 在DispatcherServlet#onRefresh中初始化SpringMVC组件
默认组件都定义在DispatcherServlet.properties
内嵌tomcat的运行
在finishRefresh()中执行了tomcat.start()