首页 > 开发 > Java > 正文

深入Spring Boot实现对Fat Jar jsp的支持

2024-07-14 08:41:09
字体:
来源:转载
供稿:网友

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自己改变了打包格式引起的。

原来的结构之下,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

总结

  1. spring boot改变了打包结构,导致tomcat没有办法扫描到fat jar里的/BOOT-INF/classes
  2. 通过一个StaticResourceConfigurer把fat jar里的/BOOT-INF/classes加到tomcat的ResourceSet来解决问题

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持VeVb武林网。


注:相关教程知识阅读请移步到JAVA教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表