《Spring Boot 實(shí)戰(zhàn):從0到1》第3章 零XML配置的Spring Boot Application

第3章 零XML配置的Spring Boot

Spring Boot 提供了一種統(tǒng)一的方式來管理應(yīng)用的配置惜颇,允許開發(fā)人員使用屬性properties文件皆刺、YAML 文件、環(huán)境變量和命令行參數(shù)來定義優(yōu)先級(jí)不同的配置值凌摄。

本章我們就來體驗(yàn)一下零XML配置的Spring Boot 應(yīng)用的開發(fā)羡蛾。

2.1 Spring Boot 簡(jiǎn)介

2.1.1 Spring 去 XML配置簡(jiǎn)史

Spring IOC有一個(gè)非常核心的概念——Bean。由Spring容器來負(fù)責(zé)對(duì)Bean的實(shí)例化锨亏,裝配和管理痴怨。

最早XML是用來描述Bean最為流行的配置方式忙干。Spring可以從XML配置文件中讀取任何類型的元數(shù)據(jù)并自動(dòng)轉(zhuǎn)換成相應(yīng)的Java代碼。

隨著Spring的日益發(fā)展浪藻,越來越多的人對(duì)Spring提出了批評(píng)捐迫。“Spring項(xiàng)目大量的爛用XML”就是最為嚴(yán)勵(lì)的一個(gè)批評(píng)珠移。

由于Spring會(huì)把幾乎所有的業(yè)務(wù)類都以Bean的形式配置在XML文件中弓乙,造成了大量的XML文件。使用XML來配置Bean失去了編譯時(shí)的類型安全檢查钧惧。大量的XML配置使得整個(gè)項(xiàng)目變得更加復(fù)雜暇韧。

我們使用XML配置的問題之一是要等到運(yùn)行時(shí)的時(shí)候來發(fā)現(xiàn)Bean里面的錯(cuò)誤或者其他愚蠢的問題。當(dāng)然浓瞪,在使用Spring的IDE插件(或者其他整合了Spring Tools Suite的工具)能在一定程度上發(fā)現(xiàn)這方面問題懈玻。

  • Spring 2.5中我們開始有了面向注解的依賴注入編程(@Component和 @Autowired)。
  • Spring 3.0中我們有了 JavaConfig , 它能夠取代 XML乾颁。Spring 3.1中又提供了@Enable* 系列的注解涂乌,使得基于注解的配置更加自動(dòng)化。
  • 在 Spring 4.0中@Conditional注解(org.springframework.context.annotation.Conditional)實(shí)現(xiàn)的基于條件的配置英岭,根據(jù)應(yīng)用的類路徑中的類湾盒、環(huán)境信息以及其他一些相關(guān)信息,在運(yùn)行時(shí)自動(dòng)化地完成配置诅妹,大量省去了程序員們大量樣板化的手工配置工作罚勾。

2.1.2 要進(jìn)一步解決的問題

在有了上面的這些支持后,使用Spring或者SpringMVC的過程中吭狡,仍然有很多配置以及繁瑣的操作需要我們手工去完成尖殃。例如:

  • 單獨(dú)部署配置一個(gè) tomcat(tomcat 的相關(guān)配置需要單獨(dú)去tomcat安裝目錄下配)
  • 使用大量依賴庫(kù)可能導(dǎo)致的版本沖突
  • Spring 集成使用使用模板引擎 Freemarker、velocity划煮、thymeleaf 等需要單獨(dú)配置
  • Spring 集成使用 MyBatis送丰、JPA 等 ORM 框架需要單獨(dú)配置
  • Spring 集成使用安全框架 Security 、日志框架等等都需要單獨(dú)一套配置
  • 配置 SpringMVC 中的 DispatcherServlet 需要在 web.xml 或者在 Servlet 初始化代碼里進(jìn)行顯式配置
  • 靜態(tài)資源的處理
  • 應(yīng)用的運(yùn)維監(jiān)控工作等

由于這些已經(jīng)存在的問題弛秋,Spring Boot應(yīng)運(yùn)而生器躏,使用Spring Boot可以讓我們快速創(chuàng)建一個(gè)基于Spring的項(xiàng)目,而讓這個(gè)Spring項(xiàng)目跑起來我們只需要很少的配置就可以了蟹略。

2.1.3 SpringBoot 的核心功能

