詳解SpringBoot注入數(shù)據(jù)的方式
關(guān)于注入數(shù)據(jù)說(shuō)明

1.不通過(guò)配置文件注入數(shù)據(jù)
通過(guò)@Value將外部的值動(dòng)態(tài)注入到Bean中,使用的情況有:
- 注入普通字符串
- 注入操作系統(tǒng)屬性
- 注入表達(dá)式結(jié)果
- 注入其他Bean屬性:注入Student對(duì)象的屬性name
- 注入文件資源
- 注入U(xiǎn)RL資源
輔助代碼
package com.hannpang.model;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component(value = "st")//對(duì)student進(jìn)行實(shí)例化操作
public class Student {
@Value("悟空")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
測(cè)試@Value的代碼
package com.hannpang.model;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
@Component
public class SimpleObject {
@Value("注入普通字符串")
private String normal;
//關(guān)于屬性的KEY可以查看System類說(shuō)明
@Value("#{systemProperties['java.version']}")//-->使用了SpEL表達(dá)式
private String systemPropertiesName; // 注入操作系統(tǒng)屬性
@Value("#{T(java.lang.Math).random()*80}")//獲取隨機(jī)數(shù)
private double randomNumber; //注入表達(dá)式結(jié)果
@Value("#{1+2}")
private double sum; //注入表達(dá)式結(jié)果 1+2的求和
@Value("classpath:os.yaml")
private Resource resourceFile; // 注入文件資源
@Value("http://www.baidu.com")
private Resource testUrl; // 注入U(xiǎn)RL資源
@Value("#{st.name}")
private String studentName;
//省略getter和setter方法
@Override
public String toString() {
return "SimpleObject{" +
"normal='" + normal + '\'' +
", systemPropertiesName='" + systemPropertiesName + '\'' +
", randomNumber=" + randomNumber +
", sum=" + sum +
", resourceFile=" + resourceFile +
", testUrl=" + testUrl +
", studentName='" + studentName + '\'' +
'}';
}
}
Spring的測(cè)試代碼
package com.hannpang;
import com.hannpang.model.SimpleObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class Demo04BootApplicationTests {
@Autowired
private SimpleObject so;
@Test
public void contextLoads() {
System.out.println(so);
}
}
運(yùn)行結(jié)果為:SimpleObject{normal='注入普通字符串', systemPropertiesName='1.8.0_172', randomNumber=56.631954541947266, sum=3.0, resourceFile=class path resource [os.yaml], testUrl=URL [http://www.baidu.com], studentName='悟空'}
2.通過(guò)配置文件注入數(shù)據(jù)
通過(guò)@Value將外部配置文件的值動(dòng)態(tài)注入到Bean中。配置文件主要有兩類:
- application.properties、application.yaml application.properties在spring boot啟動(dòng)時(shí)默認(rèn)加載此文件
- 自定義屬性文件。自定義屬性文件通過(guò)@PropertySource加載。@PropertySource可以同時(shí)加載多個(gè)文件,也可以加載單個(gè)文件。如果相同第一個(gè)屬性文件和第二屬性文件存在相同key,則最后一個(gè)屬性文件里的key啟作用。加載文件的路徑也可以配置變量,如下文的${anotherfile.configinject},此值定義在第一個(gè)屬性文件config.properties
在application.properties中加入如下測(cè)試代碼
app.name=一步教育
在resources下面新建第一個(gè)屬性文件config.properties內(nèi)容如下
book.name=西游記 anotherfile.configinject=system
在resources下面新建第二個(gè)屬性文件config_system.properties內(nèi)容如下
我的目的是想system的值使用第一個(gè)屬性文件中定義的值
book.name.author=吳承恩
下面通過(guò)@Value(“${app.name}”)語(yǔ)法將屬性文件的值注入bean屬性值,詳細(xì)代碼見(jiàn):
package com.hannpang.test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
@Component
@PropertySource(value = {"classpath:config.properties","classpath:config_${anotherfile.configinject}.properties"})
public class LoadPropsTest {
@Value("${app.name}")
private String appName; // 這里的值來(lái)自application.properties,spring boot啟動(dòng)時(shí)默認(rèn)加載此文件
@Value("${book.name}")
private String bookName; // 注入第一個(gè)配置外部文件屬性
@Value("${book.name.author}")
private String author; // 注入第二個(gè)配置外部文件屬性
@Autowired
private Environment env; // 注入環(huán)境變量對(duì)象,存儲(chǔ)注入的屬性值
//省略getter和setter方法
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("bookName=").append(bookName).append("\r\n")
.append("author=").append(author).append("\r\n")
.append("appName=").append(appName).append("\r\n")
.append("env=").append(env).append("\r\n")
// 從eniroment中獲取屬性值
.append("env=").append(env.getProperty("book.name.author")).append("\r\n");
return sb.toString();
}
}
測(cè)試代碼
package com.hannpang;
import com.hannpang.model.SimpleObject;
import com.hannpang.test.LoadPropsTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class Demo04BootApplicationTests {
@Autowired
private LoadPropsTest lpt;
@Test
public void loadPropertiesTest() {
System.out.println(lpt);
}
}
運(yùn)行結(jié)果為:
bookName=西游記
author=吳承恩
appName=一步教育
env=StandardEnvironment {activeProfiles=[], defaultProfiles=[default], propertySources=[ConfigurationPropertySourcesPropertySource {name='configurationProperties'}, MapPropertySource {name='Inlined Test Properties'}, MapPropertySource {name='systemProperties'}, OriginAwareSystemEnvironmentPropertySource {name='systemEnvironment'}, RandomValuePropertySource {name='random'}, OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.properties]'}, ResourcePropertySource {name='class path resource [config_system.properties]'}, ResourcePropertySource {name='class path resource [config.properties]'}]}
env=吳承恩
3. #{...}和${...}的區(qū)別演示
A .${…}的用法
{}里面的內(nèi)容必須符合SpEL表達(dá)式,通過(guò)@Value(“${app.name}”)可以獲取屬性文件中對(duì)應(yīng)的值,但是如果屬性文件中沒(méi)有這個(gè)屬性,則會(huì)報(bào)錯(cuò)。可以通過(guò)賦予默認(rèn)值解決這個(gè)問(wèn)題,如@Value("${app.name:胖先森}")
部分代碼
// 如果屬性文件沒(méi)有app.name,則會(huì)報(bào)錯(cuò)
// @Value("${app.name}")
// private String name;
// 使用app.name設(shè)置值,如果不存在則使用默認(rèn)值
@Value("${app.name:胖先森}")
private String name;
B.#{...}的用法
部分代碼直接演示
// SpEL:調(diào)用字符串Hello World的concat方法
@Value("#{'Hello World'.concat('!')}")
private String helloWorld;
// SpEL: 調(diào)用字符串的getBytes方法,然后調(diào)用length屬性
@Value("#{'Hello World'.bytes.length}")
private String helloWorldbytes;
C.#{...}和${...}混合使用
${...}和#{...}可以混合使用,如下文代碼執(zhí)行順序:通過(guò)${server.name}從屬性文件中獲取值并進(jìn)行替換,然后就變成了 執(zhí)行SpEL表達(dá)式{‘server1,server2,server3'.split(‘,')}。
// SpEL: 傳入一個(gè)字符串,根據(jù)","切分后插入列表中, #{}和${}配置使用(注意單引號(hào),注意不能反過(guò)來(lái)${}在外面,#{}在里面)
@Value("#{'${server.name}'.split(',')}")
private List<String> servers;
在上文中在#{}外面,${}在里面可以執(zhí)行成功,那么反過(guò)來(lái)是否可以呢${}在外面,#{}在里面,如代碼
// SpEL: 注意不能反過(guò)來(lái)${}在外面,#{}在里面,這個(gè)會(huì)執(zhí)行失敗
@Value("${#{'HelloWorld'.concat('_')}}")
private List<String> servers2;
答案是不能。
因?yàn)閟pring執(zhí)行${}是時(shí)機(jī)要早于#{}。
在本例中,Spring會(huì)嘗試從屬性中查找#{‘HelloWorld'.concat(‘_')},那么肯定找到,由上文已知如果找不到,然后報(bào)錯(cuò)。所以${}在外面,#{}在里面是非法操作
D.用法總結(jié)
- #{…} 用于執(zhí)行SpEl表達(dá)式,并將內(nèi)容賦值給屬性
- ${…} 主要用于加載外部屬性文件中的值
- #{…} 和${…} 可以混合使用,但是必須#{}外面,${}在里面
4.@Value獲取值和@ConfigurationProperties獲取值比較
| @ConfigurationProperties | @Value | |
|---|---|---|
| 功能 | 批量注入配置文件中的屬性 | 一個(gè)個(gè)指定 |
| 松散綁定(松散語(yǔ)法) | 支持 | 不支持 |
| SpEL | 不支持 | 支持 |
| JSR303數(shù)據(jù)校驗(yàn) | 支持 | 不支持 |
| 復(fù)雜類型封裝 | 支持 | 不支持 |
配置文件yml還是properties他們都能獲取到值;
- 如果說(shuō),我們只是在某個(gè)業(yè)務(wù)邏輯中需要獲取一下配置文件中的某項(xiàng)值,使用@Value;
- 如果說(shuō),我們專門編寫了一個(gè)javaBean來(lái)和配置文件進(jìn)行映射,我們就直接使用@ConfigurationProperties;
關(guān)于數(shù)據(jù)校驗(yàn)的部分代碼
@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {
//lastName必須是郵箱格式
@Email
private String lastName;
5. @ImportResource引入配置文件
不推薦的使用方式
Spring Boot里面沒(méi)有Spring的配置文件,我們自己編寫的配置文件,也不能自動(dòng)識(shí)別;
想讓Spring的配置文件生效,加載進(jìn)來(lái);@ImportResource標(biāo)注在一個(gè)配置類上
@ImportResource(locations = {"classpath:beans.xml"})
導(dǎo)入Spring的配置文件讓其生效
編寫配置文件信息
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
<bean id="helloService" class="com.hanpang.springboot.service.HelloService"></bean>
</beans>
大概了解就好,我們基本上不使用這種方式
6.@Configuration注解
SpringBoot推薦給容器中添加組件的方式;推薦使用全注解的方式
1、配置類@Configuration作用于類上,相當(dāng)于一個(gè)xml配置文件
2、使用@Bean給容器中添加組件,作用于方法上
/**
* @Configuration:指明當(dāng)前類是一個(gè)配置類;就是來(lái)替代之前的Spring配置文件
*
* 在配置文件中用<bean><bean/>標(biāo)簽添加組件
* <bean id="helloService" class="com.hanpang.springboot.service.HelloService"></bean>
*/
@Configuration
public class MyAppConfig {
//將方法的返回值添加到容器中;容器中這個(gè)組件默認(rèn)的id就是方法名
@Bean
public HelloService helloService02(){
System.out.println("配置類@Bean給容器中添加組件了...");
return new HelloService();
}
}
使用Bean注入太麻煩,我們更加喜歡使用掃描的方式
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.wx.dao.IUserDao;
import com.wx.dao.UserDaoImpl;
//通過(guò)該注解來(lái)表明該類是一個(gè)Spring的配置,相當(dāng)于一個(gè)傳統(tǒng)的ApplicationContext.xml
@Configuration
//相當(dāng)于配置文件里面的<context:component-scan/>標(biāo)簽,掃描這些包下面的類的注解
@ComponentScan(basePackages="com.hanpang.dao,com.hanpang.service")
public class SpringConfig {
// 通過(guò)該注解來(lái)表明是一個(gè)Bean對(duì)象,相當(dāng)于xml中的<bean>
//bean的id值默認(rèn)是方法名userDao
/*
@Bean
public HelloService helloService02(){
System.out.println("配置類@Bean給容器中添加組件了...");
return new HelloService();
}
*/
}
附錄
隨機(jī)數(shù)
${random.value}、${random.int}、${random.long}
${random.int(10)}、${random.int[1024,65536]}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 解決SpringBoot2多線程無(wú)法注入的問(wèn)題
- Springboot實(shí)現(xiàn)多線程注入bean的工具類操作
- Springboot實(shí)現(xiàn)根據(jù)條件切換注入不同實(shí)現(xiàn)類的示例代碼
- java SpringBoot自定義注解,及自定義解析器實(shí)現(xiàn)對(duì)象自動(dòng)注入操作
- 基于SpringBoot構(gòu)造器注入循環(huán)依賴及解決方式
- 使用Springboot注入帶參數(shù)的構(gòu)造函數(shù)實(shí)例
- 在springboot中使用注解將值注入?yún)?shù)的操作
- Springboot測(cè)試類沒(méi)有bean注入問(wèn)題解析
- SpringBoot注入配置文件的3種方法詳解
- 詳解SpringBoot 多線程處理任務(wù) 無(wú)法@Autowired注入bean問(wèn)題解決
- SpringBoot集成shiro,MyRealm中無(wú)法@Autowired注入Service的問(wèn)題
- 解決SpringBoot項(xiàng)目使用多線程處理任務(wù)時(shí)無(wú)法通過(guò)@Autowired注入bean問(wèn)題
- 解決Springboot @Autowired 無(wú)法注入問(wèn)題
- 詳解SpringBoot 解決攔截器注入Service為空問(wèn)題
- 關(guān)于SpringBoot獲取IOC容器中注入的Bean(推薦)
- SpringBoot屬性注入的兩種方法
相關(guān)文章
Java實(shí)現(xiàn)分頁(yè)的幾種方法詳細(xì)解析
這篇文章主要介紹了Java實(shí)現(xiàn)分頁(yè)的幾種方法詳細(xì)解析,在Java中想實(shí)現(xiàn)分頁(yè)功能有幾種常用的方法,今天我們就來(lái)詳細(xì)解析一下,文中提供了解決思路和部分實(shí)現(xiàn)代碼,需要的朋友可以參考下2023-11-11
Nacos動(dòng)態(tài)配置管理機(jī)制方式
這篇文章主要介紹了Nacos動(dòng)態(tài)配置管理機(jī)制方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
SpringBoot中的@EnableConfigurationProperties注解詳細(xì)解析
這篇文章主要介紹了SpringBoot中的@EnableConfigurationProperties注解詳細(xì)解析,如果一個(gè)配置類只配置@ConfigurationProperties注解,而沒(méi)有使用@Component或者實(shí)現(xiàn)了@Component的其他注解,那么在IOC容器中是獲取不到properties 配置文件轉(zhuǎn)化的bean,需要的朋友可以參考下2024-01-01
JAVA構(gòu)造函數(shù)不能使用void關(guān)鍵字問(wèn)題
這篇文章主要介紹了JAVA構(gòu)造函數(shù)不能使用void關(guān)鍵字問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
springboot jpa分庫(kù)分表項(xiàng)目實(shí)現(xiàn)過(guò)程詳解
這篇文章主要介紹了springboot jpa分庫(kù)分表項(xiàng)目實(shí)現(xiàn)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01

