<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應用的骨架。html
<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 :: (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
<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。java
@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; } ...... }
@Configuration @EnableConfigurationProperties(FooProperties.class) public class MyConfiguration { }
@ConfigurationProperties(prefix="foo") @Validated public class FooProperties { @NotNull private InetAddress remoteAddress; // ... getters and setters }
對於嵌套屬性,要驗證的話,直接屬性值必須標記上@Valid註解以便觸發校驗,例如:mysql
@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。git
若是Log4j 2在classpath上,Spring Boot也支持(注:spring boot不支持1.2.x),若是使用了各類starter組裝依賴,則須要排除掉Logback,不然啓動的時候會報衝突。若是沒有使用starter,則須要額外引入spring-jcl依賴。
配置log4j最簡單的方法就是使用spring-boot-starter-log4j2,以下:github
<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.pdfweb
注:通常來講,使用logback或者log4j2其實關係並不大的,但實際上,對於高負載、複雜邏輯的系統,咱們會發現一個業務服務上最終響應時間上rpc調用次數、日誌、序列化佔據了挺大的比例。redis
對於spring boot下配置log4j 2,並支持MDC(咱們都提到了跨界點日誌上下文關聯的重要性,參考寫給大忙人的CentOS 7下最新版(6.2.4)ELK+Filebeat+Log4j日誌集成環境搭建完整指南一文),官方並無文檔說明,網上也沒有直接說起,雖然如此,鑑於上一段所述緣由,筆者仍是研究了怎麼樣才能讓spring boot使用log4j2又支持MDC(參考寫給大忙人的spring cloud 1.x學習指南一文)。spring
application.yml中增長以下:
logging:
config: classpath:log4j2.xml
log4j2.xml配置以下:sql
<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]
或者:apache
<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}" } } }
@Configuration public class MyConfiguration { @Bean public HttpMessageConverters customConverters() { HttpMessageConverter<?> additional = ... HttpMessageConverter<?> another = ... return new HttpMessageConverters(additional, another); } }
@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); } }
在代碼中增長系統默認目錄配置 ,以下: @Bean MultipartConfigElement multipartConfigElement() { MultipartConfigFactory factory = new MultipartConfigFactory(); factory.setLocation("/app/tmp"); return factory.createMultipartConfig(); }
在windows中,若是指向c:\目錄,可能會提示無權限,須要注意。
在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,參數發生了變動。
參考:
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>
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不會將可執行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