spring boot完整学习指南(含各种常见问题servlet、web.xml、maven打包,spring mvc差别及解决方法)
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.StackOverflowError: 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://stackoverflow.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
补充
spring boot面试题 https://blog.csdn.net/qq_30999361/article/details/124461725