Spring Boot主要有如下核心功能:

  1. 直接創(chuàng)建一個(gè)可以獨(dú)立運(yùn)行的Spring項(xiàng)目
    Spring Boot可以以jar包的形式來運(yùn)行登失,我們可以直接通過 java -jar xx.jar 命令來運(yùn)行一個(gè)Spring Boot項(xiàng)目。

  2. 內(nèi)嵌Servlet容器

Spring Boot可以內(nèi)嵌Tomcat直接一鍵運(yùn)行 Web 應(yīng)用科乎。我們不再需要打 war 包壁畸,丟到 Tomcat 下面,再啟動(dòng) Tomcat 等等一系列操作了。

  1. 提供starter簡(jiǎn)化 Maven/Gradle 配置

使用Spring或者SpringMVC我們需要添加大量的依賴捏萍,而這些依賴很多都是固定的樣板化配置太抓。Spring Boot 通過starter 幫助我們簡(jiǎn)化 Maven/Gradle 配置。

  1. 自動(dòng)配置Spring
    SpringBoot 提供了大量超級(jí)實(shí)用的 starter令杈,大大簡(jiǎn)化了我們使用 Spring 開發(fā)過程中的配置走敌。

  2. 生產(chǎn)環(huán)境的應(yīng)用監(jiān)控
    使用SpringBoot 提供的 Actuator ,我們可以方便地進(jìn)行應(yīng)用程序的監(jiān)控逗噩。

  3. 無代碼生成和xml配置
    SpringBoot 沒有引入任何形式的代碼生成掉丽,它是使用的 Spring 4.0的條件注解以實(shí)現(xiàn)根據(jù)條件進(jìn)行配置;同時(shí)使用了 Maven/Gradle 的依賴傳遞解析機(jī)制來實(shí)現(xiàn) Spring 應(yīng)用里面的自動(dòng)配置异雁。

2.2 回顧 Spring

Spring能夠進(jìn)行自動(dòng)化的裝配捶障,它使用兩種方式來進(jìn)行自動(dòng)化裝配:

1、組件掃描:
Spring會(huì)自動(dòng)發(fā)現(xiàn)應(yīng)用上下文中所創(chuàng)建的bean

2纲刀、自動(dòng)裝配:
Spring會(huì)自動(dòng)構(gòu)建bean之間的依賴關(guān)系

Spring的自動(dòng)化裝配使用了零xml配置项炼,也就是使用了全代碼配置(注解配置),其中代碼配置類使用@Configuration注解進(jìn)行標(biāo)注示绊。

2.2.1 組件掃描:

@Component能給一個(gè)類自動(dòng)生成對(duì)象并注入到Spring容器中锭部,比如下面的CDPlayer,會(huì)自動(dòng)new一個(gè)CDPlayer的對(duì)象并放置到Spring容器中面褐。

  public interface Player {
      void play();
  }

  @Component
  public class CDPlayer implements Player {
      public void play() {
          System.out.print("播放CD");
      }
  }

我們知道拌禾,Spring容器中每個(gè)bean都有自己唯一的一個(gè)id,自動(dòng)注入的bean的id的規(guī)則如下:

1展哭、如果@Component中有值湃窍,類似
@Component("xxx"),那么此bean的id即為xxx 摄杂。

2坝咐、如果類名為第一個(gè)字母大寫循榆,第二個(gè)字母小寫析恢,即滿足首字母大寫的駝峰命令規(guī)則,比如CdPlayer, 那么其bean的id第一個(gè)字母要小寫秧饮,其余不變映挂,所以最終為cdplayer。

3盗尸、如果不滿足規(guī)則1柑船,比如類名是CDPlayer, 那么其bean的id跟類名相同,所以最終為CDPlayer泼各。

2.2.2 自動(dòng)裝配

需要注意的是鞍时,配置對(duì)象需要 @Configuration和@ComponentScan注解,而@ComponentScan注解是標(biāo)注Spring掃描的基礎(chǔ)包名的。如果沒有值逆巍,默認(rèn)會(huì)掃描自己所在的包的所有類及塘。

其中的Configuration配置對(duì)象:

  @Configuration
  @ComponentScan
  public class PlayerConfig {
  }

那么如何配置掃描包呢?比如我想掃描 com.easy.springboot 包下的所有類锐极,可以這樣:

  @ComponentScan(basePackages = "com.easy.springboot")

