本篇會(huì)給大家舉出各種
Spring
屬性依賴注入的例子,方便大家理解。
1. setter屬性注入
1.1 使用XML進(jìn)行setter方法注入
我們?cè)谇懊娴奈恼轮幸呀?jīng)使用過(guò)XML
進(jìn)行setter
方法的屬性注入了,下面讓我們?cè)賮?lái)回顧一下:
<bean id="userSetter" class="com.example.demo.bean.User">
<property name="username" value="example-username-setter"/>
<property name="age" value="25"/>
</bean>
1.2 使用@Bean注解進(jìn)行setter方法注入
我們?cè)谇懊娴奈恼轮幸矊W(xué)習(xí)過(guò)如何在bean
創(chuàng)建時(shí)通過(guò)編程方式設(shè)置屬性:
@Bean
public User user() {
User user = new User();
user.setUsername("example-username-anno-setter");
user.setAge(25);
return user;
}
1.3 setter方法注入完整代碼示例
- 使用XML進(jìn)行setter方法注入
首先,我們需要?jiǎng)?chuàng)建一個(gè)User
類,并在其中包含username
和age
兩個(gè)屬性,以及相應(yīng)的getter
、setter
方法和構(gòu)造器。
public class User {
private String username;
private Integer age;
public User() {}
// 為了節(jié)省篇幅,getter和setter方法省略......
@Override
public String toString() {
return "User{username='" + username + "', age=" + age + "}";
}
}
對(duì)于XML
方式的setter
注入和構(gòu)造器注入,我們需要?jiǎng)?chuàng)建一個(gè)配置文件,比如叫applicationContext.xml
。
<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">
<!-- setter方法注入 -->
<bean id="userSetter" class="com.example.demo.bean.User">
<property name="username" value="example-username-setter"/>
<property name="age" value="25"/>
</bean>
</beans>
然后,我們需要?jiǎng)?chuàng)建一個(gè)DemoApplication
類,使用ApplicationContext
來(lái)加載配置文件并獲取Bean
:
import com.example.demo.bean.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User userSetter = (User) context.getBean("userSetter");
System.out.println(userSetter);
}
}
運(yùn)行結(jié)果如下:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-479235.html
- 使用@Bean注解進(jìn)行setter方法注入
我們需要?jiǎng)?chuàng)建一個(gè)配置類,例如叫AppConfig.java
:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public User userSetter() {
User user = new User();
user.setUsername("example-username-anno-setter");
user.setAge(25);
return user;
}
}
使用@Bean
注解來(lái)定義Bean
。每個(gè)@Bean
方法對(duì)應(yīng)于XML
配置中的一個(gè)<bean>
元素。這個(gè)方法的名稱就是Bean
的id
,方法的返回值就是Bean
的類型
然后修改主程序,這里使用AnnotationConfigApplicationContext
來(lái)創(chuàng)建Spring
的應(yīng)用上下文,并加載配置類。Spring
會(huì)自動(dòng)從配置類中獲取所有的Bean
定義,并創(chuàng)建相應(yīng)的Bean
實(shí)例。
package com.example.demo;
import com.example.demo.bean.User;
import com.example.demo.configuration.AppConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
User userSetter = (User) context.getBean("userSetter");
System.out.println(userSetter);
}
}
運(yùn)行結(jié)果如下
??注意:XML
配置方式已經(jīng)相對(duì)陳舊,而且在Spring Boot
項(xiàng)目中,主流的做法是使用注解和Java
配置方式。對(duì)于setter
注入,有時(shí)會(huì)引發(fā)循環(huán)依賴的問(wèn)題。在Spring
中,可以使用構(gòu)造器注入來(lái)避免這種情況,這里了解即可。
2. 構(gòu)造器注入
??setter
注入是一種在對(duì)象被實(shí)例化之后(通過(guò)調(diào)用無(wú)參構(gòu)造器創(chuàng)建實(shí)例)再通過(guò)setter
方法注入依賴的方式。構(gòu)造器注入則是在創(chuàng)建對(duì)象實(shí)例的時(shí)候就通過(guò)構(gòu)造器參數(shù)來(lái)注入依賴。
為了演示構(gòu)造器注入,我們需要給User
添加一個(gè)全參數(shù)構(gòu)造器:
public User(String username, Integer age) {
this.username = username;
this.age = age;
}
添加這個(gè)構(gòu)造器后,Java
不再提供默認(rèn)的無(wú)參構(gòu)造器,這會(huì)導(dǎo)致我們之前的<bean>
標(biāo)簽創(chuàng)建時(shí)失敗,因?yàn)樗也坏侥J(rèn)的構(gòu)造器。
2.1 使用XML進(jìn)行構(gòu)造器注入
我們可以在<bean>
標(biāo)簽內(nèi)部聲明一個(gè)子標(biāo)簽:constructor-arg
。它用于指定構(gòu)造器的參數(shù),來(lái)進(jìn)行屬性注入。constructor-arg
標(biāo)簽的編寫規(guī)則如下:
<bean id="userConstructor" class="com.example.demo.bean.User">
<constructor-arg index="0" value="example-username-constructor"/>
<constructor-arg index="1" value="25"/>
</bean>
??index
屬性表示構(gòu)造函數(shù)參數(shù)的位置,它的值是一個(gè)非負(fù)整數(shù),其中0
表示第一個(gè)參數(shù),1
表示第二個(gè)參數(shù),以此類推。雖然value
屬性的值總是一個(gè)字符串,但是Spring
會(huì)嘗試將它轉(zhuǎn)換為構(gòu)造函數(shù)參數(shù)所需的類型。例如構(gòu)造函數(shù)的第二個(gè)參數(shù)是int
類型,那么Spring
會(huì)嘗試將字符串"25"
轉(zhuǎn)換為整數(shù)25
。
??使用index
屬性來(lái)指定構(gòu)造函數(shù)參數(shù)的位置在大多數(shù)情況下是可以的,但是如果構(gòu)造函數(shù)的參數(shù)數(shù)量或者順序發(fā)生了改變,就可能會(huì)出錯(cuò)。另外一種更為可靠的方式是使用name
屬性來(lái)指定參數(shù)的名稱,如:
<bean id="userConstructor" class="com.example.demo.bean.User">
<constructor-arg name="username" value="example-username-constructor"/>
<constructor-arg name="age" value="25"/>
</bean>
這樣無(wú)論參數(shù)的順序如何,只要參數(shù)名稱不變,就不會(huì)出錯(cuò)。
2.2 使用@Bean注解進(jìn)行構(gòu)造器屬性注入
在注解驅(qū)動(dòng)的bean
注冊(cè)中,我們也可以直接使用編程方式賦值:
@Bean
public User user() {
return new User("example-username-anno-constructor", 25);
}
2.3 構(gòu)造器注入的完整代碼示例
- 使用XML進(jìn)行構(gòu)造器注入
首先,我們需要?jiǎng)?chuàng)建一個(gè)User
類,并在其中包含username
和age
兩個(gè)屬性,以及相應(yīng)的getter
、setter
方法和構(gòu)造器。
public class User {
private String username;
private Integer age;
public User() {}
public User(String username, Integer age) {
this.username = username;
this.age = age;
}
// 為了節(jié)省篇幅,getter和setter方法省略......
@Override
public String toString() {
return "User{username='" + username + "', age=" + age + "}";
}
}
對(duì)于XML
方式的構(gòu)造器注入,我們需要?jiǎng)?chuàng)建一個(gè)配置文件,比如叫applicationContext.xml
,這里保留setter
注入方便大家對(duì)比
<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">
<!-- setter方法注入 -->
<!-- setter方法注入 -->
<!-- <bean id="userSetter" class="com.example.demo.bean.User">-->
<!-- <property name="username" value="example-username-setter"/>-->
<!-- <property name="age" value="25"/>-->
<!-- </bean>-->
<!-- 構(gòu)造器注入 -->
<bean id="userConstructor" class="com.example.demo.bean.User">
<constructor-arg name="username" value="example-username-constructor"/>
<constructor-arg name="age" value="25"/>
</bean>
</beans>
然后,我們需要?jiǎng)?chuàng)建一個(gè)DemoApplication
類,使用ApplicationContext
來(lái)加載配置文件并獲取Bean
:
package com.example.demo;
import com.example.demo.bean.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// User userSetter = (User) context.getBean("userSetter");
// System.out.println(userSetter);
User userConstructor = (User) context.getBean("userConstructor");
System.out.println(userConstructor);
}
}
運(yùn)行結(jié)果如下:
- 使用@Bean注解進(jìn)行構(gòu)造器屬性注入
我們需要?jiǎng)?chuàng)建一個(gè)配置類,例如叫AppConfig.java
:
import com.example.demo.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
// @Bean
// public User userSetter() {
// User user = new User();
// user.setUsername("example-username-anno-setter");
// user.setAge(25);
// return user;
// }
@Bean
public User userConstructor() {
return new User("example-username-anno-constructor", 25);
}
}
同樣,我們需要?jiǎng)?chuàng)建一個(gè)DemoApplication
類,使用AnnotationConfigApplicationContext
來(lái)加載配置類并獲取Bean
:
import com.example.demo.bean.User;
import com.example.demo.configuration.AppConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// User userSetter = (User) context.getBean("userSetter");
// System.out.println(userSetter);
User userConstructor = (User) context.getBean("userConstructor");
System.out.println(userConstructor);
}
}
運(yùn)行結(jié)果:
注意:如果在類中同時(shí)使用構(gòu)造器注入和setter
注入,需要注意它們注入的順序:先進(jìn)行構(gòu)造器注入,然后是setter
注入。
3. 注解式屬性注入
??上面我們已經(jīng)說(shuō)過(guò)注解式的setter
和構(gòu)造器注入。我們又是如何處理那些通過(guò)@Component
掃描而注冊(cè)的bean
的屬性的呢?我們來(lái)仔細(xì)說(shuō)說(shuō)這個(gè)問(wèn)題,同時(shí)展示如何在xml
中進(jìn)行相同的操作。
3.1 @Value注解式屬性注入的應(yīng)用
??首先,讓我們從最簡(jiǎn)單的屬性注入方法:@Value
開始。創(chuàng)建一個(gè)新的White
類,并聲明一些字段,但是這次我們不會(huì)設(shè)置setter
方法:
@Component
public class White {
@Value("white-value-annotation")
private String title;
@Value("1")
private Integer rank;
@Override
public String toString() {
return "White{" + "title='" + title + '\'' + ", rank=" + rank + '}';
}
}
要實(shí)現(xiàn)注解式屬性注入,我們可以直接在需要注入的字段上添加@Value
注解:
@Value("white-value-annotation")
private String title;
@Value("1")
private Integer rank;
要注意的是,如果使用 @Value
注解來(lái)注入一個(gè)不存在的屬性,那么應(yīng)用程序會(huì)在啟動(dòng)時(shí)拋出異常。
然后,我們將通過(guò)組件掃描方式將這個(gè)White
類掃描到IOC
容器中,并將其取出并打?。?/p>
public class DemoApplication {
public static void main(String[] args) throws Exception {
ApplicationContext ctx = new AnnotationConfigApplicationContext(White.class);
White white = ctx.getBean(White.class);
System.out.println("Injected value : " + white);
}
}
運(yùn)行main
方法會(huì)看到White
的字段已經(jīng)成功注入:
Injected value : White{title='white-value-annotation', rank=1}
3.2 引入外部配置文件@PropertySource
??如果我們需要在Spring
中使用properties
文件,我們應(yīng)該怎么辦呢?Spring
考慮到了這一點(diǎn),并擴(kuò)展了一個(gè)用于導(dǎo)入外部配置文件的注解:@PropertySource
。
- 創(chuàng)建Bean和配置文件
創(chuàng)建一個(gè)新的Blue
類,其結(jié)構(gòu)與White
類完全相同。然后在項(xiàng)目的resources
目錄下創(chuàng)建一個(gè)新的blue.properties
文件,用于存儲(chǔ)Blue
類的屬性配置:
blue.title=blue-value-properties
blue.rank=2
- 引入配置文件
使用@PropertySource
注解將properties
文件導(dǎo)入到配置類:
@Configuration
@ComponentScan("com.example")
@PropertySource("classpath:blue.properties")
public class InjectValueConfiguration {
}
??這個(gè)blue.properties
文件是一個(gè)鍵值對(duì)的列表,Spring
將這些鍵值對(duì)加載到 Environment
中,我們可以通過(guò) @Value
注解或者 Environment
類的方法來(lái)獲取這些屬性值。
@Value
注解和Environment
類都可以用于讀取Spring
上下文中的屬性值。這些屬性值可能來(lái)自于多個(gè)不同的源,包括但不限于:
Spring Boot
的默認(rèn)配置文件(application.properties
或application.yml
)。- 通過(guò)
@PropertySource
注解加載的屬性文件。- 系統(tǒng)環(huán)境變量。
Java
系統(tǒng)屬性(可以通過(guò)-D
命令行參數(shù)設(shè)置)。
如果你想通過(guò) @Value
注解來(lái)獲取屬性值,如下:
@Component
public class BlueConfig {
@Value("${blue.title}")
private String title;
@Value("${blue.rank}")
private int rank;
// getters and setters...
}
??在 Spring
應(yīng)用中使用 @PropertySource
注解來(lái)加載一個(gè) .properties
文件時(shí),這個(gè)文件中的所有配置項(xiàng)都會(huì)被讀取,并存儲(chǔ)在一個(gè)內(nèi)部的 Map
結(jié)構(gòu)中。這個(gè) Map
的鍵是配置項(xiàng)的名稱,值是配置項(xiàng)的值。Spring
中的一些內(nèi)置配置項(xiàng)也會(huì)被添加到這個(gè) Map
中。
??當(dāng)我們使用 ${...}
占位符語(yǔ)法來(lái)引用一個(gè)配置項(xiàng)時(shí),Spring
會(huì)查找這個(gè) Map
,取出與占位符名稱相應(yīng)的配置項(xiàng)的值。例如有一個(gè)配置項(xiàng) blue.title=blue-value-properties
,我們可以在代碼中使用 ${blue.title}
占位符來(lái)引用這個(gè)配置項(xiàng)的值。
如果想通過(guò) Environment
類的方法來(lái)獲取屬性值,可以像下面這樣做:
@Component
public class SomeComponent {
@Autowired
private Environment env;
public void someMethod() {
String title = env.getProperty("blue.title");
int rank = Integer.parseInt(env.getProperty("blue.rank"));
// ...
}
}
??在上述代碼中,Environment
類的 getProperty
方法用于獲取屬性值。注意,getProperty
方法返回的是 String
,所以如果屬性是非字符串類型(如 int
),則需要將獲取的屬性值轉(zhuǎn)換為適當(dāng)?shù)念愋汀?/p>
??注意:@PropertySource
無(wú)法加載 YAML
格式的文件,只能加載 properties
格式的文件。如果需要加載 YAML
格式的文件,而且使用的是 Spring Boot
框架,那么可以使用@ConfigurationProperties
或@Value
注解。例如以下的YAML
文件:
application.yml
appTest:
name: MyApp
version: 1.0.0
可以使用@ConfigurationProperties
來(lái)加載這些屬性:
@Configuration
@ConfigurationProperties(prefix = "appTest")
public class AppConfig {
private String name;
private String version;
// getters and setters...
}
??@ConfigurationProperties
注解主要用于指定配置屬性的前綴,@ConfigurationProperties
注解本身并不直接指定配置文件的位置, 而是由Spring Boot
的自動(dòng)配置機(jī)制處理的。
??這樣,name
字段就會(huì)被自動(dòng)綁定到appTest.name
配置屬性,version
字段就會(huì)被自動(dòng)綁定到appTest.version
配置屬性。
??默認(rèn)情況下,Spring Boot
會(huì)在啟動(dòng)時(shí)自動(dòng)加載src/main/resources
目錄下的application.properties
或application.yml
文件。我們可以通過(guò)設(shè)置spring.config.name
和spring.config.location
屬性來(lái)改變默認(rèn)的配置文件名或位置。
??注意:@ConfigurationProperties
注解需要配合@EnableConfigurationProperties
注解或@Configuration
注解使用,以確保Spring
能夠發(fā)現(xiàn)并處理這些注解。
或者,你也可以使用@Value
注解來(lái)加載這些屬性:
@Component
public class AppConfig {
@Value("${appTest.name}")
private String name;
@Value("${appTest.version}")
private String version;
// getters and setters...
}
- Blue類的屬性注入
對(duì)于properties
類型的屬性,我們這里選擇@Value
注解和占位符來(lái)注入屬性:
@Value("${blue.title}")
private String title;
@Value("${blue.rank}")
private Integer rank;
如果你熟悉jsp
的el
表達(dá)式,會(huì)發(fā)現(xiàn)這和它非常相似!
- 測(cè)試啟動(dòng)類
修改啟動(dòng)類,將配置類引入,然后取出并打印Blue
:
public static void main(String[] args) throws Exception {
ApplicationContext ctx = new AnnotationConfigApplicationContext(InjectValueConfiguration.class);
Blue blue = ctx.getBean(Blue.class);
System.out.println("Properties value : " + blue);
}
運(yùn)行main
方法會(huì)看到控制臺(tái)已經(jīng)成功打印出了配置文件的屬性:
Properties value : Blue{title='blue-value-properties', rank=2}
3.3 在XML中引入外部配置文件
在xml
中,我們可以和@Value
相同的方式使用占位符:
<?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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
xmlns:context="http://www.springframework.org/schema/context">
<!-- 相當(dāng)于注解中的 @PropertySource("classpath:blue.properties") -->
<context:property-placeholder location="classpath:blue.properties"/>
<bean class="com.example.demo.bean.Blue">
<property name="title" value="${blue.title}"/>
<property name="rank" value="${blue.rank}"/>
</bean>
</beans>
3.4 注解式屬性注入完整代碼示例
- @Value注解式屬性注入的應(yīng)用
創(chuàng)建White
類:
package com.example.demo.bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class White {
@Value("white-value-annotation")
private String title;
@Value("1")
private Integer rank;
@Override
public String toString() {
return "White{" + "title='" + title + '\'' + ", rank=" + rank + '}';
}
}
創(chuàng)建啟動(dòng)類InjectValueAnnotationApplication
:
package com.example.demo;
import com.example.demo.bean.White;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
public static void main(String[] args) throws Exception {
ApplicationContext ctx = new AnnotationConfigApplicationContext(White.class);
White white = ctx.getBean(White.class);
System.out.println("Injected value : " + white);
}
}
運(yùn)行結(jié)果如下:
- 引入外部配置文件@PropertySource
創(chuàng)建Blue
類和配置文件,沒(méi)有setter
和getter
方法:
package com.example.demo.bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Blue {
@Value("${blue.title}")
private String title;
@Value("${blue.rank}")
private Integer rank;
@Override
public String toString() {
return "Blue{" + "title='" + title + '\'' + ", rank=" + rank + '}';
}
}
resources
目錄下的blue.properties
文件:
blue.title=blue-value-properties
blue.rank=2
創(chuàng)建配置類InjectValueConfiguration
:
package com.example.demo.configuration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@ComponentScan("com.example")
@PropertySource("classpath:blue.properties")
public class InjectValueConfiguration {
}
修改啟動(dòng)類,引入配置類:
package com.example.demo;
import com.example.demo.bean.Blue;
import com.example.demo.configuration.InjectValueConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
public static void main(String[] args) throws Exception {
ApplicationContext ctx = new AnnotationConfigApplicationContext(InjectValueConfiguration.class);
Blue blue = ctx.getBean(Blue.class);
System.out.println("Properties value : " + blue);
}
}
運(yùn)行結(jié)果如下:
- 在xml中引入外部配置文件
??在使用XML
配置的情況下,我們需要?jiǎng)?chuàng)建一個(gè)XML
文件來(lái)替代InjectValueConfiguration
類,我們可以先注釋掉InjectValueConfiguration
類的所有內(nèi)容
下面是相應(yīng)的XML
文件內(nèi)容:
<?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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
xmlns:context="http://www.springframework.org/schema/context">
<!-- 相當(dāng)于注解中的 @PropertySource("classpath:blue.properties") -->
<context:property-placeholder location="classpath:blue.properties"/>
<bean class="com.example.demo.bean.Blue">
<property name="title" value="${blue.title}"/>
<property name="rank" value="${blue.rank}"/>
</bean>
</beans>
??在這里我們使用了context:property-placeholder
標(biāo)簽來(lái)導(dǎo)入外部的properties
文件,然后使用${...}
占位符語(yǔ)法來(lái)引用配置文件中的屬性值。這樣無(wú)論是選擇用注解方式還是XML
方式,都可以方便地在Spring
中使用外部配置文件。
這里還需要修改下Blue
類,因?yàn)橥ㄟ^(guò)XML
方法注入屬性需要提供相應(yīng)的setter
方法,修改后的Blue
類如下:
package com.example.demo.bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Blue {
@Value("${blue.title}")
private String title;
@Value("${blue.rank}")
private Integer rank;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Integer getRank() {
return rank;
}
public void setRank(Integer rank) {
this.rank = rank;
}
@Override
public String toString() {
return "Blue{" + "title='" + title + '\'' + ", rank=" + rank + '}';
}
}
然后,我們需要修改啟動(dòng)類,使用XmlApplicationContext
代替AnnotationConfigApplicationContext
:
package com.example.demo;
import com.example.demo.bean.Blue;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@ComponentScan("com.example")
public class DemoApplication {
public static void main(String[] args) throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:injectValueContext.xml");
Blue blue = ctx.getBean(Blue.class);
System.out.println("Properties value : " + blue);
}
}
運(yùn)行結(jié)果如下:
4. SpEL表達(dá)式
??當(dāng)我們談到屬性注入的時(shí)候,我們可能會(huì)遇到一些復(fù)雜的需求,例如我們需要引用另一個(gè)Bean
的屬性,或者我們需要?jiǎng)討B(tài)處理某個(gè)屬性值。這種需求無(wú)法通過(guò)使用${}
的占位符方式實(shí)現(xiàn),我們需要一個(gè)更強(qiáng)大的工具:SpEL
表達(dá)式。
??Spring Expression Language
(SpEL
)是從Spring
框架 3.0
開始支持的強(qiáng)大工具。SpEL
不僅是Spring
框架的重要組成部分,也可以獨(dú)立使用。它的功能豐富,包括調(diào)用屬性值、屬性參數(shù)、方法調(diào)用、數(shù)組存儲(chǔ)以及邏輯計(jì)算等。它與開源項(xiàng)目OGNL
(Object-Graph Navigation Language
)相似,但SpEL
是Spring
框架推出的,并默認(rèn)內(nèi)嵌在Spring
框架中。
4.1 使用@Value注解和SpEL表達(dá)式實(shí)現(xiàn)屬性注入
??SpEL
的表達(dá)式用#{}
表示,花括號(hào)中就是我們要編寫的表達(dá)式。
??我們創(chuàng)建一個(gè)Bean
,命名為Azure
,同樣地,我們聲明屬性name
和priority
,并提供getter
和setter
方法以及toString()
方法。然后我們使用@Component
注解標(biāo)注它。
使用@Value
配合SpEL
完成屬性注入,如下:
@Component
public class Azure {
@Value("#{'spel-for-azure'}")
private String name;
@Value("#{10}")
private Integer priority;
}
我們修改啟動(dòng)類,從IOC
容器中獲取Azure
并打印,可以看到屬性被成功注入:
Azure{name='spel-for-azure', priority=10}
??SpEL
的功能遠(yuǎn)不止這些,它還可以獲取IOC
容器中其他Bean
的屬性,讓我們來(lái)展示一下。
??我們已經(jīng)注冊(cè)了Azure Bean
,現(xiàn)在我們?cè)賱?chuàng)建一個(gè)Bean
,命名為Emerald
。我們按照上述方法對(duì)字段和方法進(jìn)行聲明,然后使用@Component
注解標(biāo)注。
??我們希望name
屬性直接復(fù)制Azure
的name
屬性,而priority
屬性則希望比Azure
的priority
屬性大1
,我們可以這樣編寫:
@Component
public class Emerald {
@Value("#{'copy of ' + azure.name}")
private String name;
@Value("#{azure.priority + 1}")
private Integer priority;
}
??在Spring
的SpEL
中可以通過(guò)bean
的名稱訪問(wèn)到對(duì)應(yīng)的bean
,并通過(guò).
操作符訪問(wèn)bean
的屬性。在這個(gè)例子中,azure
就是一個(gè)bean
的名稱,它對(duì)應(yīng)的bean
就是Azure
類的實(shí)例。所以,azure.name
就是訪問(wèn)Azure
類實(shí)例的name
屬性。
如果你在一個(gè)不涉及Spring
的環(huán)境中使用SpEL
,這個(gè)特性是不會(huì)生效的。這是因?yàn)檫@個(gè)特性依賴于Spring
的IoC
容器。
我們修改啟動(dòng)類,測(cè)試運(yùn)行,可以看到Azure
的屬性已經(jīng)成功被復(fù)制:
use spel bean property : Emerald{name='copy of spel-for-azure', priority=11}
??SpEL
表達(dá)式不僅可以引用對(duì)象的屬性,還可以直接引用類的常量,以及調(diào)用對(duì)象的方法。下面我們通過(guò)示例進(jìn)行演示。
??我們新建一個(gè)Bean
,命名為Ivory
。我們按照上述方法初始化屬性、toString()
方法、注解。
??假設(shè)我們有一個(gè)需求,讓name
取azure
屬性的前3
個(gè)字符,priority
取Integer
的最大值。那么我們可以使用SpEL
這樣寫:
@Component
public class Ivory {
@Value("#{azure.name.substring(0, 3)}")
private String name;
@Value("#{T(java.lang.Integer).MAX_VALUE}")
private Integer priority;
}
注意,直接引用類的屬性,需要在類的全限定名外面使用T()
包圍。
我們修改啟動(dòng)類,測(cè)試運(yùn)行,可以看到Ivory
的屬性已經(jīng)是處理之后的值:
use spel methods : Ivory{name='spe', priority=2147483647}
4.2 在XML中使用SpEL表達(dá)式實(shí)現(xiàn)屬性注入:
<bean id="ivory" class="com.example.demo.bean.Ivory">
<property name="name" value="#{azure.name.substring(0, 3)}" />
<property name="priority" value="#{T(java.lang.Integer).MAX_VALUE}" />
</bean>
學(xué)習(xí)SpEL
表達(dá)式不需要花費(fèi)大量的精力,掌握基礎(chǔ)的使用方法即可。
4.3 SpEL表達(dá)式屬性注入完整代碼示例
- 使用@Value注解和SpEL表達(dá)式實(shí)現(xiàn)屬性注入
創(chuàng)建三個(gè)SpEL
表達(dá)式屬性注入的Bean
:Azure.java
、Emerald.java
和Ivory.java
。
Azure.java:
package com.example.demo.bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Azure {
@Value("#{'spel-for-azure'}")
private String name;
@Value("#{10}")
private Integer priority;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPriority() {
return priority;
}
public void setPriority(Integer priority) {
this.priority = priority;
}
@Override
public String toString() {
return "Azure{" +
"name='" + name + '\'' +
", priority=" + priority +
'}';
}
}
Emerald.java:
package com.example.demo.bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Emerald {
@Value("#{'copy of ' + azure.name}")
private String name;
@Value("#{azure.priority + 1}")
private Integer priority;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPriority() {
return priority;
}
public void setPriority(Integer priority) {
this.priority = priority;
}
@Override
public String toString() {
return "Emerald{" +
"name='" + name + '\'' +
", priority=" + priority +
'}';
}
}
Ivory.java:
package com.example.demo.bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Ivory {
@Value("#{azure.name.substring(0, 3)}")
private String name;
@Value("#{T(java.lang.Integer).MAX_VALUE}")
private Integer priority;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPriority() {
return priority;
}
public void setPriority(Integer priority) {
this.priority = priority;
}
@Override
public String toString() {
return "Ivory{" +
"name='" + name + '\'' +
", priority=" + priority +
'}';
}
}
MyBean.java
@Component
public class MyBean {
@Autowired
private Azure azure;
@Autowired
private Emerald emerald;
@Autowired
private Ivory ivory;
public void init() {
System.out.println(azure);
System.out.println(emerald);
System.out.println(ivory);
}
}
??MyBean
是一個(gè)用于展示如何在Spring
中通過(guò)SpEL
表達(dá)式來(lái)注入屬性的類,它聚合了三個(gè)對(duì)象Azure
, Emerald
和Ivory
,并通過(guò)Spring
的依賴注入機(jī)制將這三個(gè)對(duì)象注入到了MyBean
類的實(shí)例中
主程序DemoApplication
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args);
MyBean myBean = applicationContext.getBean(MyBean.class);
myBean.init();
}
}
運(yùn)行結(jié)果:
- 在XML中使用SpEL表達(dá)式實(shí)現(xiàn)屬性注入
??對(duì)于XML
配置,Spring
還支持在bean
定義中使用SpEL
。
首先,需要?jiǎng)?chuàng)建一個(gè)Spring XML
配置文件,我們將其命名為app-config.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.example" />
<bean id="azure" class="com.example.demo.bean.Azure">
<property name="name" value="#{'spel-for-azure'}" />
<property name="priority" value="#{10}" />
</bean>
<bean id="emerald" class="com.example.demo.bean.Emerald">
<property name="name" value="#{'copy of ' + azure.name}" />
<property name="priority" value="#{azure.priority + 1}" />
</bean>
<bean id="ivory" class="com.example.demo.bean.Ivory">
<property name="name" value="#{azure.name.substring(0, 3)}" />
<property name="priority" value="#{T(java.lang.Integer).MAX_VALUE}" />
</bean>
</beans>
注意:在XML
中使用SpEL
需要使用#{}
,而不是${}
。
??然后修改這3
個(gè)Bean
,如果是使用XML
來(lái)配置Spring
的Bean
的話,那么在Java
類中就不需要使用@Component
注解了。因?yàn)?code>XML配置文件已經(jīng)明確地告訴Spring
這些類是Spring Bean
。
??同樣的,如果在XML
文件中定義了Bean
的屬性值,那么在Java
類中就不需要使用@Value
注解來(lái)注入這些值了。因?yàn)?code>XML配置文件已經(jīng)明確地為這些屬性賦了值。
Azure.java
package com.example.demo.bean;
public class Azure {
private String name;
private Integer priority;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPriority() {
return priority;
}
public void setPriority(Integer priority) {
this.priority = priority;
}
@Override
public String toString() {
return "Azure{" +
"name='" + name + '\'' +
", priority=" + priority +
'}';
}
}
Emerald.java
package com.example.demo.bean;
public class Emerald {
private String name;
private Integer priority;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPriority() {
return priority;
}
public void setPriority(Integer priority) {
this.priority = priority;
}
@Override
public String toString() {
return "Emerald{" +
"name='" + name + '\'' +
", priority=" + priority +
'}';
}
}
Ivory.java
package com.example.demo.bean;
public class Ivory {
private String name;
private Integer priority;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPriority() {
return priority;
}
public void setPriority(Integer priority) {
this.priority = priority;
}
@Override
public String toString() {
return "Ivory{" +
"name='" + name + '\'' +
", priority=" + priority +
'}';
}
}
然后需要在主程序中導(dǎo)入這個(gè)XML
配置文件,這可以通過(guò)在主程序中添加@ImportResource
注解實(shí)現(xiàn):
package com.example.demo;
import com.example.demo.bean.MyBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ImportResource;
@SpringBootApplication
@ImportResource("classpath:app-config.xml")
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args);
MyBean myBean = applicationContext.getBean(MyBean.class);
myBean.init();
}
}
這樣就可以在Spring
的XML
配置文件中使用SpEL
了。
運(yùn)行結(jié)果如下:
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-479235.html
歡迎一鍵三連~
有問(wèn)題請(qǐng)留言,大家一起探討學(xué)習(xí)
----------------------Talk is cheap, show me the code-----------------------
到了這里,關(guān)于Spring高手之路3——揭秘Spring依賴注入和SpEL表達(dá)式的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!