注意!!
此篇博文和上一篇博文有一些關聯,如已經建立好的各種類的位置,如果對于類的位置不清楚請看上一篇博文
【Spring 4.0】Spring入門之第一個程式HelloWorld實作
一、關于IOC和DI
**IOC(Inversion of Control)控制反轉:**其思想是反轉資源擷取的方向. 傳統的資源查找方式要求元件向容器發起請求查找資源. 作為回應, 容器适時的傳回資源. 而應用了 IOC 之後, 則是容器主動地将資源推送給它所管理的元件, 元件所要做的僅是選擇一種合适的方式來接受資源. 這種行為也被稱為查找的被動形式
DI(Dependency Injection)依賴注入: IOC 的另一種表述方式:即元件以一些預先定義好的方式(例如: setter 方法)接受來自如容器的資源注入. 相對于 IOC 而言,這種表述更直接。
二、Bean的配置
(1)建立一個名為 HelloWorld
的JavaBean
HelloWorld
(如果按照上一篇博文過來的朋友則不用做Bean的配置了,隻需看一下解釋就好。因為我是以上一篇的HelloWorld執行個體來講解的)
public class HelloWorld {
private String user;
public HelloWorld() {
System.out.println("HelloWorld's constructor...");
}
public void setUser(String user) {
System.out.println("setUser:" + user);
this.user = user;
}
public HelloWorld(String user) {
this.user = user;
}
public void hello(){
System.out.println("Hello: " + user);
}
}
HelloWorld.Java
(2)在 applicationContext
中為Bean中的屬性指派
applicationContext
<bean id="helloWorld" class="com.spring.helloworld.HelloWorld">
<!-- 為屬性指派 -->
<property name="user" value="Jerry"></property>
</bean>
屬性解釋:
屬性 | 屬性值 |
---|---|
class | bean 的 指的是HelloWorld的全路徑名稱,并且由于是通過反射方式建立Bean,是以Bean中必須有無參的構造器。如果沒有無參構造器則會出錯,當然如果沒有顯示聲明構造器也無妨,因為虛拟機會隐式建立一個無參的構造器。 |
id | 當建立好一個bean之後,如何引用這個bean呢?就需要使用id.它辨別bean.并且id唯一。id:Bean 的名稱:(1)在 IOC 容器中必須是唯一的。(2)若 id 沒有指定,Spring 自動将權限定性類名作為 Bean 的名字。(3)id 可以指定多個名字,名字之間可用逗号、分号、或空格分隔。 |
(3)在 Main.java
中通過容器讀出資料
Main.java
//1. 建立 Spring 的 IOC 容器
//ApplicationContext:代表IOC容器
//ClassPathXmlApplicationContext:是ApplicationContext接口的實作類
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2. 從 IOC 容器中擷取 bean 的執行個體
HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");
//根據類型來擷取 bean 的執行個體: 要求在 IOC 容器中隻有一個與之類型比對的 bean, 若有多個則會抛出異常.
//一般情況下, 該方法可用, 因為一般情況下, 在一個 IOC 容器中一個類型對應的 bean 也隻有一個.
// HelloWorld helloWorld1 = ctx.getBean(HelloWorld.class);
//3. 使用 bean
helloWorld.hello();
注意!
在 Spring IOC 容器讀取 Bean 配置建立 Bean 執行個體之前, 必須對它進行執行個體化. 隻有在容器執行個體化後, 才可以從 IOC 容器裡擷取 Bean 執行個體并使用。
三、屬性注入方式
在Spring中,支援三種依賴注入的方式
(1)屬性注入
<!-- 配置一個 bean -->
<bean id="helloWorld2" class="com.spring.helloworld.HelloWorld">
<!-- 為屬性指派 -->
<!-- 通過屬性注入: 通過 setter 方法注入屬性值 -->
<property name="user" value="Tom"></property>
</bean>
- 屬性注入即通過 setter 方法注入Bean 的屬性值或依賴的對象
- 屬性注入使用
元素, 使用<property>
屬性指定 Bean 的屬性名稱,name
屬性或 子節點指定屬性值value
- 屬性注入是實際應用中最常用的注入方式
(2)構造器注入
示範:
1.添加Car類
public class Car {
private String company;
private String brand;
private int maxSpeed;
private float price;
public Car(String company, String brand, float price) {
super();
this.company = company;
this.brand = brand;
this.price = price;
}
public Car(String company, String brand, int maxSpeed) {
super();
this.company = company;
this.brand = brand;
this.maxSpeed = maxSpeed;
}
public Car(String company, String brand, int maxSpeed, float price) {
super();
this.company = company;
this.brand = brand;
this.maxSpeed = maxSpeed;
this.price = price;
}
@Override
public String toString() {
return "Car [company=" + company + ", brand=" + brand + ", maxSpeed="
+ maxSpeed + ", price=" + price + "]";
}
}
2.配置bean:
<!-- 若一個 bean 有多個構造器, 如何通過構造器來為 bean 的屬性指派? -->
<!-- 可以根據 index 和 value 進行更加精确的定位. -->
<bean id="car" class="com.spring.helloworld.Car">
<constructor-arg value="KUGA" ></constructor-arg>
<constructor-arg value="ChangAnFord" ></constructor-arg>
<constructor-arg value="250000" ></constructor-arg>
</bean>
3.主方法調用:
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Car car = (Car) ctx.getBean("car");
System.out.println(car);
4.結果
注意!
上面的構造器隻是為了其中的前三個屬性進行初始化,bean中的配置其實是按照順序來初始化的,當然如果構造器非常多,如何對bean進行配置呢?
public Car(String company, String brand, float price) {
super();
this.company = company;
this.brand = brand;
this.price = price;
}
public Car(String company, String brand, int maxSpeed) {
super();
this.company = company;
this.brand = brand;
this.maxSpeed = maxSpeed;
}
(在Car類中增添兩個構造器)
解決方案:
<bean id="car" class="com.spring.helloworld.Car">
<constructor-arg value="KUGA" index="1"></constructor-arg>
<constructor-arg value="ChangAnFord" index="0"></constructor-arg>
<constructor-arg value="250000" type="float"></constructor-arg>
</bean>
<bean id="car3" class="com.spring.helloworld.Car">
<constructor-arg value="BAOMA" type="java.lang.String"></constructor-arg>
<constructor-arg value="ChangAnFord" type="java.lang.String"></constructor-arg>
<constructor-arg value="250000" type="int"></constructor-arg>
</bean>
- (1)可以建立
:index
<constructor-arg value="audi" index="0"></constructor-arg>
- (2)構造函數也是重載的,區分重載的是參數個數和類型,個數不同好辦,相同的時候就可以在後面注明類型。
**(使用`type`來注明類型) ** 結果:
四、注入屬性值細節
(1)特殊字元
字面值:可用字元串表示的值,可以通過
<value>
元素标簽或 value 屬性進行注入。基本資料類型及其封裝類、String 等類型都可以采取字面值注入的方式。若字面值中包含特殊字元,如有尖括号<>等等,可以使用
<![CDATA[]]>
把字面值包裹起來。
<bean id="car2" class="com.spring.helloworld.Car">
<constructor-arg value="ChangAnMazda"></constructor-arg>
<!--
字面值也可以通過 <value> 元素标簽
若字面值中包含特殊字元, 則可以使用 DCDATA 來進行指派. (了解)
-->
<constructor-arg>
<value><![CDATA[<ATARZA>]]></value>
</constructor-arg>
<constructor-arg value="180" type="int"></constructor-arg>
</bean>
(2)引用其他的Bean
組成應用程式的 Bean 經常需要互相協作以完成應用程式的功能。要使 Bean 能夠互相通路, 就必須在 Bean 配置檔案中指定對 Bean 的引用。在 Bean 的配置檔案中, 可以通過
<ref>
元素或 ref 屬性為 Bean 的屬性或構造器參數指定對 Bean 的引用。也可以在屬性或構造器裡包含 Bean 的聲明, 這樣的 Bean 稱為内部 Bean。
<!-- 配置 bean -->
<bean id="dao5" class="com.spring.ref.Dao"></bean>
<bean id="service" class="com.spring.ref.Service">
<!-- 通過 ref 屬性值指定目前屬性指向哪一個 bean! -->
<property name="dao" ref="dao5"></property>
</bean>
(3)内部Bean
當 Bean 執行個體僅僅給一個特定的屬性使用時, 可以将其聲明為内部 Bean. 内部 Bean 聲明直接包含在
<property>
或
<constructor-arg>
元素裡, 不需要設定任何 id 或 name 屬性。内部 Bean 不能使用在任何其他地方。
<!-- 聲明使用内部 bean -->
<bean id="service2" class="com.spring.ref.Service">
<property name="dao">
<!-- 内部 bean, 類似于匿名内部類對象. 不能被外部的 bean 來引用, 也沒有必要設定 id 屬性 -->
<bean class="com.spring.ref.Dao">
<property name="dataSource" value="c3p0"></property>
</bean>
</property>
</bean>
(4)Null值
可以使用專用的
<null/>
元素标簽為 Bean 的字元串或其它對象類型的屬性注入 null 值。
<bean id="dao2" class="com.spring.ref.Dao">
<!-- 為 Dao 的 dataSource 屬性指派為 null, 若某一個 bean
的屬性值不是 null, 使用時需要為其設定為 null(了解) -->
<property name="dataSource"><null/></property>
</bean>
(5)級聯屬性
和 Struts、Hiberante 等架構一樣,Spring 支援級聯屬性的配置。
<bean id="action" class="com.spring.ref.Action">
<property name="service" ref="service2"></property>
<!-- 設定級聯屬性 -->
<property name="service.dao.dataSource" value="DBCP2"></property>
</bean>
(6)集合屬性
在 Spring中可以通過一組内置的 xml 标簽(例如:
<list>
,
<set>
或
<map>
) 來配置集合屬性
1.配置 java.util.List
類型的屬性
java.util.List
需要指定
<list>
标簽, 在标簽裡包含一些元素. 這些标簽可以通過
<value>
指定簡單的常量值, 通過
<ref>
指定對其他 Bean 的引用. 通過
<bean>
指定内置 Bean 定義. 通過
<null/>
指定空元素. 甚至可以内嵌其他集合。
<!-- 裝配集合屬性 -->
<bean id="user" class="com.spring.helloworld.User">
<property name="userName" value="Jack"></property>
<property name="cars">
<!-- 使用 list 元素來裝配集合屬性 -->
<list>
<ref bean="car"/>
<ref bean="car2"/>
</list>
</property>
</bean>
注意!
數組的定義和 List 一樣, 都使用
<list>
2.配置 java.util.Set
類型的屬性
java.util.Set
java.util.Map
通過
<map>
标簽定義,
<map>
标簽裡可以使用多個
<entry>
作為子标簽. 每個條目包含一個鍵和一個值。
<bean id="user7" class="com.spring.helloworld.User">
<property name="userName" value="Rose"></property>
<property name="wifeName" value="JACK"></property>
<!-- 使用 Map 元素來裝配集合屬性 -->
<property name="carmap">
<map>
<entry key="AA" value-ref="car"></entry>
<entry key="BB" value-ref="car"></entry>
</map>
</property>
</bean>
注意!
- 必須在
标簽裡定義鍵<key>
- 因為鍵和值的類型沒有限制, 是以可以自由地為它們指定
,<value>
,<ref>
或<bean>
元素。<null>
- 可以将 Map 的鍵和值作為
的屬性定義: 簡單常量使用<entry>
和key
來定義; Bean 引用通過value
和key-ref
屬性定義。value-ref
3.配置 java.util.Properties
類型的屬性
java.util.Properties
使用
<props>
定義
java.util.Properties
, 該标簽使用多個
<prop>
作為子标簽. 每個
<prop>
标簽必須定義
key
屬性.實際應用于配置資料庫連接配接池。
第一步:建立DataSource類
import java.util.Properties;
public class DataSource {
private Properties properties;
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "DataSoure [properties=" + properties +"]" ;
}
}
第二步:配置bean
<bean id="dataSource" class="com.spring.helloworld.DataSource">
<property name="properties" >
<props>
<prop key="user">rout</prop>
<prop key="password">rout</prop>
<prop key="jdbcUrl">jdbc:mysql://localhost/hibernate</prop>
<prop key="driverClass">com.mysql.jdbc.Driver</prop>
</props>
</property>
</bean>
第三步:列印相關資訊
DataSource dataSource = (DataSource) ctx.getBean("dataSource");
System.out.println(dataSource);
第四步:結果
DataSoure[properties={driverClass=com.mysql.jdbc.Driver, user=rout, password=rout, jdbcUrl=jdbc:mysql://localhost/hibernate}]
4.使用 utility scheme
定義集合
utility scheme
使用基本的集合标簽定義集合時, 不能将集合作為獨立的 Bean 定義, 導緻其他 Bean 無法引用該集合, 是以無法在不同 Bean 之間共享集合.。可以使用 util schema 裡的集合标簽定義獨立的集合 Bean. 需要注意的是, 必須在
<beans>
根元素裡添加 util schema 定義。
第一步:導入util命名空間
打開
applicationContext
如圖按順序設定
第二步:使用
util:list
聲明集合類型的 bean
<!-- 聲明集合類型的 bean -->
<util:list id="cars">
<ref bean="car"/>
<ref bean="car2"/>
</util:list>
<bean id="user2" class="com.spring.helloworld.User">
<property name="userName" value="Rose"></property>
<!-- 引用外部聲明的 list -->
<property name="cars" ref="cars"></property>
</bean>
5.使用 p 命名空間
為了簡化 XML 檔案的配置,越來越多的 XML 檔案采用屬性而非子元素配置資訊。Spring 從 2.5 版本開始引入了一個新的 p 命名空間,可以通過
<bean>
元素屬性的方式配置 Bean 的屬性。使用 p 命名空間後,基于 XML 的配置方式将進一步簡化。
<!-- 通過p命名空間為bean的屬性指派,需要導入p命名空間 -->
<bean id="user3" class="com.spring.helloworld.User"
p:cars-ref="cars" p:userName="Titannic"></bean>