我們使用junit4來進(jìn)行測(cè)試笙僚,注意在想獲取Spring中bean上加上@Autowired,Spring會(huì)自動(dòng)注入灵再。

另外肋层,下面的Player可以換成CDPlayer,因?yàn)镃DPlayer的對(duì)象既是CDPlayer的對(duì)象翎迁,也是Player的對(duì)象栋猖。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = PlayerConfig.class)
public class TestCDPlayer {

    @Autowired
    private Player cdPlayer;
 
    @Test
    public void testNotNull(){
        cdPlayer.play();
    }
}

另外,我們也可以將一個(gè)對(duì)象注入到另一個(gè)對(duì)象中汪榔。比如有一個(gè)People類掂铐,要為其注入一個(gè)Player類,然后其跑步的時(shí)候會(huì)調(diào)用Player類的play方法揍异,這樣實(shí)現(xiàn)即可:

  @Component
  public class People {
      @Autowired
      private Player player;
      public void run(){
          player.play();
          System.out.println("正在跑步");
      }
  }

這里的

@Autowired
private Player player

Spring會(huì)自動(dòng)把生成的Player對(duì)象注入到People類中全陨。

注入的規(guī)則分為兩步:
1、Spring會(huì)先查找id為player的Bean對(duì)象衷掷,如果找到辱姨,注入進(jìn)來
2、如果沒有找到id為player的Player對(duì)象戚嗅,那么就去尋找Spring容器中查找Player的對(duì)象雨涛,如果一個(gè)都沒有,或者有兩個(gè)或者多個(gè)懦胞,那么就會(huì)報(bào)錯(cuò)替久。

2.2.3 使用用JavaConfig

一般來說,自動(dòng)裝配bean已經(jīng)能為我們解決很多問題躏尉。但是蚯根,有的時(shí)候可能我們需要更自動(dòng)的配置,這個(gè)時(shí)候我們就可以使用 JavaConfig 來完成胀糜。

Spring Boot的零XML配置也是基于 JavaConfig來實(shí)現(xiàn)的颅拦。

JavaConfig就是使用注釋來描述Bean配置的組件,也就是注解驅(qū)動(dòng)配置( Annotation-Driven Configuration)教藻。它是從Spring 3.0后嵌入到Spring里的一個(gè)以前的獨(dú)立項(xiàng)目距帅。JavaConfig能夠等價(jià)看成是XML文件,不過它只是用Java編寫的括堤。

提示:JavaConfig 是Spring的一個(gè)子項(xiàng)目(詳細(xì)了解可參考:http://docs.spring.io/spring-javaconfig/docs/).

比如我想獲取同一個(gè)類的多個(gè)bean對(duì)象碌秸,就可以在JavaConfig中聲明方法來裝配bean:

@Bean
public Player player(){
    return new CDPlayer();
}

此時(shí)Spring容器就會(huì)生成一個(gè)Player的對(duì)象绍移,其id為player(注意id與方法名是一樣的)。

我們也可以為Player對(duì)象指定Bean id:

@Bean(name="firstPlayer")
public Player player(){
    return new CDPlayer();
}

那么我們?cè)诖a中就可以根據(jù)這個(gè)id名稱來裝配這個(gè) Bean

@Autowired
private Player firstPlayer

不過讥电,要注意的是@Autowired默認(rèn)按類型(byType)裝配登夫。如果我們想使用名稱裝配,可以結(jié)合@Qualifier注解進(jìn)行使用允趟,如下:

@Autowired
@Qualifier("firstPlayer")     
private Player firstPlayer;    

另外恼策,我們還可以使用@Resource(這個(gè)注解屬于J2EE的)

@Resource(name="firstPlayer")   //在字段上的注入,先按照名字裝配
private Player firstPlayer;  

默認(rèn)按照名稱(byName)進(jìn)行裝配潮剪,名稱可以通過name屬性進(jìn)行指定涣楷, 裝配規(guī)則是:

  1. 如果沒有指定name屬性,當(dāng)注解寫在字段上時(shí)抗碰,默認(rèn)取字段名進(jìn)行按照名稱查找狮斗,如果注解寫在setter方法上默認(rèn)取屬性名進(jìn)行裝配。

  2. 當(dāng)找不到與名稱匹配的bean時(shí)才按照類型進(jìn)行裝配弧蝇。但是需要注意的是碳褒,如果name屬性一旦指定,就只會(huì)按照名稱進(jìn)行裝配看疗。

