無論何種系統,都需要有一個組態設定的位置,Spring很貼心的提供預設*.properies及*.yaml兩種預設的組態參數檔,此時Spring 提供了兩種註解模式提供開發者坐接取組態參數值,分別為@ConfigurationProperties及@Value兩種註解模式,此前者可透過字首進行鎖定,後者可直接透過整段參數關鍵詞進行注入其值,Spring透過此兩項註解可取代各位開發者早期既有的Properties()或System.setProperty(key,value)兩項參數配置元件,以下將透過範例給各位開發者做詳細的敘述。
本章節提供兩種註解範例實作,整合前兩天的開發成果在延續下去,@ConfigurationProperties為一種將配置的文字訊息,自動封裝成一個類別實體,@Value則為自動的轉為某種特定屬性封裝類別,如:String.class,Integer.class or Long.class, etc),以下我們就直接透過程式碼範例進行講解。
範例一、參數檔[application.properties]參數如下
sea.food.api.china=china
sea.food.api.taiwan=taiwan
sea.food.company.name = Weisting SEA Food Retailer
sea.food.company.ceo = Darius Weisting
sea.food.company.capital= 6000000
sea.food.company.address =No. 88, Ln. 888, Sec. 5, Minzu Rd., Yangmei Dist., Taoyuan City 326002 , Taiwan (R.O.C.)
sea.food.company.uniformNumber = 86633399
sea.food.company.createdDate= 2021/10/05
sea.food.company.version = v1.0.1
範例一、將參數透過prefix字首為sea.food.company,封裝成類別實體為CompanyInformationConfig,而InformationController中置放@Value註解將配置參數檔中的sea.food.company.version的值注入version欄位,透過API即可取得相關資訊。
@Configuration
@ConfigurationProperties(
prefix = "sea.food.company",
ignoreInvalidFields=true
)
public class CompanyInformationConfig {
String name;
String ceo;
Integer capital;
String address;
String uniformNumber;
@DateTimeFormat(pattern = "YYYY/mm/dd")
Date createdDate;
.....
.....
.....
}
@RestController
public class InformationController extends ControllerBase {
@Value("${sea.food.company.version}")
String version;
@Autowired
private CompanyInformationConfig config;
@GetMapping(
value="/about"
)
ResponseEntity<Map> seaFoodVersion() {
Map<String,Object> informationMap = new LinkedHashMap<String, Object>();
informationMap.put("version",version);
informationMap.put("name",config.getName());
informationMap.put("ceo",config.getCeo());
informationMap.put("capital",config.getCapital());
informationMap.put("address",config.getAddress());
informationMap.put("uniformNumber",config.getUniformNumber());
informationMap.put("createdDate",config.getCreatedDate());
return new ResponseEntity<>(informationMap, HttpStatus.OK);
}
}
範例一、測試結果,可完整的取得其參數檔資訊
範例二、透過參數檔(${sea.food.api.taiwan})進行注入Sea Food Restful API 路徑位置
@RestController
public class ProductController extends ControllerBase{
@Resource(name="seaFoodRetailService",type = SeaFoodRetailerService.class)
SeaFoodRetailerService seaFoodRetailService;
@GetMapping(
value="/${sea.food.api.taiwan}/list"
)
List<SeaFood> listSeaFood() {
return seaFoodRetailService.listSeaFoodProducts();
}
@GetMapping(
value="/${sea.food.api.taiwan}/find/{id}",
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE
)
ResponseEntity<SeaFood> findSeaFoodById(@PathVariable("id") String id) throws ResourceNotFoundException {
Optional<SeaFood> seaFood = seaFoodRetailService.findProductById(id);
if (!seaFood.isPresent())
throw new ResourceNotFoundException();
return new ResponseEntity<SeaFood>(
seaFood.get()
, HttpStatus.OK
);
}
.....
.....
}
範例二、測試結果可成功取得數據
根據以上小編所範例提供的範例,我們可以看出所有的註解模式的value值都是可透過參數檔進行注入的囉!
透過下圖一,入口點為AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization,並透過ConfigurationPropertiesBindingPostProcessorbind(ConfigurationPropertiesBean bean)進行串接與獲取該組態配置檔元件。
圖一 ConfigurationProperties Bean實體配置流程
透過下圖二,入口點為BeanConfigurerSupport.configureBean方法,並透過AbstractAutowireCapableBeanFactory.populateBean進行觸發PropertyValues元件中postProcessPropertyValues的方法以獲取相對應的參數值。
圖二 Value 參數值獲取流程
SpringBoot源码解析之ConfigurationProperties原理