(點選上方公眾號,可快速關註)
來源:Hengyunabc ,
hengyunabc.github.io/spring-boot-fat-jar-jsp-sample/
spring boot 對於jsp支援的限制
對於jsp的支援,Spring Boot官方只支援了war的打包方式,不支援fat jar。參考官方檔案。
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-jsp-limitations
這裡spring boot官方說是tomcat的問題,實際上是spring boot自己改變了打包格式引起的。參考之前的文章。
http://hengyunabc.github.io/spring-boot-classloader/#spring-boot-1-3-和-1-4-版本的區別
原來的結構之下,tomcat是可以掃描到fat jar裡的META-INF/resources目錄下麵的資源的。在增加了BOOT-INF/classes之後,則tomcat掃描不到了。
那麼怎麼解決這個問題呢?下麵給出一種方案,來實現對spring boot fat jar/exploded directory的jsp的支援。
個性化配置tomcat,把BOOT-INF/classes 加入tomcat的ResourceSet
在tomcat裡,所有掃描到的資源都會放到所謂的ResourceSet裡。比如servlet 3規範裡的應用jar包的META-INF/resources就是一個ResourceSet。
現在需要想辦法把spring boot打出來的fat jar的BOOT-INF/classes目錄加到ResourceSet裡。
下麵透過實現tomcat的 LifecycleListener介面,在Lifecycle.CONFIGURE_START_EVENT事件裡,獲取到BOOT-INF/classes的URL,再把這個URL加入到WebResourceSet裡。
/**
* Add main class fat jar/exploded directory into tomcat ResourceSet.
*
* @author hengyunabc 2017-07-29
*
*/
public class StaticResourceConfigurer implements LifecycleListener {
private final Context context;
StaticResourceConfigurer(Context context) {
this.context = context;
}
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
URL location = this.getClass().getProtectionDomain().getCodeSource().getLocation();
if (ResourceUtils.isFileURL(location)) {
// when run as exploded directory
String rootFile = location.getFile();
if (rootFile.endsWith(“/BOOT-INF/classes/”)) {
rootFile = rootFile.substring(0, rootFile.length() – “/BOOT-INF/classes/”.length() + 1);
}
if (!new File(rootFile, “META-INF” + File.separator + “resources”).isDirectory()) {
return;
}
try {
location = new File(rootFile).toURI().toURL();
} catch (MalformedURLException e) {
throw new IllegalStateException(“Can not add tomcat resources”, e);
}
}
String locationStr = location.toString();
if (locationStr.endsWith(“/BOOT-INF/classes!/”)) {
// when run as fat jar
locationStr = locationStr.substring(0, locationStr.length() – “/BOOT-INF/classes!/”.length() + 1);
try {
location = new URL(locationStr);
} catch (MalformedURLException e) {
throw new IllegalStateException(“Can not add tomcat resources”, e);
}
}
this.context.getResources().createWebResourceSet(ResourceSetType.RESOURCE_JAR, “/”, location,
“/META-INF/resources”);
}
}
}
為了讓spring boot embedded tomcat載入這個 StaticResourceConfigurer,還需要一個EmbeddedServletContainerCustomizer的配置:
@Configuration
@ConditionalOnProperty(name = “tomcat.staticResourceCustomizer.enabled”, matchIfMissing = true)
public class TomcatConfiguration {
@Bean
public EmbeddedServletContainerCustomizer staticResourceCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
((TomcatEmbeddedServletContainerFactory) container)
.addContextCustomizers(new TomcatContextCustomizer() {
@Override
public void customize(Context context) {
context.addLifecycleListener(new StaticResourceConfigurer(context));
}
});
}
}
};
}
}
這樣子的話,spring boot就可以支援fat jar裡的jsp資源了。
demo地址:
https://github.com/hengyunabc/spring-boot-fat-jar-jsp-sample
總結
-
spring boot改變了打包結構,導致tomcat沒有辦法掃描到fat jar裡的/BOOT-INF/classes
-
透過一個StaticResourceConfigurer把fat jar裡的/BOOT-INF/classes加到tomcat的ResourceSet來解決問題
【關於投稿】
如果大家有原創好文投稿,請直接給公號傳送留言。
① 留言格式:
【投稿】+《 文章標題》+ 文章連結
② 示例:
【投稿】《不要自稱是程式員,我十多年的 IT 職場總結》:http://blog.jobbole.com/94148/
③ 最後請附上您的個人簡介哈~
看完本文有收穫?請轉發分享給更多人
關註「ImportNew」,提升Java技能