Spring的XML配置方式是使用被Spring命名空間的所支持的一系列的XML標(biāo)簽來實(shí)現(xiàn)的沙峻。Spring有以下主要的命名空間:context、beans两芳、jdbc摔寨、tx、aop怖辆、mvc等是复。

使用XML來配置Bean所能實(shí)現(xiàn)的功能,通過JavaConfig同樣可以很好的實(shí)現(xiàn)竖螃。之前我們都是在xml文件中定義bean的淑廊,比如:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
  
    <bean id="helloBean" class="com.hello.impl.HelloWorldImpl">
  
</beans>

其實(shí)我們可以使用注解來完成這些事情,例如下面的代碼特咆,完成的功能和上面的xml配置的功能是一樣的:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.hello.HelloWorld;
import com.hello.impl.HelloWorldImpl;
  
@Configuration
public class AppConfig {
  
    @Bean(name="helloBean")
    public HelloWorld helloWorld() {
        return new HelloWorldImpl();
    }
  
}

使用@Bean注解季惩,來標(biāo)識(shí)此方法構(gòu)造出一個(gè)由Spring容器管理的bean。@Bean聲明所起到的作用與<bean/> 元素類似坚弱。

Spring對(duì)Java配置的支持是由@Configuration注解和@Bean注解來實(shí)現(xiàn)的蜀备。由@Bean注解的方法將會(huì)實(shí)例化关摇、配置和初始化一個(gè)新對(duì)象荒叶,這個(gè)對(duì)象將由Spring的IoC容器來管理。

2.2.4 導(dǎo)入子配置類

其實(shí)输虱,Spring 中的 XML 配置文件本質(zhì)上說是一種編程元數(shù)據(jù)些楣。在早期Java版本中,應(yīng)用中的元數(shù)據(jù)一般使用屬性文件、XML愁茁。但是用配置文件不夠靈活而且比較繁瑣蚕钦。從Spring 3起,JavaConfig功能已經(jīng)包含在Spring核心模塊鹅很,它允許開發(fā)者將bean定義和在Spring配置XML文件到Java類中嘶居。與此同時(shí)仍然允許使用經(jīng)典的XML方式來定義bean和配置。

一般在一個(gè)大型工程項(xiàng)目中促煮,如果將所有的bean都配置在一個(gè)xml文件中邮屁,那么這個(gè)文件就會(huì)非常的大。所以一般會(huì)將一個(gè)大的xml配置文件分割為好幾份菠齿。這樣方便管理佑吝,最后在總的那個(gè)xml文件中導(dǎo)入。比如:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  
        <import resource="config/customer.xml"/>
        <import resource="config/scheduler.xml"/>
  
</beans>

但是現(xiàn)在我們也可以使用JavaConfig來完成同樣的工作了:

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
  
@Configuration
@Import({ CustomerConfig.class, SchedulerConfig.class })
public class AppConfig {
  
}

@Configuration可以被認(rèn)為是相當(dāng)于XML的< bean / >元素绳匀。

2.2.5 導(dǎo)入XML 配置

在 Spring XML中, 啟動(dòng)注解注入bean芋忿,通過如下標(biāo)簽實(shí)現(xiàn):

<context:annotation-config/>

在 JavaConfig中, 等同于 @AnnotationDrivenConfig注解。
代碼示例:

@Configuration
@AnnotationDrivenConfig
public class Config {
}

使用@ComponentScan注解疾棵,等同于在 Spring XML中的

 <context:component-scan/>

代碼示例:

package com.company.foo;

@Service
public class FooServiceImpl implements FooService {
    private final FooRepository fooRepository;

    @Autowired
    public FooService(FooRepository fooRepository) {
        this.fooRepository = fooRepository;
    }

    // ...
}
                
package com.company.foo;

@Repository
public class JdbcFooRepository implements FooRepository {
    private final DataSource dataSource;

    @Autowired
    public FooRepository(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    // ...
}
                
@Configuration
@ComponentScan("com.company") // search the com.company package for @Component classes
@ImportXml("classpath:com/company/data-access-config.xml") // XML with DataSource bean
public class Config {
}
    

在配置類中使用上述的配置戈钢,我們就可以在代碼里調(diào)用service方法了:

public class Main {
    public static void main(String[] args) {
        JavaConfigApplicationContext ctx = new JavaConfigApplicationContext(Config.class);
        FooService fooService = ctx.getBean(FooService.class);
        fooService.doStuff();
    }
}
      

2.3 SpringBoot的應(yīng)用級(jí)配置文件

SpringBoot應(yīng)用中有個(gè)應(yīng)用級(jí)的配置文件application.properties 。

例如是尔,我們?cè)赼pplication.properties中配置一個(gè)使用 JPA 的數(shù)據(jù)源

