Spring4 IOC詳解
上一章對Spring做一個快速入門的教程,其中只是簡單的提到了IOC的特性。本章便對Spring的IOC進行一個詳解。主要從三個方面開始:基於xml文件的Bean配置,基於注解的Bean配置和IOC容器Bean的生命周期。
基於xml文件的Bean配置
首先是applicationContext.xml文件,這可是核心文件。
配置一個bean,需要一個id去唯一標識它,用class指定Bean對象的路徑,作用域默認是單例。
通過prototype進行屬性賦值,name是屬性名,value是值,也可以用ref引用對象,用list,map設置集合。
用SpEL表達式語言賦值,用p命名空間簡化賦值,用繼承和依賴簡化代碼。
<?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:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 配置一個 bean
bean中有一個id,且id是唯一的。若不指名則為該類的類名並首字母小寫。
property 中有一個name,其name就是生產了setter方法的屬性,value便是其值。
-->
<!-- Bean 的作用域
singleton:單例,默認值,容器初始化創建bean實例,在整個生命周期內只創建一個bean。
prototype:原型,容器初始化不創建bean實例,每次請求的時候會創建一個新的bean
-->
<bean id="entity" class="com.itdragon.spring.my.Entity" scope="prototype">
<!-- 屬性賦值
屬性注入使用 <property> 元素, 使用 name 屬性指定 Bean 的屬性名稱,value 屬性或 <value> 子節點指定屬性值
-->
<property name="intValue" value="1"></property>
<!-- 引用bean
細節:
1. 用ref 是引用外部bean
2. 也可以直接寫在當前bean里面,這就是內部bean, 內部bean是不能被外部引用
-->
<property name="spELEntity" ref="spELEntity"></property>
<!-- 構造器注入
構造器注入在 <constructor-arg> 元素里聲明屬性, <constructor-arg> 中沒有 name 屬性,按照構造器參數順序賦值
細節:
1. 也可以用index(按索引匹配入參),和type(按類型匹配入參)去指定賦值。實際上是沒有必要的
2. 使用構造器注入的前提是 entity 被初始化。
3. 特殊字符,需要用 <![CDATA[內容]]> 這屬於xml語法
-->
<constructor-arg value="1.1" />
<constructor-arg >
<value><![CDATA[<ITDragon>]]></value>
</constructor-arg>
<property name="listValue">
<list>
<value>歡迎閱讀</value>
<value>ITDragon</value>
<value>的博客!</value>
</list>
</property>
<property name="mapValue">
<map>
<entry key="one" value="1"></entry>
<entry key="two" value="2"></entry>
</map>
</property>
</bean>
<!-- SpEL 表達式語言, #{…} 作為定界符, 操作和java相似-->
<bean id="spELEntity" class="com.itdragon.spring.my.SpELEntity">
<property name="intSpel" value="#{1}"></property>
<property name="floatSpel" value="#{entity.intValue + 0.2}"></property>
<property name="stringSpel" value="#{'Spring4基礎教程'}"></property>
<property name="bSpel" value="#{2 >= 1}"></property>
</bean>
<!-- 使用 p 命名空間
給Entity 對象 的intValue 字段設置 為2 ,根據名稱匹配SpEL對象
自動裝配 autowire (不常用)
byName(根據名稱自動裝配): 必須將目標 Bean 的名稱和屬性名設置的完全相同.反之不能
byType(根據類型自動裝配): 若 IOC 容器中有多個與目標 Bean 類型一致的 Bean. 在這種情況下, 不能執行自動裝配.
-->
<bean id="entity2" class="com.itdragon.spring.my.Entity"
p:intValue="2" autowire="byName" />
<!-- 繼承 依賴
如果 被繼承的bean 不想被繼承,則要加上 abstract="true"
依賴:如果被依賴的bean,沒有實例化,則會報錯。如果有多個依賴需用","分開
-->
<bean id="entity3" class="com.itdragon.spring.my.Entity"
parent="entity" depends-on="spELEntity" />
<!-- 使用外部屬性文件 在Spring操作數據庫的時候再講 -->
</beans>
實體類Entity和SpELEntity
import java.util.List;
import java.util.Map;
public class Entity {
private int intValue;
private float floatValue;
private String stringValue;
private SpELEntity spELEntity;
private Map<String, Object> mapValue;
private List<Object> listValue;
public Entity() {
}
public Entity(float floatValue, String stringValue) {
this.floatValue = floatValue;
this.stringValue = stringValue;
}
public int getIntValue() {
return intValue;
}
public void setIntValue(int intValue) {
this.intValue = intValue;
}
public float getFloatValue() {
return floatValue;
}
public void setFloatValue(float floatValue) {
this.floatValue = floatValue;
}
public String getStringValue() {
return stringValue;
}
public void setStringValue(String stringValue) {
this.stringValue = stringValue;
}
public SpELEntity getSpELEntity() {
return spELEntity;
}
public void setSpELEntity(SpELEntity spELEntity) {
this.spELEntity = spELEntity;
}
public Map<String, Object> getMapValue() {
return mapValue;
}
public void setMapValue(Map<String, Object> mapValue) {
this.mapValue = mapValue;
}
public List<Object> getListValue() {
return listValue;
}
public void setListValue(List<Object> listValue) {
this.listValue = listValue;
}
@Override
public String toString() {
return "Entity [intValue=" + intValue + ", floatValue=" + floatValue
+ ", stringValue=" + stringValue + ", spELEntity=" + spELEntity
+ ", mapValue=" + mapValue + ", listValue=" + listValue + "]";
}
}
public class SpELEntity {
private int intSpel;
private float floatSpel;
private boolean bSpel;
private String stringSpel;
public int getIntSpel() {
return intSpel;
}
public void setIntSpel(int intSpel) {
this.intSpel = intSpel;
}
public float getFloatSpel() {
return floatSpel;
}
public void setFloatSpel(float floatSpel) {
this.floatSpel = floatSpel;
}
public boolean isbSpel() {
return bSpel;
}
public void setbSpel(boolean bSpel) {
this.bSpel = bSpel;
}
public String getStringSpel() {
return stringSpel;
}
public void setStringSpel(String stringSpel) {
this.stringSpel = stringSpel;
}
@Override
public String toString() {
return "SpELEntity [intSpel=" + intSpel + ", floatSpel=" + floatSpel
+ ", bSpel=" + bSpel + ", stringSpel=" + stringSpel + "]";
}
}
測試Main方法。首先要創建一個容器,然后通過bean的id獲取到實例,這樣就可以開始相關的操作。其中entity,entity2,entity3對應三塊不同的知識點。
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
/**
* ClassPathXmlApplicationContext:從 類路徑下加載配置文件,建議用該方法
* FileSystemXmlApplicationContext: 從文件系統中加載配置文件
*/
// 1. 創建 Spring 的 IOC 容器
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
/**
* entity 屬性注入,構造器注入,對象引用,集合,SpEL,(重點)
* entity2 自動裝配和P命名空間
* entity3 繼承和依賴,作用域
*/
// 2. 從 IOC 容器中獲取 bean 的實例
Entity entity = (Entity) ctx.getBean("entity");
// 3. 使用 bean
System.out.println(entity.toString());
// System.out.println(ctx.getBean("entity") == ctx.getBean("entity")); 使用 prototype 打印的是false
ctx.close();
}
}
Entity [intValue=1, floatValue=1.1, stringValue=<ITDragon>, spELEntity=SpELEntity [intSpel=1, floatSpel=1.2, bSpel=true, stringSpel=Spring4基礎教程], mapValue={one=1, two=2}, listValue=[歡迎閱讀, ITDragon, 的博客!]]
基於注解的Bean配置
相對於xml的配置,注解的方式顯得異常簡單。主要分兩個步驟
第一步:在applicationContext.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:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
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/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 配置自動掃描指定目錄下的包
resource-pattern="xxx/*.class" 屬性過濾特定的類
-->
<context:component-scan base-package="com.itdragon.spring.my" >
<!-- annotation 是針對指定的類 和 assignable 是針對所有繼承或者擴展該類的類-->
<!-- context:exclude-filter 只排除expression里面的內容
<context:exclude-filter type="annotation" expression=""/>
-->
<!-- context:include-filter 只包含expression里面的內容
需配合 use-default-filters="false"(默認是true) 一起使用
<context:include-filter type="annotation" expression=""/>
-->
</context:component-scan>
</beans>
第二步:在對象上用注解。這四幾個注解的作用一樣,只是為了結構清晰,取的名字不同罷了。
使用方法很簡單:直接在類上加注解即可。無參數的情況,bean的id默認是小寫字母開頭的類名。也可以指定參數@Commponent("指定參數"),那bean的id就是指定參數。
@Component: 基本注解, 標識了一個受 Spring 管理的組件
@Respository: 標識持久層組件
@Service: 標識服務層(業務層)組件
@Controller: 標識表現層組件
public interface AnnoRepository {
public void hello();
}
import org.springframework.stereotype.Repository;
@Repository
public class AnnoRepositoryImp implements AnnoRepository{
@Override
public void hello() {
System.out.println("AnnoRepository : hello!");
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class AnnoService {
@Autowired
private AnnoRepository annoRepository;
public void hello() {
System.out.println("AnnoService : hello!");
annoRepository.hello();
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class AnnoController {
@Autowired
private AnnoService annoService;
public void execut() {
System.out.println("AnnoController : hello !");
annoService.hello();
}
}
這里還有一個注解Autowired, context:component-scan 元素會自動組件裝配被Autowired修飾的對象。
測試類:雖然applicationContext.xml中沒有annoController的bean配置,但我們有注解!
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
AnnoController annoController = (AnnoController) ctx.getBean("annoController");
annoController.execut();
ctx.close();
}
}
AnnoController : hello !
AnnoService : hello!
AnnoRepository : hello!
有沒有覺得基於注解的bean配置比基於xml的bean配置簡單很多。
IOC容器Bean的生命周期
- step1 實例化,通過構造器創建 Bean 實例
- step2 賦值,為 Bean 的屬性設置值
- step3 init-method,調用 Bean 的初始化方法(init-method)
- step4 destroy-method,當容器關閉時, 調用 Bean 的銷毀方法(destroy-method)
以上代碼都是筆者親測可用的,不要嫌麻煩,麻煩是學不好的,如果有什么問題和建議可以留言,我會及時處理。http://blog.csdn.net/qq_19558705/article/details/49994191