spring boot入门
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
打开spring-boot-starter-parent的pom.xml文件,可以发现spring-boot-starter-parent提供了一些maven的默认设置,比如build中配置文件的路径,在dependency-management节点中设置了很多spring自身库以及外部三方库的版本等,这样我们引入依赖的时候就不需要设置版本信息了,spring-boot-starter-parent应该来说是整体spring-boot的骨架管理者,各具体的starter则是特定类型应用的骨架,比如spring-boot-starter-web是web应用的骨架。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
package com.yidoo.springboot.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; @Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
同时它也定义了默认的自动扫描根目录。因为spring-boot-starter-web增加了tomcat和spring mvc,所以自然而然就认为是web应用了,其实现原理其实就是根据有没有引入特定jar来判断。
这样maven就会开始打包,并启动,如下:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.9.RELEASE) 2018-06-12 14:00:18.782 INFO 17268 --- [ main] Example : Starting Example on TF017564 with PID 17268 (D:\eclipse\workspace\spring-boot-example\target\classes started by TF017564 in D:\eclipse\workspace\spring-boot-example)
2018-06-12 14:00:18.786 INFO 17268 --- [ main] Example : No active profile set, falling back to default profiles: default
2018-06-12 14:00:19.052 INFO 17268 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5455de9: startup date [Tue Jun 12 14:00:19 CST 2018]; root of context hierarchy
2018-06-12 14:00:21.201 INFO 17268 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2018-06-12 14:00:21.220 INFO 17268 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2018-06-12 14:00:21.221 INFO 17268 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.23
2018-06-12 14:00:21.398 INFO 17268 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2018-06-12 14:00:21.399 INFO 17268 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2348 ms
2018-06-12 14:00:21.661 INFO 17268 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2018-06-12 14:00:21.686 INFO 17268 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-06-12 14:00:21.688 INFO 17268 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-06-12 14:00:21.690 INFO 17268 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2018-06-12 14:00:21.691 INFO 17268 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2018-06-12 14:00:22.331 INFO 17268 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5455de9: startup date [Tue Jun 12 14:00:19 CST 2018]; root of context hierarchy
2018-06-12 14:00:22.466 INFO 17268 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto java.lang.String Example.home()
2018-06-12 14:00:22.476 INFO 17268 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-06-12 14:00:22.478 INFO 17268 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-06-12 14:00:22.529 INFO 17268 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-12 14:00:22.529 INFO 17268 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-12 14:00:22.607 INFO 17268 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-12 14:00:22.829 INFO 17268 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-06-12 14:00:22.928 INFO 17268 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2018-06-12 14:00:22.936 INFO 17268 --- [ main] Example : Started Example in 4.606 seconds (JVM running for 36.043)
2018-06-12 14:00:46.142 INFO 17268 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2018-06-12 14:00:46.142 INFO 17268 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2018-06-12 14:00:46.166 INFO 17268 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 24 ms
相当于原来的各种繁琐,spring-boot确实简化了开发过程。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.9.RELEASE)
package com.yidoo.springboot.example.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import com.yidoo.springboot.example.service.ExampleService; @RestController
public class ExampleWeb { @Autowired
private ExampleService exampleSerivce; @RequestMapping("/")
String home() {
return exampleSerivce.get();
}
}
package com.yidoo.springboot.example.service;
import org.springframework.stereotype.Service; @Service
public class ExampleService { public String get() {
return "Hello World";
} }
可以发现,从应用层面来说,和原来开发基本无异,基本上就是引导类由tomcat变成了我们定义的。启动后,通过localhost:8080可以返回hello world。
- 创建合适的ApplicationContext实例;
- 注册CommandLinePropertySource实例,将命令行参数暴露为Spring属性;
- 刷新application context,加载所有单例;
- 触发所有 CommandLineRunner实例;
配置文件
- Devtools配置文件中的值
- 命令行(默认情况下,SpringApplication 会将命令行参数转换为property ,同时添加到Environment)
- ServletConfig初始化参数
- ServletContext初始化参数
- Java系统属性
- 环境变量
- RandomValuePropertySource(主要用来生成随机值,random.*格式,适合用来生成随机值,参考24.1 Configuring random values)
- jar包外的application-{profile}.properties
- jar包内的application-{profile}.properties
- jar包外的application.properties
- jar包内的application.properties
- @Configuration 类上的@PropertySource注解
- SpringApplication.setDefaultProperties声明的默认属性
- 当前运行目录的/config子目录
- 当前目录
- classpath的/config中
- classpath
@ConfigurationProperties("foo")
public class FooProperties { private boolean enabled; private InetAddress remoteAddress; private final Security security = new Security(); public static class Security { private String username; private String password;
}
......
}
- foo.enabled, 默认false
- foo.remote-address, 只要可从String转换过来
- foo.security.username
- foo.security.password
- foo.security.roles, String集合
@Configuration
@EnableConfigurationProperties(FooProperties.class)
public class MyConfiguration {
}
@ConfigurationProperties(prefix="foo")
@Validated
public class FooProperties { @NotNull
private InetAddress remoteAddress; // ... getters and setters }
对于嵌套属性,要验证的话,直接属性值必须标记上@Valid注解以便触发校验,例如:
@ConfigurationProperties(prefix="connection")
@Validated
public class FooProperties { @NotNull
private InetAddress remoteAddress; @Valid
private final Security security = new Security(); // ... getters and setters public static class Security { @NotEmpty
public String username; // ... getters and setters } }
日志
spring boot日志配置 参考https://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html#howto-configure-logback-for-logging
Spring Boot有一个LoggingSystem抽象,他会根据classpath中可以找到的日志实现选择可用的,如果Logback可用,它会优先选择。
如果只是希望为各种logger设置级别,只要在application.properties中增加logging.level开头的配置即可,如下:
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR
要设置文件的位置,增加logging.file开头的配置
如果要更细粒度的配置,则需要使用LoggingSystem的原生配置格式,对于logback,Spring Boot会加载classpath:logback.xml,具体路径搜索顺序参考spring boot学习笔记。
原则上,不应该在application.properties中设置日志配置
spring boot提供了一些logback模板,可以参考或者适当修改,logback官方文档参考https://logback.qos.ch/documentation.html。
如果Log4j 2在classpath上,Spring Boot也支持(注:spring boot不支持1.2.x),如果使用了各种starter组装依赖,则需要排除掉Logback,否则启动的时候会报冲突。如果没有使用starter,则需要额外引入spring-jcl依赖。
配置log4j最简单的方法就是使用spring-boot-starter-log4j2,如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
为了确保java.util.logging执行的debug会被Log4j 2记录,需要配置系统属性java.util.logging.manager为org.apache.logging.log4j.jul.LogManager。
log4j 2手册可以参考http://logging.apache.org/log4j/2.x/log4j-users-guide.pdf
注:一般来说,使用logback或者log4j2其实关系并不大的,但实际上,对于高负载、复杂逻辑的系统,我们会发现一个业务服务上最终响应时间上rpc调用次数、日志、序列化占据了挺大的比例。
对于spring boot下配置log4j 2,并支持MDC(我们都提到了跨界点日志上下文关联的重要性,参考写给大忙人的CentOS 7下最新版(6.2.4)ELK+Filebeat+Log4j日志集成环境搭建完整指南一文),官方并没有文档说明,网上也没有直接提及,虽然如此,鉴于上一段所述原因,笔者还是研究了怎么样才能让spring boot使用log4j2又支持MDC(参考写给大忙人的spring cloud 1.x学习指南一文)。
application.yml中增加如下:
logging:
config: classpath:log4j2.xml
log4j2.xml配置如下:
<Properties>
<Property name="pattern">%d{yyyy-MM-dd HH:mm:ss,SSS} [%X{X-B3-TraceId},%X{X-B3-SpanId},%X{X-B3-ParentSpanId},%X{X-Span-Export}] %5p %c{1}:%L - %m%n</Property>
</Properties>
输出为[3bfdd6f72352ef7e,3bfdd6f72352ef7e,,false]
或者:
<Properties>
<Property name="pattern">%d{yyyy-MM-dd HH:mm:ss,SSS} %X %5p %c{1}:%L - %m%n</Property>
</Properties>
输出为{X-B3-SpanId=3bfdd6f72352ef7e, X-B3-TraceId=3bfdd6f72352ef7e, X-Span-Export=false}
除了这两种自带格式外,还可以自定义,例如在HandlerInterceptor接口的preHandle方法中设置上下文如下:
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String path = request.getContextPath().length() > 1 ? request.getRequestURI().replace(request.getContextPath(), "") : request.getRequestURI(); String sessionId = getSessionCookie(request);
if (StringUtils.isEmpty(sessionId)) {
logger.warn("请求" + path + "的sessionId为空!");
response.sendRedirect(appWebHomeUrl + "/logout.html");
return false;
}
try {
String session = redisUtils.get(REDIS_SESSION_ID_PREFIX + sessionId).toString();
String traceId = sessionId.substring(0, 8) + "_" + path + "_" + formatter.format(new Date()); // 设置log4j2 mdc
ThreadContext.push(traceId);
return true;
} catch (NullPointerException e) {
logger.warn("请求" + path + "的sessionId不存在或已失效!");
response.sendRedirect(appWebHomeUrl + "/logout.html");
return false;
}
}
同理,在postHandle清除,如下:
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object handler, ModelAndView arg3)
throws Exception {
ThreadContext.clearAll();
}
log4j2.xml Pattern配置如下:
<Pattern>%x %d{yyyy-MM-dd HH:mm:ss} [%r] [%c{1.}]-[%p] %t %l %m%n</Pattern>
输出格式为:
[c327093e_/filesend_21:31:39] 2018-11-25 21:31:39 [138805] [c.h.t.a.d.c.CheckItemController]-[DEBUG] http-nio-8086-exec-8 {"operatorId":null,"memberId":null,"memberName":null,"branchId":null,"branchIds":null,"mobile":null,"operatorName":null,"realName":null,"email":null,"sessionKey":null,"sessionId":null,"traceId":"c327093e_/filesend_21:31:39"}
相比默认格式的可读性要好得多,如果使用了rpc比如dubbo或者其它,可以通过filter进行透传。
相关参考文档
http://logging.apache.org/log4j/2.x/manual/thread-context.html
https://github.com/spring-cloud/spring-cloud-sleuth
https://zipkin.io/pages/instrumenting.html
https://github.com/openzipkin/b3-propagation
http://ryanjbaxter.com/cloud/spring%20cloud/spring/2016/07/07/spring-cloud-sleuth.html
https://github.com/spring-cloud/spring-cloud-sleuth/issues/162
filter {
# pattern matching logback pattern
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp}\s+%{LOGLEVEL:severity}\s+\[%{DATA:service},%{DATA:trace},%{DATA:span},%{DATA:exportable}\]\s+%{DATA:pid}\s+---\s+\[%{DATA:thread}\]\s+%{DATA:class}\s+:\s+%{GREEDYDATA:rest}" }
}
}
MVC web应用
@Configuration
public class MyConfiguration { @Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = ...
HttpMessageConverter<?> another = ...
return new HttpMessageConverters(additional, another);
} }
CORS(https://en.wikipedia.org/wiki/Cross-origin_resource_sharing)支持
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter { @Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(false).maxAge(3600);
}
}
嵌入式容器的配置
自定义容器配置
- server.port
- server.address
- server.session.timeout
JDBC等配置
相关问题
在代码中增加系统默认目录配置 ,如下:
@Bean
MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
factory.setLocation("/app/tmp");
return factory.createMultipartConfig();
}
在windows中,如果指向c:\目录,可能会提示无权限,需要注意。
指定应用的context-path
在application.properties文件中添加如下内容:
# 如果无需修改默认端口,此配置可不要
server.port=8080
# 配置次路径后,所有的资源访问路径都会加上/app前缀
server.context-path=/app
需要注意的的,配置了server.context-path路径,所有的资源,请注意,包括静态资源,访问地址都会加上/app前缀。
或
在启动JVM时,添加如下启动参数:
-Dserver.context-path=/app
或
@Component
public class CustomContainer implements EmbeddedServletContainerCustomizer { @Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setContextPath("/app");
}
}
Spring Boot默认只有一个Servlet,默认会映射到根路径/,无法像配置DispatcherServlet的方式只将@Controller的路径指向到上下文地址。
注意:在spring boot 2.x,参数发生了变更。
weblogic集成
参考:
https://blog.csdn.net/MT_xiaoshutong/article/details/54019993
https://segmentfault.com/a/1190000015721951
条件化注入
Springboot中提供了很多条件化配置的注解,只要输入@ConditionalOn
就能出现一大堆。不过比较常用的也就几种:
/*******************
* Class包含Bean *
******************/ // 容器中有ThreadPoolTaskExecutor类型的bean时才注入
@ConditionalOnBean(ThreadPoolTaskExecutor.class)
@ConditionalOnMissingBean(ThreadPoolTaskExecutor.class)
// 类路径中有ThreadPoolTaskExecutor类型的bean时才注入
@ConditionalOnClass(ThreadPoolTaskExecutor.class)
@ConditionalOnMissingClass // 在配置文件中查找hello.name的值,如果能找到并且值等于yan,就注入,如果根本就没配,也注入,这就是matchIfMissing = true的含义
@ConditionalOnProperty(prefix = "hello", name = "name", havingValue = "yan", matchIfMissing = true) //只在web环境下注入
@ConditionalOnWebApplication // java8或以上环境才注入
@ConditionalOnJava(ConditionalOnJava.JavaVersion.EIGHT)
问题描述:spring boot使用maven的package命令打出来的包,却不包含依赖的jar包
问题原因:打包时使用了maven默认的maven-jar-plugin插件,而不是spring-boot-maven-plugin插件
解决方法:pom中必须配置spring-boot-maven-plugin插件,而且必须指定需要执行的目标构建
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<!-- 下面可选 -->
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
问题: spring boot没有打包本地第三方库,如src/lib下的oracle jdbc。
解决方法:在build标签下增加下列配置。
<resources>
<resource>
<directory>src/lib</directory>
<targetPath>BOOT-INF/lib/</targetPath>
<includes>
<include>**/*.jar</include>
</includes>
</resource>
</resources>
spring servlet、listener、context param、error-page、index-page、session-timeout配置:
启动到一半终止,没有日志,如下:
2019-02-19 09:27:46,343 main DEBUG Reconfiguration complete for context[name=18b4aac2] at URI E:\恒生TA\TA-BASE\trunk\Sources\stage-source\Sources\ta-base\ta-base-webapp\target\classes\log4j2.xml (org.apache.logging.log4j.core.LoggerContext@3a80515c) with optional ClassLoader: null . ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.8.RELEASE) [] 2019-02-19 09:27:47 [2662] [o.j.logging]-[DEBUG] background-preinit org.hibernate.validator.internal.util.logging.LoggerFactory.make(LoggerFactory.java:19) Logging Provider: org.jboss.logging.Log4j2LoggerProvider
2019-02-19 09:27:47,107 background-preinit DEBUG AsyncLogger.ThreadNameStrategy=CACHED
[] 2019-02-19 09:27:47 [2670] [o.h.v.i.u.Version]-[INFO] background-preinit org.hibernate.validator.internal.util.Version.<clinit>(Version.java:30) HV000001: Hibernate Validator 5.3.5.Final
[] 2019-02-19 09:27:47 [2698] [o.h.v.i.e.r.DefaultTraversableResolver]-[DEBUG] background-preinit org.hibernate.validator.internal.engine.resolver.DefaultTraversableResolver.detectJPA(DefaultTraversableResolver.java:80) Found javax.persistence.Persistence on classpath, but no method 'getPersistenceUtil'. Assuming JPA 1 environment. All properties will per default be traversable.
日志框架配置不正确到时有些信息没有显示,改成debug启动可能就报错了。如:
log4j栈溢出:
java.lang.*Error: null
at org.slf4j.impl.JDK14LoggerAdapter.fillCallerData(JDK14LoggerAdapter.java:595) ~[slf4j-jdk14-1.7.25.jar:1.7.25]
at org.slf4j.impl.JDK14LoggerAdapter.log(JDK14LoggerAdapter.java:581) ~[slf4j-jdk14-1.7.25.jar:1.7.25]
at org.slf4j.impl.JDK14LoggerAdapter.log(JDK14LoggerAdapter.java:632) ~[slf4j-jdk14-1.7.25.jar:1.7.25]
at org.slf4j.bridge.SLF4JBridgeHandler.callLocationAwareLogger(SLF4JBridgeHandler.java:221) ~[jul-to-slf4j-1.7.25.jar:1.7.25]
at org.slf4j.bridge.SLF4JBridgeHandler.publish(SLF4JBridgeHandler.java:303) ~[jul-to-slf4j-1.7.25.jar:1.7.25]
at java.util.logging.Logger.log(Logger.java:738) ~[?:1.8.0_171]
at org.slf4j.impl.JDK14LoggerAdapter.log(JDK14LoggerAdapter.java:582) ~[slf4j-jdk14-1.7.25.jar:1.7.25]
解决方法,去掉jul依赖,如下:
spring boot将外部路径添加到classpath
默认情况下,spring boot不会将可执行jar之外的目录作为classpath的一部分,通过-classpath指定也不起作用。要使用该功能,需要使用spring boot的PropertiesLauncher特性,也就是使用zip布局,如下所示:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layout>ZIP</layout><!-- enables PropertiesLauncher -->
</configuration>
</plugin>
</plugins>
</build>
然后通过-Dloader.path=/your/folder/containing/password/file/指定作为classpath的目录。
spring boot maven plugin所有配置:https://docs.spring.io/spring-boot/docs/current/maven-plugin/repackage-mojo.html
注意其中的executable不能为true,否则无法修改。
参考:
https://*.com/questions/46728122/add-an-external-xml-file-containing-passwords-to-class-path-in-spring-boot
https://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html