# datasource: unicode編碼的支持逆趣,設(shè)定為utf-8
spring.datasource.url=jdbc:mysql://localhost:3306/blog?zeroDateTimeBehavior=convertToNull&characterEncoding=utf8&characterSetResults=utf8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.testWhileIdle=true
spring.datasource.validationQuery=SELECT 1
spring.jpa.database=MYSQL
spring.jpa.show-sql=true
# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto=update
# Naming strategy
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

2.3.1 配置文件所在目錄

Spring Boot 提供的 SpringApplication 類會(huì)搜索并加載 application.properties 文件來獲取配置屬性值。SpringApplication 類會(huì)在下面位置搜索該文件:

1.當(dāng)前目錄的/config子目錄
2.當(dāng)前目錄
3.classpath 中的/config包
4.classpath

我們?cè)陂_發(fā)的時(shí)候嗜历,application.properties經(jīng)常使用它來配置一些可以手動(dòng)修改而且不用編譯的變量宣渗。這樣我們?cè)诖虺蓋ar包或者jar包用于生產(chǎn)環(huán)境時(shí),我們可以直接通過application.properties配置文件來修改環(huán)境變量梨州,而不用再次重新編譯痕囱。

Spring Boot幾乎所有的配置項(xiàng)都可以在這個(gè)文件中配置,如果不配置暴匠,則使用默認(rèn)項(xiàng)鞍恢。Spring Boot會(huì)檢測(cè)配置項(xiàng)的key,啟動(dòng)相應(yīng)的自動(dòng)配置模塊每窖。

提示:這個(gè)application.properties里面到底有哪些key是可配置的呢帮掉?在SpringBoot官網(wǎng)文檔給出了詳盡的配置以及說明。
參考 Appendix A. Common application properties中: http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#common-application-properties

這個(gè)完整的application properties文件窒典,有1000多行蟆炊,屬性key有900多個(gè)。當(dāng)你看到如此龐大的配置瀑志,你一定會(huì)被嚇到涩搓。不過污秆,在實(shí)際項(xiàng)目中,我們?nèi)绻裱璖pring Boot的約定昧甘,通常不需要我們單獨(dú)指定太多配置良拼。這里SpringBoot的實(shí)現(xiàn)方案,充分體現(xiàn)了Spring框架的“約定優(yōu)于配置”理念充边。通過約定俗成的規(guī)范庸推,很多問題的解決講得到大大的簡(jiǎn)化。

雖然是零XML配置浇冰,但是“有些配置的事情”予弧,還是必須要做的。

2.3.2 yml 格式的配置文件

相對(duì)于屬性文件來說湖饱,application.yml 是一個(gè)更好的配置文件格式掖蛤。
當(dāng)有同一前綴大量使用的情況下,使用.yml格式的配置文件會(huì)更加簡(jiǎn)單井厌。例如上面的使用 JPA 的數(shù)據(jù)源的配置蚓庭,我們使用 yml 格式配置如下

# datasource: unicode編碼的支持,設(shè)定為utf-8
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/blog?zeroDateTimeBehavior=convertToNull&characterEncoding=utf8&characterSetResults=utf8
    username: root
    password: root
    testWhileIdle: true
    validationQuery: SELECT 1

spring:
  jpa:
    database: MYSQL
    show-sql: true
    # Hibernate ddl auto (create, create-drop, update)
    hibernate:
      ddl-auto: update
      # Naming strategy
      naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL5Dialect

注意:使用.yml時(shí)仅仆,屬性名的值和冒號(hào)中間必須有空格器赞。它的基本語法規(guī)則如下:

  1. 區(qū)分大小寫
  2. 使用縮進(jìn)表示層級(jí)關(guān)系
  3. 縮進(jìn)時(shí)不允許使用Tab鍵,只允許使用空格墓拜。
  4. 縮進(jìn)的空格數(shù)目不重要港柜,只要相同層級(jí)的元素左側(cè)對(duì)齊即可
  5. # 表示注釋,從這個(gè)字符一直到行尾咳榜,都會(huì)被解析器忽略夏醉。

