spring boot学习之tomcat与spring boot

it2024-11-24  27

tomcat是Servlet容器,spring boot是开发框架,可开发基于Servlet规范的应用 即spring boot应用需要放在Servlet容器上运行 而spring boot可以使用内置Servlet容器启动,也可以发布在外置Servlet容器容器上

内置tomcat之tomcat启动 1.容器构建时期ServletWebServerApplicationContext的onRefresh()

//在父类AbstractApplicationContext的refresh()中调用 protected void onRefresh() { super.onRefresh(); try { //创建web容器 createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server", ex); } } private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = getServletContext(); if (webServer == null && servletContext == null) { //main方法启动时会找对应的jar包,没有则报错 ServletWebServerFactory factory = getWebServerFactory(); this.webServer = factory.getWebServer(getSelfInitializer()); } else if (servletContext != null) { //外置tomcat启动,初始化selvlet context try { getSelfInitializer().onStartup(servletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } } initPropertySources(); }

2.容器启动时期ServletWebServerApplicationContext的finishRefresh()

protected void finishRefresh() { super.finishRefresh(); WebServer webServer = startWebServer(); if (webServer != null) { publishEvent(new ServletWebServerInitializedEvent(webServer, this)); } }

外置tomcat之不采用web.xml配置 大部分传统的JavaWeb应用启动入口一般在web.xml文件中,而在新的servlet规范中可支持不使用web.xml文件,提供了基于注解的启动模式,因此提供了ServletContainerInitializer接口和HandlesTypes注解等。而spring boot也对此规范进行了实现,从而可以发布应用时无需构建web.xml文件

package javax.servlet; import java.util.Set; public interface ServletContainerInitializer { void onStartup(Set<Class<?>> var1, ServletContext var2) throws ServletException; }

ServletContainerInitializer的实现SpringServletContainerInitializer

public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException { //实现WebApplicationInitializer该接口进行扩展 List<WebApplicationInitializer> initializers = new LinkedList<>(); if (webAppInitializerClasses != null) { for (Class<?> waiClass : webAppInitializerClasses) { // Be defensive: Some servlet containers provide us with invalid classes, // no matter what @HandlesTypes says... 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) { initializer.onStartup(servletContext); } }

WebApplicationInitializer的实现SpringBootServletInitializer

public void onStartup(ServletContext servletContext) throws ServletException { // Logger initialization is deferred in case an ordered // LogServletContextInitializer is being used this.logger = LogFactory.getLog(getClass()); WebApplicationContext rootAppContext = createRootApplicationContext(servletContext); if (rootAppContext != null) { servletContext.addListener(new ContextLoaderListener(rootAppContext) { @Override public void contextInitialized(ServletContextEvent event) { // no-op because the application context is already initialized } }); } else { this.logger.debug("No ContextLoaderListener registered, as " + "createRootApplicationContext() did not " + "return an application context"); } } protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) { //构建SpringApplication SpringApplicationBuilder builder = createSpringApplicationBuilder(); builder.main(getClass()); ApplicationContext parent = getExistingRootWebApplicationContext(servletContext); if (parent != null) { this.logger.info("Root context already created (using as parent)."); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null); builder.initializers(new ParentContextApplicationContextInitializer(parent)); } builder.initializers(new ServletContextApplicationContextInitializer(servletContext)); //指定加载applicationContext的类为ServletWebServerApplicationContext的子类AnnotationConfigServletWebServerApplicationContext builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class); //需要继承此类并实现该方法,定义spring boot的配置如扫描包目录等 builder = configure(builder); builder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext)); SpringApplication application = builder.build(); if (application.getAllSources().isEmpty() && AnnotationUtils.findAnnotation(getClass(), Configuration.class) != null) { application.addPrimarySources(Collections.singleton(getClass())); } Assert.state(!application.getAllSources().isEmpty(), "No SpringApplication sources have been defined. Either override the " + "configure method or add an @Configuration annotation"); // Ensure error pages are registered if (this.registerErrorPageFilter) { application.addPrimarySources(Collections.singleton(ErrorPageFilterConfiguration.class)); } //main方法启动的形式也调用过该方法 return run(application); }

参考博文: SpringBoot 中的 ServletInitializer spring boot 内置tomcat和外置tomcat部署总结 在Spring boot中加入web.xml

最新回复(0)