zoukankan      html  css  js  c++  java
  • SpringBoot加载外部依赖

    背景

    公司一个项目的大数据平台进行改造,之前使用Structured Streaming作为实时计算框架,需要替换为替换为Kafka Streams,并使用SpringBoot包装,使其可以纳入微服务体系。然而由于之前并没有接触过SpringFramework相关技术,并且项目工期较为紧张,因此只好花了2天时间看了看Spring和SpringBoot,并且在改造过程中沿用大部分原有代码,最后套上SpringBoot的壳子(就是基本不使用Spring Data相关的封装和DI、AOP这些特性,只是在启动类上添加@SpringBootApplication注解,并在main()方法里面使用SpringApplication.run()方式启动)。

    问题

    然后在部署过程中就遇到了一个比较蛋疼的问题:因为遗留代码的关系,部分配置项的名称是自定义的,并使用java.util.ResourceBundlegetString()来读取,而为了让项目可以注册到Eureka以及使用SpringBoot默认的日志配置,在配置文件中配置了eureka.client.serviceUrl.defaultZone以及logging.file等SpringBoot内置的配置项,并使用SpringBoot内置的配置读取方式读取。也就是在一个应用程序中,混合使用了两种读取配置文件的方式。在使用maven将应用程序“EatMalonPeople”打包后,根据微服务组大佬的友情提示,使用如下命令运行程序:

    java -jar EatMalonPeople.jar
    

    然鹅运行倒是没问题,不过application.properties文件在jar包里面,修改配置文件需要用vim直接修改jar包。感觉这种方式略挫,不太能接受。按照以往的经验,使用java -cp命令可以指定classpath,应用程序会优先读取classpath指定的外部配置文件。但是当我在config目录下拷贝了一份application.properties文件,并修改了其中使用ResourceBundle.getString()方式读取的配置项时,再使用:

    java -cp .:./config/application.properties EatMalonPeople.jar
    

    启动后,发现生效的配置项仍然是EatMalonPeople.jar这个jar包内的配置项......
    感觉不太科学啊。于是去查了查SpringBoot项目加载配置文件的顺序,结果根据Spring官网的提示,SpringBoot加载配置文件application.properties的顺序依次为:

    1. 当前目录的cofnig目录
    2. 当前目录
    3. classpath目录下的/config目录
    4. classpath目录

    但是根据这种顺序,明明应该加载config目录下的配置文件嘛。于是在pom文件中exclude掉了配置文件:

    <resources>
        <resource>
            <directory>src/main/resources</directory>
                <excludes>
                    <exclude>${resource.exclude}</exclude>
                </excludes>
        </resource>
    </resources>
    

    这样jar包内就不含有配置文件了。再次使用

    java -cp .:./config/application.properties EatMalonPeople.jar
    

    启动后,应用程序能注册到Eureka,然而使用ResourceBundle.getString()方法获取的配置项竟然找不到了,直接throw出了内部封装的找不到配置项错误!
    天啦噜,这是要闹哪样嘛。原来SpringBoot读取配置文件的顺序只能保证内部方式可以读到,也就是说对于SpringBoot的jar包,-cp命令是没有用的撒。没想到我这个刚学过两天Spring的萌新竟然碰到了这种问题,真是不给活路啊。

    解决

    又是一顿好找,终于在官网的另一处发现了原因。
    原来SpringBoot是通过org.springframework.boot.loader.Launcher类来启动的,这货才是jar包中META-INF/MANIFEST.MF文件中Main-Class这个属性的值,Launcher最后会调用我们自定义启动类中的的main()方法(而我们自定义的启动类是META-INF/MANIFEST.MF文件中的Start-Class属性的值,这个属性应该是SpringBoot特有的)。这个类有三个子类,分别是JarLauncher,WarLauncher,PropertiesLauncher,前两个Launcher都是不能添加外部依赖的。只有PropertiesLauncher是可以的。于是在spring-boot-maven-plugin中添加layout属性,添加后的spring-boot-maven-plugin的配置是酱婶儿的:

    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
            <layout>ZIP</layout>
        </configuration>
    </plugin>
    

    然后用maven重新打包,并且在运行时使用loader.path参数指定外部classpath地址:

    java -Dloader.path=./config -jar EatMalonPeople.jar
    

    这样SpringBoot应用程序就可以使用两种方式愉快的读取外部配置文件啦(其实还有外部jar,也是可以的)!至于具体原理,感兴趣的同学可以看看参考中的链接。

    总结

    花了我一天时间。SpringBoot水平还是太菜,需要以后再学习一个。另外很感谢参考中的三篇博客(2是官方文档)。

    参考

    1. How to add extra dir to CLASSPATH at spring-boot
    2. Lanching executable jars
    3. Spring Boot应用启动原理分析
    4. 将Springboot的“fat jar” 变成 “thin jar”


    作者:柴诗雨
    链接:https://www.jianshu.com/p/a2cf2336a48c
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    笔记-归并排序
    Repeated Substring Pattern
    Assign Cookies
    Number of Boomerangs
    Paint Fence
    Path Sum III
    Valid Word Square
    Sum of Two Integers
    Find All Numbers Disappeared in an Array
    First Unique Character in a String
  • 原文地址:https://www.cnblogs.com/a-du/p/12172999.html
Copyright © 2011-2022 走看看