只要將SnakeYAML 庫(kù)放到classpath下,SpringApplication就會(huì)自動(dòng)支持YAML涌韩,以作為.properties的替換畔柔。當(dāng)然,我們通常不需要這么做臣樱,因?yàn)槲覀円话愣紩?huì)使用Starters靶擦,在spring-boot-starter里已經(jīng)集成了SnakeYAML,所以不需要我們單獨(dú)去添加該依賴雇毫。

2.4 配置服務(wù)端口號(hào)

Spring Boot默認(rèn)已經(jīng)配置了很多環(huán)境變量玄捕,例如,tomcat的默認(rèn)端口是8080棚放,項(xiàng)目的contextpath是“/”等等枚粘。

我們?cè)谏弦徽轮校褂玫氖悄J(rèn)的服務(wù)端口8080席吴。如果我們想自定義端口號(hào)赌结,在SpringBoot中怎么搞?

很簡(jiǎn)單捞蛋,在application.properties中只需要一行配置即可孝冒。

server.port=5678

如果是在application.yml中

server:
  port: 8080

注意:冒號(hào)之后有空格柬姚。

啟動(dòng)應(yīng)用,你將看到:

2017-04-04 23:31:21.673  INFO 90250 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2017-04-04 23:31:21.774  INFO 90250 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 5678 (http)
2017-04-04 23:31:21.780  INFO 90250 --- [           main] com.example.DemoApplication              : Started DemoApplication in 4.712 seconds (JVM running for 5.511)

TomcatEmbeddedServletContainer已經(jīng)在5678端口監(jiān)聽請(qǐng)求了庄涡。

瀏覽器訪問:http://localhost:5678/hello
你會(huì)看到成功輸出:

Hello World! Tue Apr 04 23:32:38 CST 2017

2.5 配置 Profile

一般在一個(gè)項(xiàng)目中量承,總是會(huì)有好多個(gè)環(huán)境。通常的應(yīng)用部署會(huì)包含開發(fā)穴店、測(cè)試和生產(chǎn)等若干個(gè)環(huán)境撕捍。比如:

開發(fā)環(huán)境 -> 測(cè)試環(huán)境 -> 預(yù)發(fā)布環(huán)境 -> 生產(chǎn)環(huán)境

在開發(fā)中, 通常針對(duì)不同的環(huán)境我們都會(huì)有不同的配置。例如日志打印泣洞、數(shù)據(jù)庫(kù)連接等忧风,開發(fā)、測(cè)試球凰、生產(chǎn)等每個(gè)環(huán)境的配置可能都不一樣狮腿。

Spring Boot支持通過不同的profile來配置不同環(huán)境的配置。

---
#開發(fā)環(huán)境配置
spring:
  profiles: dev
server:
  port: 8080
---
#測(cè)試環(huán)境配置
spring:
  profiles: test
server:
  port: 8081
---
#生產(chǎn)環(huán)境配置
spring:
  profiles: prod
server:
  port: 8082

application.yml配置文件中呕诉,我們使用一組(---)來作為分隔符缘厢。

然后,我們通過spring.profiles.active來指定采用哪個(gè) profiles

spring:
  profiles:
    active: dev

這樣我們可以控制本地啟動(dòng)調(diào)用 dev 環(huán)境的配置文件甩挫。

如果是部署到服務(wù)器的話,我們正常打成jar包,發(fā)布是時(shí)候,采用:

--spring.profiles.active=dev (test贴硫、pro) 來控制加載哪個(gè)環(huán)境的配置,完整命令如下:

java -jar xxxxx.jar --spring.profiles.active=test 表示加載測(cè)試環(huán)境test的配置
java -jar xxxxx.jar --spring.profiles.active=prod  表示加載生產(chǎn)環(huán)境prod的配置

2.6 使用 JavaConfig 配置 Profile

Spring 框架本身提供了多種的方式來管理配置屬性文件。Spring 3.1 之前可以使用 PropertyPlaceholderConfigurer伊者。Spring 3.1 引入了新的環(huán)境(Environment)和概要信息(Profile)API英遭,是一種更加靈活的處理不同環(huán)境和配置文件的方式。

Spring Profiles提供了一種隔離應(yīng)用程序配置的方式亦渗,并讓這些配置只在特定的環(huán)境下生效贪绘。任何@Component或@Configuration都能注解@Profile,從而限制加載它的環(huán)境:


