上篇文章介紹了Spring Boot的Demo教程:SpringBoot(一):初章,方便你們快速入門、瞭解、實踐Spring Boot的特性;html
本章則繼續介紹Spring Boot的其它特性java
上篇說過,咱們經過IDEA新建一個Project後,系統會幫咱們建立一個名爲 artifactId + Application 的入口類,這個類有一個標準的Java應用程序的入口方法,而且類上標註@SpringBootApplication的註解。web
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { ...... }
咱們能夠看到,@SpringBootApplication註解,其本質就是@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三個註解組合而成spring
1. @SpringBootConfiguration實質上就是Spring的@Configuration註解,代表這個類是一個JavaConfig類、配置類數據庫
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { }
2. @EnableAutoConfiguration註解的做用:基於導入的jar包依賴,使得SpringBoot去「猜想」你想要如何配置Spring。假設您的項目導入了spring-boot-starter-web的依賴(其依賴了Tomcat和SpringMVC等),則SpringBoot將自動假設您在開發一個WEB應用程序而且自動添加相應的spring配置。雖然「自動配置「被設計用來和「starter」一塊兒工做,可是兩者的概念並不直接相關,您能夠自由挑選任意的starter依賴項以外的jar包,SpringBoot會盡力自動配置您的應用程序。其實@Enable*註解並非新發明的註解,在Spring 3 Framework以後的版本均可以找到它的身影,其目的是用這些註釋替代傳統XML配置文件。例如@EnableTransactionManagement(聲明事務管理)、@EnableWebMvc(啓用MVC)、@EnableCaching(啓用緩存)、@EnableScheduling(初始化調度器)等。@EnableAutoConfiguration的理念和方式與這些註解一脈相承,簡單歸納一下就是:藉助@Import和AutoConfigurationImportSelector類的支持,收集和註冊特定場景相關的bean定義bootstrap
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { ...... }
3. @ComponentScan:告知Spring Framework,哪一個package下的某些註解標識過的類,會被Spring管理api
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Repeatable(ComponentScans.class) public @interface ComponentScan { ...... }
對於Spring Boot來講,有兩種方式去配置咱們的項目,第一種即是使用經過application.yml或者application.properties。而第二種則是使用@Configuration註解和@Bean註解進行配置(這是後話)緩存
對於第一種配置方式,有兩類配置文件:1)application.properties. 2)application.yml. 兩類均可以配置Spring Boot項目中的一些參數設置、變量定義,咱們一般會在其中配置端口、數據庫鏈接、cache鏈接等等,其實二者並沒有本質區別,均是一種配置文件的寫法,能夠類比的想象傳統Spring項目的XML和MyBatis的properties,都是配置文件的一種表達形式,區別僅在於直觀與否、可讀性、適用性等方面tomcat
application.properties(鍵值對一一對應,簡單明瞭)安全
spring.application.name=demo
spring.profiles.active=dev
application.yml(自然的樹形結構,一目瞭然)
spring:
application:
name: demo
profiles:
active: dev
TIP:
必定要注意,yml文件每個冒號後,都是有跟隨着一個空格的,而且每個縮進都是兩個空格(千萬千萬)
Other:
1. 配置文件的路徑
此列表是按照優先級排序(列表中位置較高的路徑下的配置文件中定義的屬性將覆蓋位置較低配置文件中的同名屬性定義)
2. 如何修改默認的配置文件路徑或名稱
方法一(代碼形式)
@SpringBootApplication public class DemoApplication { public static void main(String[] args) throws IOException { // SpringApplication.run(DemoApplication.class, args); // 讀取配置文件 InputStream in = DemoApplication.class.getClassLoader().getResourceAsStream("xxx.properties"); Properties prop = new Properties(); prop.load(in); // 加載配置文件 SpringApplication application = new SpringApplication(DemoApplication.class); application.setDefaultProperties(prop); // 運行服務 application.run(); } }
方法二(啓動時命令行參數形式)
使用環境屬性切換名稱或者路徑(應用程序上下文須要根據配置文件決定具體加載內容,因此必須定義爲environment屬性)
java --jar xxx.jar --spring.config.name=xxx.properties
java --jar xxx.jar --spring.config.location=classpath:/xxx.properties
3. 相信你們在以後的學習中,也會有機會見到bootstrap.yml(bootstrap.application),它與application.yml(application.properties)的區別在於:前者在後者以前被加載並使用,主要用於引導後續的應用程序的上下文加載。例如在Spring Cloud Config Server(遠程讀取配置文件的一種解決方案)中先於應用程序上下文加載以前指定程序讀取的配置文件的 url 以及一些加解密信息,這裏再也不細述,等寫Spring Cloud的隨筆時,會從源碼階段對其進行分析。
在開發中,咱們常常須要自定義一些配置文件(例如JDBC鏈接等),在SpringBoot中應該如何使用呢?
1. 使用@Value註解讀取配置文件(${key})
application.properties或任意能夠被加載的配置文件
user.age=18 user.gender=男
代碼
@RestController
public class DemoController { @Value("${user.name}") private String name; @Value("${user.age}") private Integer age; @Value("${user.gender}") private String gender; @RequestMapping("/hello") public String hello() { return "{name:" + name + ", age:" + age + ", gender:" + gender + "}"; } }
地址欄訪問後卻發現一件很詭異的事情,中文竟然亂碼了,而且項目也是默認指定了UTF-8
這是由於程序默認是以ISO-8859-1的字符編碼讀取配置文件的(另外,真的有人在配置文件中寫中文嗎 = = Orz)
解決方案
1.
# 設置 Spring Boot 編碼格式
# 1.banner中文亂碼問題(SpringBoot2.0以前的版本修改成banner.charset)
spring.banner.charset=UTF-8
# 2.返回頁面、數據中文亂碼問題
server.tomcat.uri-encoding=UTF-8
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
# 3.解決程序讀配置文件亂碼問題
spring.messages.encoding=UTF-8
2. (此步驟個人IDEA並無設置,讀取也是正常的,可是很早以前學習Spring Boot時就碰見了此問題,粘貼出來供你們參考)
IDEA:
設置 File Encodings的Transparent native-to-ascii conversion爲true,具體步驟以下:
依次點擊
File -> Settings -> Editor -> File Encodings
將Properties Files (*.properties)下的Default encoding for properties files設置爲UTF-8,將Transparent native-to-ascii conversion前的選項勾選上便可解決
Eclipse:
安裝properties插件PropertiesEditor,對其進行設置,ASCII碼轉換成中文
2. JavaBean方式讀取自定義properties(使用@ConfigurationProperties指定統一的前綴,@PropertySource註解指定配置文件路徑)(有時候屬性太多了,一個個綁定到屬性字段上太累,並且官方提倡綁定一個對象的bean)
user.properties
user.age=18 user.gender=男
代碼
@Configuration
@ConfigurationProperties(prefix = "user")
@PropertySource("classpath:user.properties")
public class UserEntity {
private Integer age;
private String gender;
......
}
@RestController
public class DemoController {
@Autowired
private UserEntity user;
@RequestMapping("/hello")
public String hello() {
return "{age:" + user.getAge() + ", gender:" + user.getGender() + "}";
}
}
在配置文件中,各個參數之間能夠直接引用,就像下面的設置
user.age=18 user.gender=男 user.info=${user.age}, ${user.gender}
# 隨機字符串 com.wangyanrui.value=${random.value} # 隨機int com.wangyanrui.randomInt=${random.int} # 隨機long com.wangyanrui.randomLong=${random.long} # 隨機uuid com.wangyanrui.randomUUID=${random.uuid} # 100之內的隨機數 com.wangyanrui.randomRangeInt1=${random.int(100)} # 100到200之間的隨機數 com.wangyanrui.randomRangeInt2=${random.int[100,200]}
相信對於WEB項目,不少人都有設置過服務端口的經歷。在Spring Boot中,咱們能夠在application.properties(yml)中設置,亦或者在啓動時動態的輸入啓動參數,兩者是等價的
在命令行中,兩個連續「-」號後的內容(key=value)就是對application.properties中的屬性值進行賦值
java -jar xxx.jar --server.port=10000
經過命令行修改屬性當然提供了不錯的便捷性,可是經過命令行就能夠修改程序運行的參數,在某些狀況下豈不是很不安全(萌新瑟瑟發抖),Spring Boot也爲咱們提供了屏蔽命令行的設置
@SpringBootApplication public class DemoApplication { public static void main(String[] args) throws IOException { // SpringApplication.run(DemoApplication.class, args); SpringApplication application = new SpringApplication(DemoApplication.class); // 禁止命令行設置屬性值 application.setAddCommandLineProperties(false); application.run(args); } }
咱們在開發Spring Boot項目時,一般同一套程序會被應用和安裝到不一樣的環境中,例如開發、測試、生產等。各個環境的數據庫地址,服務器端口等等配置均會不一樣,若是在每次發佈程序時都要大批量的修改這部分數據,是一件極其極其繁瑣且容易發生錯誤的事
對於多環境的配置,各個構建工具或者框架的基本思路是一致的,即經過配置多份不一樣環境的配置文件,經過一些打包命令指定打包的內容加以區分。Spring Boot也不例外,或者說,相比較傳統Maven來講更加簡單便捷
在Spring Boot的多環境配置中,配置文件的名稱須要知足"application-{profile}.properties"或"application-{profile}.yml"的形式,其中"profile"對應了不一樣的環境標識
至於哪一個具體的文件會被加載,須要在application.properties中,經過spring.profiles.active屬性進行設置,其值對應了不一樣的"{profile}"值
如:spring.profiles.active=prod,則指定加載application-prod.properties配置文件的內容
因此,Spring Boot配置多環境的思路以下
application.properties中配置通用內容,而且設置"spring.profiles.active=xxx"指定程序運行讀取的配置文件
application-xxx.properties配置各個環境不一樣的內容
經過修改application.properties或者命令行的形式,激活不一樣環境的配置
SpringBoot內部日誌系統使用Apache的Commons Logging對JDKLogging、Log4J2和Logback提供了默認配置,而且若是使用的「starters」,那麼默認使用的就是Logback,咱們能夠經過依賴關係看出默認的日誌依賴爲Logback
簡而言之,只要你的POM文件中使用了spring-boot-starter(starter是SpringBoot的核心部件,不使用它,近乎於自殘手腳= =),就表明其會自動配置Logback做爲日誌的實現
SpringBoot最招人喜歡的一大特色即是配置方便,關於日誌配置的相關參數,只須要寫在application.properties中就能夠生效
對於日誌來講,application.properties僅僅只能作一些基本配置,仍是應該添加對應日誌系統的配置文件的。我的建議,若是僅僅是本地演示或者非生產使用,SpringBoot對於Logback的默認配置就足夠使用,咱們仍是要以配置文件的形式爲主。這裏不對application.properties配置日誌和日誌的基本概念作過多的描述,下面歸納了配置文件所能配置的所有選項,其中logging.config主要用於指定日誌配置的文件路徑(因爲日誌是在應用程序上下文被建立以前初始化,因此不能使用@Configuration和@PropertySource(value={"classpath:application.properties"})對其進行配置),其他配置項見名知意便可。
logging.config # 日誌配置文件路徑,如 classpath:logback-spring.xml
logging.exception-conversion-word # 記錄異常時使用的轉換詞
logging.file # 記錄日誌的文件名稱,如:dev.log
logging.file.max-history # 日誌的文件自動切割時長
logging.file.max-size # 日誌的文件自動切割大小(默認10MB)
logging.level.* # 日誌映射,如:logging.level.root=WARN,logging.level.org.springframework.web=DEBUG
logging.path # 記錄日誌的文件路徑,如:c:/
logging.pattern.console # 向控制檯輸出的日誌格式,只支持默認的 logback 設置。
logging.pattern.dateformat # 向控制檯輸出的日期格式,只支持默認的 logback 設置。
logging.pattern.file # 向記錄日誌文件輸出的日誌格式,只支持默認的 logback 設置。
logging.pattern.level # 用於呈現日誌級別的格式,只支持默認的 logback 設置。
logging.register-shutdown-hook # 初始化時爲日誌系統註冊一個關閉鉤子
Spring Boot默認加載classpath:logback-spring.xml、classpath:logback-spring.groovy、logback.xml、logback.groovy(咱們會盡能夠的使用 "-spring" 的形式標註咱們的配置文件名稱,SpringBoot會自動注入一些多環境的配置項,此對log4j2是無效的)(官方說log4j2也可使用"-spring",可是我發現並不生效)(咱們也能夠自定義配置文件的名稱,只須要在application.properties中經過logging.config指定日誌文件路徑便可)
<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 文件輸出格式 --> <property name="PATTERN" value="%-12(%d{yyyy-MM-dd HH:mm:ss.SSS}) |-%-5level [%thread] %c [%L] -| %msg%n"/> <!-- test文件路徑 --> <property name="TEST_FILE_PATH" value="c:/test.log"/> <!-- prod文件路徑 --> <property name="PRO_FILE_PATH" value="/home/wangyanrui/logs"/> <!-- 開發環境 --> <springProfile name="dev"> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>${PATTERN}</pattern> </encoder> </appender> <root level="info"> <appender-ref ref="CONSOLE"/> </root> </springProfile> <!-- 測試環境 --> <springProfile name="test"> <!-- 天天產生一個文件 --> <appender name="TEST_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 文件路徑 --> <file>${TEST_FILE_PATH}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 文件名稱 --> <fileNamePattern>${TEST_FILE_PATH}/info.%d{yyyy-MM-dd}.log</fileNamePattern> <!-- 文件最大保存歷史數量 --> <MaxHistory>100</MaxHistory> </rollingPolicy> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>${PATTERN}</pattern> </layout> </appender> <root level="info"> <appender-ref ref="TEST_FILE"/> </root> </springProfile> <!-- 生產環境 --> <springProfile name="prod"> <appender name="PROD_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${PRO_FILE_PATH}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${PRO_FILE_PATH}/warn.%d{yyyy-MM-dd}.log</fileNamePattern> <MaxHistory>100</MaxHistory> </rollingPolicy> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>${PATTERN}</pattern> </layout> </appender> <root level="warn"> <appender-ref ref="PROD_FILE"/> </root> </springProfile> </configuration>
其中,springProfile標籤的name屬性對應於application.properties中的spring.profiles.active。咱們能夠經過指定不一樣的profile,激活同一個日誌配置文件中不一樣springProfile標籤下的配置內容
首先排除默認的Logback
<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>
引入基於SpringBoot的Log4j2 Starter
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency>
使用配置文件配置log4j2(關於多環境的log4j2,須要新建多個不一樣的配置文件,在不一樣的application-xxx.properties中分別指定不一樣的配置文件便可)(官方說可使用"-spring",可是我發現並不生效)
<?xml version="1.0" encoding="UTF-8"?> <!--設置log4j2的自身log級別爲warn --> <configuration status="warn"> <properties> <Property name="app_name">SpringBoot-demo</Property> <Property name="log_path">logs/${app_name}</Property> </properties> <appenders> <console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="[%d][%t][%p][%l] %m%n"/> </console> <RollingFile name="RollingFileInfo" fileName="${log_path}/info.log" filePattern="${log_path}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.gz"> <Filters> <ThresholdFilter level="INFO"/> <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/> </Filters> <PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/> <Policies> <!-- 歸檔天天的文件 --> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> <!-- 限制單個文件大小 --> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <!-- 限制天天文件個數 --> <DefaultRolloverStrategy compressionLevel="0" max="10"/> </RollingFile> <RollingFile name="RollingFileWarn" fileName="${log_path}/warn.log" filePattern="${log_path}/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log.gz"> <Filters> <ThresholdFilter level="WARN"/> <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/> </Filters> <PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/> <Policies> <!-- 歸檔天天的文件 --> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> <!-- 限制單個文件大小 --> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <!-- 限制天天文件個數 --> <DefaultRolloverStrategy compressionLevel="0" max="10"/> </RollingFile> <RollingFile name="RollingFileError" fileName="${log_path}/error.log" filePattern="${log_path}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz"> <ThresholdFilter level="ERROR"/> <PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/> <Policies> <!-- 歸檔天天的文件 --> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> <!-- 限制單個文件大小 --> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <!-- 限制天天文件個數 --> <DefaultRolloverStrategy compressionLevel="0" max="10"/> </RollingFile> </appenders> <loggers> <!--過濾掉spring和hibernate的一些無用的debug信息 --> <root level="info"> <appender-ref ref="Console"/> <appender-ref ref="RollingFileInfo"/> <appender-ref ref="RollingFileWarn"/> <appender-ref ref="RollingFileError"/> </root> </loggers> </configuration>
在POM.xml裏設置
<packaging>war</packaging>
POM.xml中的spring-boot-starter-web默認引入了一個嵌入的Tomcat容器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.0</version> <scope>provided</scope> </dependency>
@SpringBootApplication public class DemoApplication extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { // return super.configure(builder); return builder.sources(DemoApplication.class); } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
命令行執行mvn的打包命令:mvn clean package便可
等待打包完成,將target目錄下的war包放置在tomcat的webapps目錄下,啓動tomcat便可
熱啓動在正常開發項目中很常見,SpringBoot對其有很好的配置,只需修改POM.xml文件,添加以下內容便可支持熱啓動
dependency節點下添加以下依賴 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> build節點的plugins節點修改成以下 <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> </configuration> </plugin> </plugins> </build>
這種方式是基於類熱加載機制來實現熱加載的,所以就要求了修改完成代碼後必須從新編譯當前代碼後才能出發熱部署。
Eclipse默認就支持自動編譯,而在IDEA中默認是關閉了自動編譯的,須要以下設置
1. 開啓IDEA項目自動編譯
設置 —> Build, Execut, Deployment —> Compiler,勾選中左側的Build Project automatically
2. 開啓IDEA項目自動make
ctrl + shift + a —> 搜索命令registry —> 勾選compiler.automake.allow.when.app.running
SringBoot的特性有不少,這裏僅作簡單的闡述,更多內容仍是推薦去看Spring爸爸的官方文檔(PS:Spring的官方文檔是我看到過的文檔中描述最清楚的一個......)