前面咱们讲了关于嵌入式servlet容器的配置及其工做原理,其优势毫无疑问:java
缺点:web
但不少时候,仍是须要支持JSP,或者须要将应用部署到固定的web容器中,即咱们以war对应用进行打包(springboot默认是jar)。spring
和以前建立项目的方式同样,只不过在选择发布方式的时候从jar
变为war
便可,项目名为jspweb。docker
因为这是一个以war发布的项目,咱们应该建立webapp文件夹以及web.xml描述文件,可是如今没有,所以须要咱们去建立。tomcat
在编辑器的右上角有一个名为Project Structure的按钮,打开项目结构配置对话框(ctrl+alt+shift+s).springboot
+
按钮,添加一个web.xml文件,注意,路径那里写在咱们下面建立的那个web路径下。即xxx\jspweb\src\main\webapp\WEB-INF\web.xml
,其中XXXX是项目所在的本地路径。很显然,此时要项目运行起来,咱们得添加外部的servlet容器。在进行以下步骤前,请记得先去tomcat官网下载一个tomcat,安装在本地(解压到本地一个目录便可)。服务器
edit configuration
;tomcat server
的项,点击,选择local
即本地的tomcat直接运行项目,就能够直接访问咱们的首页了(固然,若是是新项目,固然会跳到找不到页面的错误页面)。app
咱们能够直接在webapp下面新增一个hello.jsp,而后访问localhost:8080/hello.jsp便可。less
总结一下,咱们若是想要用外部容器的话,大概须要以下步骤:webapp
SpringBootServletInitializer
的子类,目的是为了调用configure方法public class ServletInitializer extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { // 传入springboot应用的主程序 return application.sources(JspwebApplication.class); } }
回想一下咱们以前。
服务器如何启动springboot的?看上一节的代码就能够知道
public class ServletInitializer extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { // 传入springboot应用的主程序 return application.sources(JspwebApplication.class); } }
参考文档servlet3.0(Spring注解版)中的8.2.4节: Shared libraries / runtimes pluggability
,里面定义了这样的规则:
接下来分析一下咱们这个项目的运行过程
其中,Spring的web模块里面有这个文件org.springframework.web.SpringServletContainerInitializer
;
SpringServletContainerInitializer将@HandlesTypes(WebApplicationInitializer.class)标注的全部这个类型的类都传入到onStartup方法的Set<Class<?>>,接下来为这些WebApplicationInitializer类型的类建立实例;
每个WebApplicationInitializer都调用本身的onStartup;
至关于咱们的SpringBootServletInitializer的类会被建立对象,并执行onStartup方法
SpringBootServletInitializer实例执行onStartup的时候会createRootApplicationContext;建立容器
protected WebApplicationContext createRootApplicationContext( ServletContext servletContext) { //一、建立SpringApplicationBuilder SpringApplicationBuilder builder = createSpringApplicationBuilder(); StandardServletEnvironment environment = new StandardServletEnvironment(); environment.initPropertySources(servletContext, null); builder.environment(environment); 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)); builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class); //调用configure方法,子类重写了这个方法,将SpringBoot的主程序类传入了进来 builder = configure(builder); //使用builder建立一个Spring应用 SpringApplication application = builder.build(); if (application.getSources().isEmpty() && AnnotationUtils .findAnnotation(getClass(), Configuration.class) != null) { application.getSources().add(getClass()); } Assert.state(!application.getSources().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.getSources().add(ErrorPageFilterConfiguration.class); } //启动Spring应用 return run(application); }
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); Banner printedBanner = printBanner(environment); context = createApplicationContext(); analyzers = new FailureAnalyzers(context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); //刷新IOC容器 refreshContext(context); afterRefresh(context, applicationArguments); listeners.finished(context, null); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } return context; } catch (Throwable ex) { handleRunFailure(context, listeners, analyzers, ex); throw new IllegalStateException(ex); } }
总结一下启动原理:
先是启动servlet容器,再启动springboot应用,恰好和咱们的内嵌方式相反。
至此章节开始以后有一节是讲关于docker相关的知识,这点推荐你们本身去学习相关的书籍和视频就好,不在插入此系列文档之中了。
docker是一个很棒的理念,相关的衍生技术已经获得了普遍的运用,做为一名it相关的人员,必须得学,由于不是三言两语说得完的,所以,就不在springboot这里说明了。