64

深入 Spring Boot :实现对 Fat Jar jsp&nb

 5 years ago
source link: http://www.10tiao.com/html/194/201806/2651481295/1.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

(点击上方公众号,可快速关注)


来源: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技能


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK