一.應用場景
使用Spring Boot開發,經常需要自定義配置屬性,例如系統全局屬性,或者外部調用的常量屬性等,那麼這些配置屬性應該放在哪裏比較合適?怎麼讀取並在代碼中使用呢?
二. 屬性配置
在Spring Boot中,有兩種常用的配置文件格式:properties和yml。下面總結了幾種常見的屬性配置和讀取方式:
- 直接使用JDK自帶的 java.util.ResourceBundle
JDK本身提供了 java.util.ResourceBundle 工具類可以用於讀取properties配置文件。
package com.hong.util;
import java.io.UnsupportedEncodingException;
import java.util.Locale;
import java.util.ResourceBundle;
/**
* @author wanghong
* @date 2019/06/14 22:48
* properties屬性文件讀取器
**/
public class PropertiesReader {
private ResourceBundle resourceBundle;
public PropertiesReader(String propertiesHolder) {
this.resourceBundle = ResourceBundle.getBundle(propertiesHolder, Locale.getDefault());
}
public String getLabel(String key) {
String label;
try {
label = new String(resourceBundle.getString(key).getBytes("ISO-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return label;
}
}
package com.hong.config;
import com.hong.util.PropertiesReader;
/**
* @author wanghong
* @date 2019/06/14 22:49
* App端屬性配置常量類,綁定到類路徑下app_config.properties資源
**/
public class AppConfig {
private static PropertiesReader getPropertiesVal = new PropertiesReader("app_config");
public static final String MY_PROP = getPropertiesVal.getLabel("myProp");
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class ConfigTest {
@Test
public void testConfig(){
System.out.println(AppConfig.MY_PROP); //123456
}
}
- @ConfigurationProperties
package com.hong.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author wanghong
* @date 2019/06/14 23:08
**/
@Data
@Component
@ConfigurationProperties(prefix = "app")
public class AppConfig2 {
private String version;
}
package com.hong.controller;
import com.hong.config.AppConfig2;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* @author wanghong
* @date 2019/06/14 23:14
**/
@Api(value = "測試控制器")
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private AppConfig2 appConfig2;
@ApiOperation(value = "屬性讀取測試")
@RequestMapping(value = "testConfig",method = RequestMethod.GET)
public String testConfig() {
String version = appConfig2.getVersion();
return version;
}
}
如果現在 application-dev.yml中也定義了該屬性:
且 spring.profiles.active=dev,那麼讀取到的 version = 1.0.0
- @PropertySource
現在再來看另一種場景: 假如我在 app_config.properties中也定義了該屬性:
如何讓 AppConfig2中讀取的值是該文件中配置的值呢?這時就要手動指定屬性源了。
package com.hong.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
* @author wanghong
* @date 2019/06/14 23:08
**/
@Data
@Component
@PropertySource(value = { "classpath:app_config.properties" }, encoding = "UTF-8")
@ConfigurationProperties(prefix = "app")
public class AppConfig2 {
private String version;
}
但這裏有一個坑,我本機Spring Boot使用的版本是2.0.4.RELEASE,如果在Spring Boot默認的全局屬性文件application.yml或application.properties或application-{profile}.yml或application-{profile}.properties中存在與自定義屬性配置文件中同名的屬性,那麼即使加了@PropertySource(value = { “classpath:app_config.properties” }, encoding = “UTF-8”)也不管用,最終讀取到的還是默認全局屬性文件中的值,當然一般出現這種情況,就是命名衝突的問題了,注意下就行了。
還有一種場景即使同一個屬性值在不同的profile環境中值是不同的,如app_config.properties在dev環境下是1.1.0,在prod下是1.2.0,這時我們可以在resources目錄下分別創建dev和prod兩個文件夾,放置app_config.properties,然後設置下 @PropertySource的文件路徑。
當然這種情況就是需要做到環境隔離了,如果是微服務的話,可以結合Spring Cloud使用分佈式配置中心服務,將不同環境的配置放到git中方便修改和統一管理。
- @Value
package com.hong.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
* @author wanghong
* @date 2019/06/15 0:36
**/
@Data
@Component
@PropertySource("classpath:app_config.properties")
public class AppConfig3 {
@Value("${app.version}")
private String version;
}
- @ConfigurationProperties與@Value的區別