前面咱們講了關於嵌入式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這裏說明了。