@Configuration
@Profile("production")
public class ProductionConfiguration {

    // ...

}

指定的屬性方式常用的有2種:

1.配置在application.properties中:

spring.profiles.active=production

2.或使用命令行開關(guān):

--spring.profiles.active=production

如果應(yīng)用中包含多個(gè) profile央碟,可以為每個(gè) profile 定義各自的屬性文件税灌,按照application-{profile}.properties(.yml)來命名。

2.7 自定義配置項(xiàng)

我們可以將自己自定義的屬性配置在application.properties中(注意不要和Spring Boot的默認(rèn)配置的key重復(fù))亿虽,然后在java類中通過@Value("${屬性名}")注解來加載對(duì)應(yīng)的配置屬性菱涤,例如:application.properties文件中有如下自定義配置項(xiàng):

com.easy.springboot.h5perf.app.name = H5性能測(cè)試平臺(tái)

則在java中有如下應(yīng)用:

@Component
public class TestProperties {
    @Value("${com.easy.springboot.h5perf.app.name }")
    private String appName;
}

Spring Boot使用application.properties默認(rèn)了很多配置。但需要自己添加一些配置的時(shí)候洛勉,我們應(yīng)該怎么做呢粘秆。

例如,下面這段yml格式的配置

environments:
    dev:
        url: http://dev.easy.springboot.com
        name: Easy Spring Boot

會(huì)轉(zhuǎn)化為:

environments.dev.url=http://dev.easy.springboot.com
environments.dev.name=Easy Spring Boot

如果我們自定義了屬性key收毫,在代碼中怎樣使用上面的配置信息呢攻走?利用Spring DataBinder工具集殷勘,Spring Boot通過注解@ConfigurationProperties 和@EnableConfigurationProperties 來完成這件事情。

在代碼中對(duì)應(yīng)的Bean對(duì)象:

@ConfigurationProperties(prefix="environments")
public class EnvironmentsConfig { 
    private String url; 
    private String name;
     
    public String getUrl(){ return this.url; }  
    public void setUrl(String url){ this.url = url; }  
    public String getName(){ return this.name; } 
    public void setName(){ this.name = name; } 

}

有些時(shí)候昔搂,我們還會(huì)配置類似下面這樣的列表的屬性

my:
   servers:
       - dev1.easy.com
       - dev2.easy.com

會(huì)轉(zhuǎn)化為:

my.servers[0]=dev1.easy.com
my.servers[1]=dev2.easy.com

使用@ConfigurationProperties這個(gè)注解來實(shí)現(xiàn)屬性Bean的綁定玲销,需要在Bean里面添加一個(gè)java.util.List(或者Set)類型的屬性,然后寫好setter(setter也可以換成初始化一個(gè)對(duì)象)摘符,getter:

@ConfigurationProperties(prefix="my")
public class ServersConfig {
    private List<String> servers = new ArrayList<String>();//initialize it with a mutable value贤斜, equals a setter
    public List<String> getServers() {
        return this.servers;
    }    

}

YamlPropertySourceLoader類能夠?qū)AML作為PropertySource導(dǎo)出到Spring Environment。所以我們可以使用常用的@Value注解配合占位符語法來訪問yml 中的屬性逛裤。

另外瘩绒,當(dāng)我們使用@ConfigurationProperties注解定義配置的Bean時(shí),需要在SpringBoot Application啟動(dòng)類上標(biāo)注@EnableConfigurationProperties带族。

2.8 配置的優(yōu)先級(jí)

常規(guī)情況下锁荔,我們都知道Spring Boot的配置會(huì)從application.properties中讀取。實(shí)際上蝙砌,從resource目錄下的application.properties文件讀取是Spring Boot配置鏈中的一環(huán)而已阳堕。

Spring Boot提供了一種優(yōu)先級(jí)配置讀取的機(jī)制來幫助我們從這種困境中走出來。

