摘要:為什么整合后必須通過方式啟動背景在整合這篇文章中,我們用了兩種啟動方式方法啟動測試發現,通過啟動能夠正常渲染頁面,而通過方法啟動無法渲染,本文分析下原因。通過來啟動對應的服務器。
為什么整合jsp后必須通過spring-boot:run方式啟動? 背景
在Spring Boot - 整合Jsp/FreeMarker這篇文章中,我們用了兩種啟動方式
mvn clean spring-boot:run
main方法啟動
測試發現,通過maven啟動能夠正常渲染jsp頁面,而通過main方法啟動無法渲染,本文分析下原因。
我們代碼沒有調整,只是啟動方式不同,那么懷疑是classpath不一致!
mvn啟動classpath
/Users/wanye/Code/springboot/target/classes/ /Users/wanye/.m2/repository/ch/qos/logback/logback-classic/1.1.9/logback-classic-1.1.9.jar /Users/wanye/.m2/repository/ch/qos/logback/logback-core/1.1.9/logback-core-1.1.9.jar /Users/wanye/.m2/repository/com/fasterxml/classmate/1.3.3/classmate-1.3.3.jar /Users/wanye/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.8.0/jackson-annotations-2.8.0.jar /Users/wanye/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.8.6/jackson-core-2.8.6.jar /Users/wanye/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.8.6/jackson-databind-2.8.6.jar /Users/wanye/.m2/repository/javax/servlet/jstl/1.2/jstl-1.2.jar /Users/wanye/.m2/repository/javax/validation/validation-api/1.1.0.Final/validation-api-1.1.0.Final.jar /Users/wanye/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/8.5.11/tomcat-embed-core-8.5.11.jar /Users/wanye/.m2/repository/org/apache/tomcat/embed/tomcat-embed-el/8.5.11/tomcat-embed-el-8.5.11.jar /Users/wanye/.m2/repository/org/apache/tomcat/embed/tomcat-embed-jasper/8.5.11/tomcat-embed-jasper-8.5.11.jar /Users/wanye/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/8.5.11/tomcat-embed-websocket-8.5.11.jar /Users/wanye/.m2/repository/org/hibernate/hibernate-validator/5.3.4.Final/hibernate-validator-5.3.4.Final.jar /Users/wanye/.m2/repository/org/jboss/logging/jboss-logging/3.3.0.Final/jboss-logging-3.3.0.Final.jar /Users/wanye/.m2/repository/org/slf4j/jcl-over-slf4j/1.7.22/jcl-over-slf4j-1.7.22.jar /Users/wanye/.m2/repository/org/slf4j/jul-to-slf4j/1.7.22/jul-to-slf4j-1.7.22.jar /Users/wanye/.m2/repository/org/slf4j/log4j-over-slf4j/1.7.22/log4j-over-slf4j-1.7.22.jar /Users/wanye/.m2/repository/org/slf4j/slf4j-api/1.7.22/slf4j-api-1.7.22.jar /Users/wanye/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/1.5.1.RELEASE/spring-boot-autoconfigure-1.5.1.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/boot/spring-boot-starter-logging/1.5.1.RELEASE/spring-boot-starter-logging-1.5.1.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/1.5.1.RELEASE/spring-boot-starter-tomcat-1.5.1.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/boot/spring-boot-starter-web/1.5.1.RELEASE/spring-boot-starter-web-1.5.1.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/boot/spring-boot-starter/1.5.1.RELEASE/spring-boot-starter-1.5.1.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/boot/spring-boot/1.5.1.RELEASE/spring-boot-1.5.1.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/spring-aop/4.3.6.RELEASE/spring-aop-4.3.6.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/spring-beans/4.3.6.RELEASE/spring-beans-4.3.6.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/spring-context/4.3.6.RELEASE/spring-context-4.3.6.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/spring-core/4.3.6.RELEASE/spring-core-4.3.6.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/spring-expression/4.3.6.RELEASE/spring-expression-4.3.6.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/spring-web/4.3.6.RELEASE/spring-web-4.3.6.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/spring-webmvc/4.3.6.RELEASE/spring-webmvc-4.3.6.RELEASE.jar /Users/wanye/.m2/repository/org/yaml/snakeyaml/1.17/snakeyaml-1.17.jar
Main啟動classpath
/Users/wanye/Code/springboot/target/classes/ /Users/wanye/.m2/repository/ch/qos/logback/logback-classic/1.1.9/logback-classic-1.1.9.jar /Users/wanye/.m2/repository/ch/qos/logback/logback-core/1.1.9/logback-core-1.1.9.jar /Users/wanye/.m2/repository/com/fasterxml/classmate/1.3.3/classmate-1.3.3.jar /Users/wanye/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.8.0/jackson-annotations-2.8.0.jar /Users/wanye/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.8.6/jackson-core-2.8.6.jar /Users/wanye/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.8.6/jackson-databind-2.8.6.jar /Users/wanye/.m2/repository/javax/servlet/jstl/1.2/jstl-1.2.jar /Users/wanye/.m2/repository/javax/validation/validation-api/1.1.0.Final/validation-api-1.1.0.Final.jar /Users/wanye/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/8.5.11/tomcat-embed-core-8.5.11.jar /Users/wanye/.m2/repository/org/apache/tomcat/embed/tomcat-embed-el/8.5.11/tomcat-embed-el-8.5.11.jar /Users/wanye/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/8.5.11/tomcat-embed-websocket-8.5.11.jar /Users/wanye/.m2/repository/org/hibernate/hibernate-validator/5.3.4.Final/hibernate-validator-5.3.4.Final.jar /Users/wanye/.m2/repository/org/jboss/logging/jboss-logging/3.3.0.Final/jboss-logging-3.3.0.Final.jar /Users/wanye/.m2/repository/org/slf4j/jcl-over-slf4j/1.7.22/jcl-over-slf4j-1.7.22.jar /Users/wanye/.m2/repository/org/slf4j/jul-to-slf4j/1.7.22/jul-to-slf4j-1.7.22.jar /Users/wanye/.m2/repository/org/slf4j/log4j-over-slf4j/1.7.22/log4j-over-slf4j-1.7.22.jar /Users/wanye/.m2/repository/org/slf4j/slf4j-api/1.7.22/slf4j-api-1.7.22.jar /Users/wanye/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/1.5.1.RELEASE/spring-boot-autoconfigure-1.5.1.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/boot/spring-boot-starter-logging/1.5.1.RELEASE/spring-boot-starter-logging-1.5.1.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/1.5.1.RELEASE/spring-boot-starter-tomcat-1.5.1.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/boot/spring-boot-starter-web/1.5.1.RELEASE/spring-boot-starter-web-1.5.1.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/boot/spring-boot-starter/1.5.1.RELEASE/spring-boot-starter-1.5.1.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/boot/spring-boot/1.5.1.RELEASE/spring-boot-1.5.1.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/spring-aop/4.3.6.RELEASE/spring-aop-4.3.6.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/spring-beans/4.3.6.RELEASE/spring-beans-4.3.6.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/spring-context/4.3.6.RELEASE/spring-context-4.3.6.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/spring-core/4.3.6.RELEASE/spring-core-4.3.6.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/spring-expression/4.3.6.RELEASE/spring-expression-4.3.6.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/spring-web/4.3.6.RELEASE/spring-web-4.3.6.RELEASE.jar /Users/wanye/.m2/repository/org/springframework/spring-webmvc/4.3.6.RELEASE/spring-webmvc-4.3.6.RELEASE.jar /Users/wanye/.m2/repository/org/yaml/snakeyaml/1.17/snakeyaml-1.17.jar
對比
192:~ wanye$ diff Desktop/mainsort Desktop/mvnsort 12a13 > /Users/wanye/.m2/repository/org/apache/tomcat/embed/tomcat-embed-jasper/8.5.11/tomcat-embed-jasper-8.5.11.jar
對比后發現,通過main啟動后classpath缺少tomcat-embed-jasper.jar;定位到這里,我們就可以解決這個問題了。
解決方法:去掉將pom.xml中tomcat-embed-jasper依賴
還原現場,分析Spring Boot啟動流程org.apache.tomcat.embed tomcat-embed-jasper
在IDE里,直接運行的main函數:
@SpringBootApplication public class Start { public static void main(String[] args) { SpringApplication.run(Start.class, args); } }Embead Tomcat的Servlet加載流程
判斷是否在web環境,略,大家自己查閱相關資料,不是本文重點。
spring boot通過TomcatEmbeddedServletContainerFactory來啟動對應的web服務器。
//TomcatEmbeddedServletContainerFactory @Override public EmbeddedServletContainer getEmbeddedServletContainer( ServletContextInitializer... initializers) { Tomcat tomcat = new Tomcat(); File baseDir = (this.baseDirectory != null ? this.baseDirectory : createTempDir("tomcat")); tomcat.setBaseDir(baseDir.getAbsolutePath()); Connector connector = new Connector(this.protocol); tomcat.getService().addConnector(connector); customizeConnector(connector); tomcat.setConnector(connector); tomcat.getHost().setAutoDeploy(false); configureEngine(tomcat.getEngine()); for (Connector additionalConnector : this.additionalTomcatConnectors) { tomcat.getService().addConnector(additionalConnector); } // 初始化上下文,加載Servlet prepareContext(tomcat.getHost(), initializers); return getTomcatEmbeddedServletContainer(tomcat); }初始化Servlet
protected void prepareContext(Host host, ServletContextInitializer[] initializers) { …… if (isRegisterDefaultServlet()) { addDefaultServlet(context); } // 初始化JspServlet if (shouldRegisterJspServlet()) { addJspServlet(context); addJasperInitializer(context); context.addLifecycleListener(new StoreMergedWebXmlListener()); } …… } // 判斷是否加載jspServlet protected boolean shouldRegisterJspServlet() { return this.jspServlet != null && this.jspServlet.getRegistered() && ClassUtils .isPresent(this.jspServlet.getClassName(), getClass().getClassLoader()); }
shouldRegisterJspServlet是重點了,這里ClassUtils.isPresent會去classLoader里面加載jspServlet(org.apache.jasper.servlet.JspServlet),但是classpath里面沒有這個類。addJspServlet沒有被執行
被吃掉的異常 繼續跟進(如果addJspServlet被執行)jspServlet對象被添加到Tomcat上下文中,并且以jsp擴展名為key放到HashMap中,接下來猜想,當有web請求會通過jsp擴展名去找到jspServlet對象,然后執行jsp。
驗證訪問http://localhost:8080/jsp/home,請求首先被tomcat容器攔截到,然后查找適合的servlet來處理(Tomcat本身是Servlet容器,通過servlet來響應請求,Spring也是通過注冊servlet到tomcat才能處理請求的,當然Jsp也就是servlet),我們來看下核心類org.apache.catalina.mapper.Mapper
public void map(MessageBytes host, MessageBytes uri, String version, MappingData mappingData) throws IOException { if (host.isNull()) { host.getCharChunk().append(defaultHostName); } host.toChars(); uri.toChars(); // 通過uri,找servlet映射 internalMap(host.getCharChunk(), uri.getCharChunk(), version, mappingData); } // 匹配servlet的核心方法 private final void internalMapWrapper(ContextVersion contextVersion, CharChunk path, MappingData mappingData) throws IOException { // 很多匹配規則,這我們關注 Extension Match (擴展名) // Rule 3 -- Extension Match MappedWrapper[] extensionWrappers = contextVersion.extensionWrappers; if (mappingData.wrapper == null && !checkJspWelcomeFiles) { internalMapExtensionWrapper(extensionWrappers, path, mappingData, true); } // Rule 7 -- Default servlet if (mappingData.wrapper == null && !checkJspWelcomeFiles) { if (contextVersion.defaultWrapper != null) { // 默認使用org.springframework.web.servlet.DispatcherServlet mappingData.wrapper = contextVersion.defaultWrapper.object; }} }
我們的請求path是:/jsp/home,所以沒有匹配Rule 3,而是使用默認servlet,那么這個請求被spring的dispatcherServlet接管,然后執行controller
@RequestMapping("/jsp/home") public String home() { return "home"; }
方法執行完畢,spring會去加載home這個view,由于我們整合了jsp,所以通過配置spring.mvc.view.prefix=/WEB-INF/jsp/ 這個路徑下,尋找home.jsp文件,然后將請求轉發(這里大家需要了解一下,請求轉發和重定向的區別)到/WEB-INF/jsp/home.jsp。
處理jsp請求
請求(WEB-INF/jsp/home.jsp)被Tomcat再次攔截,匹配Rule 3,通過擴展名jsp,在map中獲取到jspServlet對象,給大家截圖
簡單總結一下,本文闡述的問題并不是日常開發中的主要問題(可能連主要問題都算不上,誰會用main去調試??),但是遇到了就花時間來研究一下,還是有所收獲的。
分析問題思路
Spring Boot 初始化的部分流程
請求轉發和重定向的區別
另外大家注意如果pom文件中
如果覺得我的文章對您有用,請點贊、收藏。您的支持將鼓勵我繼續創作!
為了提高大家學習效果,錄制了同步的視頻課程,還望大家支持視頻課程
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/70110.html
摘要:大家自己了解一下的使用方法,我這里就不進行詳細的講述了。啟動方式兩種方式都可以主函數啟動或者驗證訪問頁面,驗證是否輸出了當前時間。為了提高大家學習效果,錄制了同步的視頻課程,還望大家支持視頻課程 Spring Boot - 初識 Hello World 索引 Spring Boot - 初識 Hello World Spring Boot - Servlet、過濾器、監聽器、攔截器 ...
摘要:當面講給你聽講堂地址,或許是最實用的教程,新課促銷中,只要你敢來,保你收貨滿滿。優惠報名全程擼碼快速入門教程全原價,優惠價全程擼碼進階全原價,優惠價 回顧 Spring Boot - 初識 Hello World Spring Boot - Servlet、過濾器、監聽器、攔截器 Spring Boot - 靜態資源處理、啟動加載、日志處理 Spring Boot - 部署Deplo...
摘要:背景這段時間較忙,有些想念小紅,為了表達我對小紅的思念之情,決定將啟動的研究一下,看看是否能夠自定義,讓我天天能夠看到她。 背景 這段時間較忙,有些想念小紅,為了表達我對小紅的思念之情,決定將spring boot啟動的banner研究一下,看看是否能夠自定義,讓我天天能夠看到她。 展示 經過調研,發現自定義banner是一個輕松愉快的過程,忍不住讓我多啟動幾次,先看看效果:(省略了一...
摘要:初步使用主要使用注解的方式對進行校驗,第一個例子在需要校驗的字段上指定約束條件然后在中可以這樣調用,加上注解即可。如果校驗失敗,默認會返回框架的出錯信息。指定到的分組名會全部進行校驗,不指定的不校驗。 Spring Boot - 表單校驗(JSR303&Hibernate Validator) 回顧 Spring Boot - 初識 Hello World Spring Boot -...
摘要:學習筆記使用很容易創建一個獨立運行運行內嵌容器準生產級別的基于框架的項目,使用你可以不用或者只需要很少的配置。異常消息如果這個錯誤是由異常引起的。錯誤發生時請求的路徑。 Spring-Boot 1.5 學習筆記 使用Spring Boot很容易創建一個獨立運行(運行jar,內嵌Servlet容器)、準生產級別的基于Spring框架的項目,使用Spring Boot你可以不用或者只需要很...
閱讀 2746·2021-11-16 11:45
閱讀 1654·2021-09-26 10:19
閱讀 2051·2021-09-13 10:28
閱讀 2803·2021-09-08 10:46
閱讀 1530·2021-09-07 10:13
閱讀 1525·2019-08-30 13:50
閱讀 1374·2019-08-30 11:17
閱讀 1455·2019-08-29 13:18