裝配 Bean 的概述
前面已經介紹了 Spring IoC 的理念和設計,這一篇文章将介紹的是如何将自己開發的 Bean 裝配到 Spring IoC 容器中。
大部分場景下,我們都會使用 ApplicationContext 的具體實作類,因為對應的 Spring IoC 容器功能相對強大。
而在 Spring 中提供了 3 種方法進行配置:
- 在 XML 檔案中顯式配置
- 在 Java 的接口和類中實作配置
- 隐式 Bean 的發現機制和自動裝配原則
方式選擇的原則
在現實的工作中,這 3 種方式都會被用到,并且在學習和工作之中常常混合使用,是以這裡給出一些關于這 3 種優先級的建議:
1.最優先:通過隐式 Bean 的發現機制和自動裝配的原則。
基于約定由于配置的原則,這種方式應該是最優先的
- 好處:減少程式開發者的決定權,簡單又不失靈活。
2.其次:Java 接口和類中配置實作配置
在沒有辦法使用自動裝配原則的情況下應該優先考慮此類方法
- 好處:避免 XML 配置的泛濫,也更為容易。
- 典型場景:一個父類有多個子類,比如學生類有兩個子類,一個男學生類和女學生類,通過 IoC 容器初始化一個學生類,容器将無法知道使用哪個子類去初始化,這個時候可以使用 Java 的注解配置去指定。
3.最後:XML 方式配置
在上述方法都無法使用的情況下,那麼也隻能選擇 XML 配置的方式。
- 好處:簡單易懂(當然,特别是對于初學者)
- 典型場景:當使用第三方類的時候,有些類并不是我們開發的,我們無法修改裡面的代碼,這個時候就通過 XML 的方式配置使用了。
通過 XML 配置裝配 Bean
使用 XML 裝配 Bean 需要定義對應的 XML,這裡需要引入對應的 XML 模式(XSD)檔案,這些檔案會定義配置 Spring Bean 的一些元素,當我們在 IDEA 中建立 XML 檔案時,會有友好的提示:
一個簡單的 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
這就隻是一個格式檔案,引入了一個 beans 的定義,引入了 xsd 檔案,它是一個根元素,這樣它所定義的元素将可以定義對應的 Spring Bean
裝配簡易值
先來一個最簡單的裝配:
<bean id="c" class="pojo.Category">
<property name="name" value="測試" />
</bean>
簡單解釋一下:
-
屬性是 Spring 能找到目前 Bean 的一個依賴的編号,遵守 XML 文法的 ID 唯一性限制。必須以字母開頭,可以使用字母、數字、連字元、下劃線、句号、冒号,不能以id
/
開頭。
不過
屬性不是一個必需的屬性,id
屬性也可以定義 bean 元素的名稱,能以逗号或空格隔開起多個别名,并且可以使用很多的特殊字元,比如在 Spring 和 Spring MVC 的整合中,就得使用name
屬性來定義 bean 的名稱,并且使用name
注意: 從 Spring 3.1 開始,/
屬性也可以是 String 類型了,也就是說id
屬性也可以使用id
/
開頭,而 bean 元素的 id 的唯一性由容器負責檢查。
如果
和id
屬性都沒有聲明的話,那麼 Spring 将會采用 “全限定名#{number}” 的格式生成編号。 例如這裡,如果沒有聲明 “name
” 的話,那麼 Spring 為其生成的編号就是 “id="c"
”,當它第二次聲明沒有pojo.Category#0
屬性的 Bean 時,編号就是 “id
”,以此類推。pojo.Category#1
-
屬性顯然就是一個類的全限定名class
-
元素是定義類的屬性,其中的property
屬性定義的是屬性的名稱,而name
是它的值。value
這樣的定義很簡單,但是有時候需要注入一些自定義的類,比如之前飲品店的例子,JuickMaker 需要使用者提供原料資訊才能完成 juice 的制作:
<!-- 配置 srouce 原料 -->
<bean name="source" class="pojo.Source">
<property name="fruit" value="橙子"/>
<property name="sugar" value="多糖"/>
<property name="size" value="超大杯"/>
</bean>
<bean name="juickMaker" class="pojo.JuiceMaker">
<!-- 注入上面配置的id為srouce的Srouce對象 -->
<property name="source" ref="source"/>
</bean>
這裡先定義了一個
name
為 source 的 Bean,然後再制造器中通過
ref
屬性去引用對應的 Bean,而 source 正是之前定義的 Bean 的
name
,這樣就可以互相引用了。
- 注入對象:使用
屬性ref
裝配集合
有些時候我們需要裝配一些複雜的東西,比如 Set、Map、List、Array 和 Properties 等,為此我們在 Packge【pojo】下建立一個 ComplexAssembly 類:
package pojo;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class ComplexAssembly {
private Long id;
private List<String> list;
private Map<String, String> map;
private Properties properties;
private Set<String> set;
private String[] array;
/* setter and getter */
}
這個 Bean 沒有任何的實際意義,知識為了介紹如何裝配這些常用的集合類:
<bean id="complexAssembly" class="pojo.ComplexAssembly">
<!-- 裝配Long類型的id -->
<property name="id" value="1"/>
<!-- 裝配List類型的list -->
<property name="list">
<list>
<value>value-list-1</value>
<value>value-list-2</value>
<value>value-list-3</value>
</list>
</property>
<!-- 裝配Map類型的map -->
<property name="map">
<map>
<entry key="key1" value="value-key-1"/>
<entry key="key2" value="value-key-2"/>
<entry key="key3" value="value-key-2"/>
</map>
</property>
<!-- 裝配Properties類型的properties -->
<property name="properties">
<props>
<prop key="prop1">value-prop-1</prop>
<prop key="prop2">value-prop-2</prop>
<prop key="prop3">value-prop-3</prop>
</props>
</property>
<!-- 裝配Set類型的set -->
<property name="set">
<set>
<value>value-set-1</value>
<value>value-set-2</value>
<value>value-set-3</value>
</set>
</property>
<!-- 裝配String[]類型的array -->
<property name="array">
<array>
<value>value-array-1</value>
<value>value-array-2</value>
<value>value-array-3</value>
</array>
</property>
</bean>
- 總結:
- List 屬性為對應的
元素進行裝配,然後通過多個<list>
元素設值<value>
- Map 屬性為對應的
<map>
元素設值,隻是<entry>
包含一個鍵值對(key-value)的設定entry
- Properties 屬性為對應的
元素進行裝配,通過多個<properties>
<property>
元素有一個必填屬性properties
,然後可以設定值key
- Set 屬性為對應的
<set>
<value>
- 對于數組而言,可以使用
設定值,然後通過多個<array>
元素設值。<value>
上面看到了對簡單 String 類型的各個集合的裝載,但是有些時候可能需要更為複雜的裝載,比如一個 List 可以是一個系列類的對象,為此需要定義注入的相關資訊,其實跟上面的配置沒什麼兩樣,隻不過加入了
ref
這一個屬性而已:
- 集合注入總結:
- List 屬性使用
元素定義注入,使用多個<list>
元素的 Bean 屬性去引用之前定義好的 Bean<ref>
<property name="list">
<list>
<ref bean="bean1"/>
<ref bean="bean2"/>
</list>
</property>
- Map 屬性使用
<map>
元素的<entry>
屬性去引用之前定義好的 Bean 作為鍵,而用key-ref
屬性引用之前定義好的 Bean 作為值value-ref
<property name="map">
<map>
<entry key-ref="keyBean" value-ref="valueBean"/>
</map>
</property>
- Set 屬性使用
<set>
<ref>
去引用之前定義好的 Beanbean
<property name="set">
<set>
<ref bean="bean"/>
</set>
</property>
命名空間裝配
除了上述的配置之外, Spring 還提供了對應的命名空間的定義,隻是在使用命名空間的時候要先引入對應的命名空間和 XML 模式(XSD)檔案。
——【① c-命名空間】——
c-命名空間是在 Spring 3.0 中引入的,它是在 XML 中更為簡潔地描述構造器參數的方式,要使用它的話,必須要在 XML 的頂部聲明其模式:
- 注意:是通過構造器參數的方式
現在假設我們現在有這麼一個類:
package pojo;
public class Student {
int id;
String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
// setter and getter
}
在 c-命名空間和模式聲明之後,我們就可以使用它來聲明構造器參數了:
<!-- 引入 c-命名空間之前 -->
<bean name="student1" class="pojo.Student">
<constructor-arg name="id" value="1" />
<constructor-arg name="name" value="學生1"/>
</bean>
<!-- 引入 c-命名空間之後 -->
<bean name="student2" class="pojo.Student"
c:id="2" c:name="學生2"/>
c-命名空間屬性名以 “
c:
” 開頭,也就是命名空間的字首。接下來就是要裝配的構造器參數名,在此之後如果需要注入對象的話則要跟上
-ref
(如
c:card-ref="idCard1"
,則對 card 這個構造器參數注入之前配置的名為 idCard1 的 bean)
很顯然,使用 c-命名空間屬性要比使用
<constructor-arg>
元素精簡,并且會直接引用構造器之中參數的名稱,這有利于我們使用的安全性。
我們有另外一種替代方式:
<bean name="student2" class="pojo.Student"
c:_0="3" c:_1="學生3"/>
我們将參數的名稱替換成了 “0” 和 “1” ,也就是參數的索引。因為在 XML 中不允許數字作為屬性的第一個字元,是以必須要添加一個下劃線來作為字首。
——【② p-命名空間】——
c-命名空間通過構造器注入的方式來配置 bean,p-命名空間則是用setter的注入方式來配置 bean ,同樣的,我們需要引入聲明:
然後我們就可以通過 p-命名空間來設定屬性:
<!-- 引入p-命名空間之前 -->
<bean name="student1" class="pojo.Student">
<property name="id" value="1" />
<property name="name" value="學生1"/>
</bean>
<!-- 引入p-命名空間之後 -->
<bean name="student2" class="pojo.Student"
p:id="2" p:name="學生2"/>
我們需要先删掉 Student 類中的構造函數,不然 XML 限制會提示我們配置
<constructor-arg>
元素。
同樣的,如果屬性需要注入其他 Bean 的話也可以在後面跟上
-ref
:
<bean name="student2" class="pojo.Student"
p:id="2" p:name="學生2" p:cdCard-ref="cdCard1"/>
——【③ util-命名空間】——
工具類的命名空間,可以簡化集合類元素的配置,同樣的我們需要引入其聲明(無需擔心怎麼聲明的問題,IDEA會有很友好的提示):
我們來看看引入前後的變化:
<!-- 引入util-命名空間之前 -->
<property name="list">
<list>
<ref bean="bean1"/>
<ref bean="bean2"/>
</list>
</property>
<!-- 引入util-命名空間之後 -->
<util:list id="list">
<ref bean="bean1"/>
<ref bean="bean2"/>
</util:list>
<util:list>
隻是 util-命名空間中的多個元素之一,下表提供了 util-命名空間提供的所有元素:
元素 | 描述 |
---|---|
| 引用某個類型的 域,并将其暴露為 bean |
| 建立一個 類型的 bean,其中包含值或引用 |
| |
| 類型的 bean |
| 引用一個 bean 的屬性(或内嵌屬性),并将其暴露為 bean |
| |
引入其他配置檔案
在實際開發中,随着應用程式規模的增加,系統中
<bean>
元素配置的數量也會大大增加,導緻 applicationContext.xml 配置檔案變得非常臃腫難以維護。
-
解決方案:讓 applicationContext.xml 檔案包含其他配置檔案即可
使用
元素引入其他配置檔案<import>
1.在【src】檔案下建立一個 bean.xml 檔案,寫好基礎的限制,把 applicationContext.xml 檔案中配置的
<bean>
元素複制進去
2.在 applicationContext.xml 檔案中寫入:
<import resource="bean.xml" />
3.運作測試代碼,仍然能正确擷取到 bean:
通過注解裝配 Bean
上面,我們已經了解了如何使用 XML 的方式去裝配 Bean,但是更多的時候已經不再推薦使用 XML 的方式去裝配 Bean,更多的時候回考慮使用注解(annotation) 的方式去裝配 Bean。
-
優勢:
1.可以減少 XML 的配置,當配置項多的時候,臃腫難以維護
2.功能更加強大,既能實作 XML 的功能,也提供了自動裝配的功能,采用了自動裝配後,程式猿所需要做的決斷就少了,更加有利于對程式的開發,這就是“約定由于配置”的開發原則
在 Spring 中,它提供了兩種方式來讓 Spring IoC 容器發現 bean:
- 元件掃描:通過定義資源的方式,讓 Spring IoC 容器掃描對應的包,進而把 bean 裝配進來。
- 自動裝配:通過注解定義,使得一些依賴關系可以通過注解完成。
使用@Compoent 裝配 Bean
我們把之前建立的 Student 類改一下:
package pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component(value = "student1")
public class Student {
@Value("1")
int id;
@Value("student_name_1")
String name;
// getter and setter
}
解釋一下:
-
@Component注解:
表示 Spring IoC 會把這個類掃描成一個 bean 執行個體,而其中的
屬性代表這個類在 Spring 中的value
,這就相當于在 XML 中定義的 Bean 的 id:id
,也可以簡寫成<bean id="student1" class="pojo.Student" />
,甚至直接寫成@Component("student1")
,對于不寫的,Spring IoC 容器就預設以類名來命名作為@Component
,隻不過首字母小寫,配置到容器中。id
-
@Value注解:
表示值的注入,跟在 XML 中寫
屬性是一樣的。value
這樣我們就聲明好了我們要建立的一個 Bean,就像在 XML 中寫下了這樣一句話:
<bean name="student1" class="pojo.Student">
<property name="id" value="1" />
<property name="name" value="student_name_1"/>
</bean>
但是現在我們聲明了這個類,并不能進行任何的測試,因為 Spring IoC 并不知道這個 Bean 的存在,這個時候我們可以使用一個 StudentConfig 類去告訴 Spring IoC :
package pojo;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan
public class StudentConfig {
}
這個類十分簡單,沒有任何邏輯,但是需要說明兩點:
- 該類和 Student 類位于同一包名下
-
@ComponentScan注解:
代表進行掃描,預設是掃描目前包的路徑,掃描所有帶有
注解的 POJO。@Component
這樣一來,我們就可以通過 Spring 定義好的 Spring IoC 容器的實作類——AnnotationConfigApplicationContext 去生成 IoC 容器了:
ApplicationContext context = new AnnotationConfigApplicationContext(StudentConfig.class);
Student student = (Student) context.getBean("student1", Student.class);
student.printInformation();
這裡可以看到使用了 AnnotationConfigApplicationContext 類去初始化 Spring IoC 容器,它的配置項是 StudentConfig 類,這樣 Spring IoC 就會根據注解的配置去解析對應的資源,來生成 IoC 容器了。
- 明顯的弊端:
- 對于
注解,它隻是掃描所在包的 Java 類,但是更多的時候我們希望的是可以掃描我們指定的類@ComponentScan
- 上面的例子隻是注入了一些簡單的值,測試發現,通過
注解并不能注入對象@Value
@Component
注解存在着兩個配置項:
- basePackages:它是由 base 和 package 兩個單詞組成的,而 package 還是用了複數,意味着它可以配置一個 Java 包的數組,Spring 會根據它的配置掃描對應的包和子包,将配置好的 Bean 裝配進來
- basePackageClasses:它由 base、package 和 class 三個單詞組成,采用複數,意味着它可以配置多個類, Spring 會根據配置的類所在的包,為包和子包進行掃描裝配對應配置的 Bean
我們來試着重構之前寫的 StudentConfig 類來驗證上面兩個配置項:
package pojo;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan(basePackages = "pojo")
public class StudentConfig {
}
// —————————————————— 【 宇宙超級無敵分割線】——————————————————
package pojo;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan(basePackageClasses = pojo.Student.class)
public class StudentConfig {
}
驗證都能通過,bingo!
-
對于 【basePackages】 和 【basePackageClasses】 的選擇問題:
【basePackages】 的可讀性會更好一些,是以在項目中會優先選擇使用它,但是在需要大量重構的工程中,盡量不要使用【basePackages】,因為很多時候重構修改包名需要反複地配置,而 IDE 不會給你任何的提示,而采用【basePackageClasses】會有錯誤提示。
自動裝配——@Autowired
上面提到的兩個弊端之一就是沒有辦法注入對象,通過自動裝配我們将解決這個問題。
所謂自動裝配技術是一種由 Spring 自己發現對應的 Bean,自動完成裝配工作的方式,它會應用到一個十分常用的注解
@Autowired
上,這個時候 Spring 會根據類型去尋找定義的 Bean 然後将其注入,聽起來很神奇,讓我們實際來看一看:
1.先在 Package【service】下建立一個 StudentService 接口:
package service;
public interface StudentService {
public void printStudentInfo();
}
使用接口是 Spring 推薦的方式,這樣可以更為靈活,可以将定義和實作分離
2.為上面的接口建立一個 StudentServiceImp 實作類:
package service;
import org.springframework.beans.factory.annotation.Autowired;
import pojo.Student;
@Component("studentService")
public class StudentServiceImp implements StudentService {
@Autowired
private Student student = null;
// getter and setter
public void printStudentInfo() {
System.out.println("學生的 id 為:" + student.getName());
System.out.println("學生的 name 為:" + student.getName());
}
}
該實作類實作了接口的 printStudentInfo() 方法,列印出成員對象 student 的相關資訊,這裡的
@Autowired
注解,表示在 Spring IoC 定位所有的 Bean 後,這個字段需要按類型注入,這樣 IoC 容器就會尋找資源,然後将其注入。
3.編寫測試類:
// 第一步:修改 StudentConfig 類,告訴 Spring IoC 在哪裡去掃描它:
package pojo;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan(basePackages = {"pojo", "service"})
public class StudentConfig {
}
// 或者也可以在 XML 檔案中聲明去哪裡做掃描
<context:component-scan base-package="pojo" />
<context:component-scan base-package="service" />
// 第二步:編寫測試類:
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import pojo.StudentConfig;
import service.StudentService;
import service.StudentServiceImp;
public class TestSpring {
public static void main(String[] args) {
// 通過注解的方式初始化 Spring IoC 容器
ApplicationContext context = new AnnotationConfigApplicationContext(StudentConfig.class);
StudentService studentService = context.getBean("studentService", StudentServiceImp.class);
studentService.printStudentInfo();
}
}
運作代碼:
- 再次了解:
注解表示在 Spring IoC 定位所有的 Bean 後,再根據類型尋找資源,然後将其注入。@Autowired
- 過程: 定義 Bean ——》 初始化 Bean(掃描) ——》 根據屬性需要從 Spring IoC 容器中搜尋滿足要求的 Bean ——》 滿足要求則注入
- 問題: IoC 容器可能會尋找失敗,此時會抛出異常(預設情況下,Spring IoC 容器會認為一定要找到對應的 Bean 來注入到這個字段,但有些時候并不是一定需要,比如日志)
- 解決: 通過配置項
來改變,比如required
@Autowired(required = false)
@Autowired
注解不僅僅能配置在屬性之上,還允許方法配置,常見的 Bean 的 setter 方法也可以使用它來完成注入,總之一切需要 Spring IoC 去尋找 Bean 資源的地方都可以用到,例如:
/* 包名和import */
public class JuiceMaker {
......
@Autowired
public void setSource(Source source) {
this.source = source;
}
}
在大部分的配置中都推薦使用這樣的自動注入來完成,這是 Spring IoC 幫助我們自動裝配完成的,這樣使得配置大幅度減少,滿足約定優于配置的原則,增強程式的健壯性。
自動裝配的歧義性(@Primary和@Qualifier)
在上面的例子中我們使用
@Autowired
注解來自動注入一個 Source 類型的 Bean 資源,但如果我們現在有兩個 Srouce 類型的資源,Spring IoC 就會不知所措,不知道究竟該引入哪一個 Bean:
<bean name="source1" class="pojo.Source">
<property name="fruit" value="橙子"/>
<property name="sugar" value="多糖"/>
<property name="size" value="超大杯"/>
</bean>
<bean name="source2" class="pojo.Source">
<property name="fruit" value="橙子"/>
<property name="sugar" value="少糖"/>
<property name="size" value="小杯"/>
</bean>
我們可以會想到 Spring IoC 最底層的容器接口——BeanFactory 的定義,它存在一個按照類型擷取 Bean 的方法,顯然通過 Source.class 作為參數無法判斷使用哪個類執行個體進行傳回,這就是自動裝配的歧義性。
為了消除歧義性,Spring 提供了兩個注解:
-
@Primary 注解:
代表首要的,當 Spring IoC 檢測到有多個相同類型的 Bean 資源的時候,會優先注入使用該注解的類。
- 問題:該注解隻是解決了首要的問題,但是并沒有選擇性的問題
-
@Qualifier 注解:
上面所談及的歧義性,一個重要的原因是 Spring 在尋找依賴注入的時候是按照類型注入引起的。除了按類型查找 Bean,Spring IoC 容器最底層的接口 BeanFactory 還提供了按名字查找的方法,如果按照名字來查找和注入不就能消除歧義性了嗎?
- 使用方法: 指定注入名稱為 "source1" 的 Bean 資源
/* 包名和import */
public class JuiceMaker {
......
@Autowired
@Qualifier("source1")
public void setSource(Source source) {
this.source = source;
}
}
使用@Bean 裝配 Bean
- 問題: 以上都是通過
注解來裝配 Bean ,并且隻能注解在類上,當你需要引用第三方包的(jar 檔案),而且往往并沒有這些包的源碼,這時候将無法為這些包的類加入@Component
注解,讓它們變成開發環境中的 Bean 資源。@Component
-
解決方案:
1.自己建立一個新的類來擴充包裡的類,然後再新類上使用
@Component
注解,但這樣很 low
2.使用
注解,注解到方法之上,使其成為 Spring 中傳回對象為 Spring 的 Bean 資源。@Bean
我們在 Package【pojo】 下建立一個用來測試
@Bean
注解的類:
package pojo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanTester {
@Bean(name = "testBean")
public String test() {
String str = "測試@Bean注解";
return str;
}
}
- 注意:
注解相當于 XML 檔案的根元素,必須要,有了才能解析其中的@Configuration
注解@Bean
然後我們在測試類中編寫代碼,從 Spring IoC 容器中擷取到這個 Bean :
// 在 pojo 包下掃描
ApplicationContext context = new AnnotationConfigApplicationContext("pojo");
// 因為這裡擷取到的 Bean 就是 String 類型是以直接輸出
System.out.println(context.getBean("testBean"));
@Bean
的配置項中包含 4 個配置項:
- name: 是一個字元串數組,允許配置多個 BeanName
- autowire: 标志是否是一個引用的 Bean 對象,預設值是 Autowire.NO
- initMethod: 自定義初始化方法
- destroyMethod: 自定義銷毀方法
@Bean
注解的好處就是能夠動态擷取一個 Bean 對象,能夠根據環境不同得到不同的 Bean 對象。或者說将 Spring 和其他元件分離(其他元件不依賴 Spring,但是又想 Spring 管理生成的 Bean)
Bean 的作用域
在預設的情況下,Spring IoC 容器隻會對一個 Bean 建立一個執行個體,但有時候,我們希望能夠通過 Spring IoC 容器擷取多個執行個體,我們可以通過
@Scope
注解或者
<bean>
元素中的
scope
屬性來設定,例如:
// XML 中設定作用域
<bean id="" class="" scope="prototype" />
// 使用注解設定作用域
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
Spring 提供了 5 種作用域,它會根據情況來決定是否生成新的對象:
作用域類别 | |
---|---|
singleton(單例) | 在Spring IoC容器中僅存在一個Bean執行個體 (預設的scope) |
prototype(多例) | 每次從容器中調用Bean時,都傳回一個新的執行個體,即每次調用getBean()時 ,相當于執行new XxxBean():不會在容器啟動時建立對象 |
request(請求) | 用于web開發,将Bean放入request範圍 ,request.setAttribute("xxx") , 在同一個request 獲得同一個Bean |
session(會話) | 用于web開發,将Bean 放入Session範圍,在同一個Session 獲得同一個Bean |
globalSession(全局會話) | 一般用于 Porlet 應用環境 , 分布式系統存在全局 session 概念(單點登入),如果不是 porlet 環境,globalSession 等同于 Session |
在開發中主要使用
scope="singleton"
、
scope="prototype"
,對于MVC中的Action使用prototype類型,其他使用singleton,Spring容器會管理 Action 對象的建立,此時把 Action 的作用域設定為 prototype.
擴充閱讀:@Profile 注解 、 條件化裝配 Bean
Spring 表達式語言簡要說明
Spring 還提供了更靈活的注入方式,那就是 Spring 表達式,實際上 Spring EL 遠比以上注入方式都要強大,它擁有很多功能:
- 使用 Bean 的 id 來引用 Bean
- 調用指定對象的方法和通路對象的屬性
- 進行運算
- 提供正規表達式進行比對
- 集合配置
我們來看一個簡單的使用 Spring 表達式的例子:
package pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("elBean")
public class ElBean {
// 通過 beanName 擷取 bean,然後注入
@Value("#{role}")
private Role role;
// 擷取 bean 的屬性 id
@Value("#{role.id}")
private Long id;
// 調用 bean 的 getNote 方法
@Value("#{role.getNote().toString()}")
private String note;
/* getter and setter */
}
與屬性檔案中讀取使用的 “
$
” 不同,在 Spring EL 中則使用 “
#
”
擴充閱讀: Spring 表達式語言
參考資料:
- 《Java EE 網際網路輕量級架構整合開發》
- 《Java 實戰(第四版)》
- 萬能的百度 and 萬能的大腦
歡迎轉載,轉載請注明出處!
簡書ID:@我沒有三顆心髒
github:wmyskxz
歡迎關注公衆微信号:wmyskxz_javaweb
分享自己的Java Web學習之路以及各種Java學習資料