Spring Boot 所提供的配置優(yōu)先級(jí)順序比較復(fù)雜拍霜。按照優(yōu)先級(jí)從高到低的順序嘱丢,具體的列表(從高到低)如下所示。

  • 命令行參數(shù)(優(yōu)先級(jí)最高)祠饺。
  • 通過 System.getProperties() 獲取的 Java 系統(tǒng)參數(shù)越驻。
  • 操作系統(tǒng)環(huán)境變量。
  • 從 java:comp/env 得到的 JNDI 屬性道偷。
  • 通過 RandomValuePropertySource 生成的random.*屬性缀旁。
  • jar包外部的application-{profile}.properties或application.yml(帶spring.profile)配置文件,通過spring.config.location參數(shù)指定
  • jar包內(nèi)部的application-{profile}.properties或application.yml(帶spring.profile)配置文件
  • jar包外部的application.properties或application.yml(不帶spring.profile)配置文件
  • jar包內(nèi)部的application.properties或application.yml(不帶spring.profile)配置文件
  • 應(yīng)用 Java配置類勺鸦,包含@Configuration注解的 Java 類并巍,通過@PropertySource注解聲明的屬性文件。
  • 通過SpringApplication.setDefaultProperties聲明的默認(rèn)屬性换途。

如果Spring Boot在優(yōu)先級(jí)更高的位置找到了配置懊渡,那么它就會(huì)覆蓋優(yōu)先級(jí)低的配置。

Spring Boot 的這個(gè)配置優(yōu)先級(jí)看似復(fù)雜军拟,其實(shí)是很合理的剃执。命令行參數(shù)的優(yōu)先級(jí)之所以被設(shè)置為最高,是因?yàn)榭梢苑奖阄覀冊(cè)跍y(cè)試或生產(chǎn)環(huán)境中快速地修改配置參數(shù)值懈息,而不需要重新打包和部署應(yīng)用肾档。

SpringApplication 類默認(rèn)會(huì)把以“--”開頭的命令行參數(shù)轉(zhuǎn)化成應(yīng)用中可以使用的配置參數(shù),如 “--name=Alex” 會(huì)設(shè)置配置參數(shù) “name” 的值為 “Alex”。

如果不需要這個(gè)功能怒见,可以通過

SpringApplication.setAddCommandLineProperties(false)

禁用解析命令行參數(shù)俗慈。

2.9 本章小結(jié)

Spring Boot 它拋棄了Spring 中繁瑣的xml配置文件的方式,聲明式注解的方法為服務(wù)開發(fā)提供快速簡(jiǎn)潔的配置方式遣耍。在Spring Boot 中闺阱,我們會(huì)發(fā)現(xiàn),我們其實(shí)不用做一些基本的配置也能直接運(yùn)行剛創(chuàng)建好的工程項(xiàng)目配阵,因?yàn)樗鼉?nèi)嵌了很多基本的通用的配置組件而不需要我們自己來做一些重復(fù)的配置工作馏颂。

Spring Boot讓環(huán)境配置變得輕松很多示血。

參考資料:

1.https://www.ibm.com/developerworks/cn/java/j-lo-spring-boot/index.html
2.http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#common-application-properties

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末棋傍,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子难审,更是在濱河造成了極大的恐慌瘫拣,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件告喊,死亡現(xiàn)場(chǎng)離奇詭異麸拄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)黔姜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門拢切,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人秆吵,你說我怎么就攤上這事淮椰。” “怎么了纳寂?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵主穗,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我毙芜,道長(zhǎng)忽媒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任腋粥,我火速辦了婚禮晦雨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘隘冲。我一直安慰自己闹瞧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布对嚼。 她就那樣靜靜地躺著夹抗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪纵竖。 梳的紋絲不亂的頭發(fā)上漠烧,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天杏愤,我揣著相機(jī)與錄音,去河邊找鬼已脓。 笑死珊楼,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的度液。 我是一名探鬼主播厕宗,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼堕担!你這毒婦竟也來了已慢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤霹购,失蹤者是張志新(化名)和其女友劉穎佑惠,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體齐疙,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡膜楷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贞奋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赌厅。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖轿塔,靈堂內(nèi)的尸體忽然破棺而出特愿,到底是詐尸還是另有隱情,我是刑警寧澤催训,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布洽议,位于F島的核電站,受9級(jí)特大地震影響漫拭,放射性物質(zhì)發(fā)生泄漏亚兄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一采驻、第九天 我趴在偏房一處隱蔽的房頂上張望审胚。 院中可真熱鬧,春花似錦礼旅、人聲如沸膳叨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)菲嘴。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間龄坪,已是汗流浹背昭雌。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留健田,地道東北人烛卧。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像妓局,于是被迫代替她去往敵國(guó)和親总放。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容