## 4.4 依賴
典型的企業級應用程序不是由單獨對象(或 Spring 中的 bean)構成的。盡管最簡單的 應用程序有一些對象協同工作來表示終端用戶所看到的連貫的應用。下一節會解釋如何去為 完全實現的應用程序定義一組獨立的 bean,其中對象間相互協作來達到目標。
### 4.4.1 依賴注入
依賴注入(DI)是對象定義它們依賴的過程,也就是說,要和它們協同工作其它對象, 僅僅可以通過構造方法參數,工廠方法參數,或者是在工廠方法返回的對象或被構造好后,
為對象實例設置的屬性。容器當創建好 bean,隨后就會注入那些依賴。這個過程從根本上 來說是反向的,因此命名為控制反轉(IoC),bea n 本身直接使用構造好的類或服務定位器 模式來控制實例或它的依賴的所在位置。
應用了 DI 原則,代碼就干凈多了,當為對象提供它們依賴的時候,解耦是很有效率的。
對象不再去檢查它的依賴,也不需要知道位置或依賴的類。因此,類就很容易被測試,特別 是當依賴是接口或抽象基類的時候,這允許在單元測試中使用 stub 或 mock 的實現類。
DI 存在兩種主要的方式,基于構造方法的依賴注入(4.4.1.1 節)和基于 setter 方法的依賴注入(4.4.1.2 節)。
#### 4.4.1.1 基于構造方法的依賴注入
基于構造方法的依賴注入是容器調用構造方法和一組參數完成的,每個都表示著一個依 賴。使用特定的參數來調用 static 工廠方法構造 bean 基本也是相同的,這種說法把給構 造方法的參數和給 static 工廠方法的參數相類似。下面的示例展示了一個僅使用構造方 法進行依賴注入的餓類。注意這個類沒有什么特殊之處,就是一個 POJO 而且沒有對容器特 定接口,基類或注解的依賴。
```
public class SimpleMovieLister {
// SimpleMovieLister對MovieFinder有依賴
private MovieFinder movieFinder;
// 這個構造方法使得Spring容器可以’注入’MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// 業務邏輯就可以’使用’注入的MovieFinder了,代碼就省略了...
}
```
構造方法參數解析
構造方法參數解析匹配使用參數的類型。如果在 bean 的構造方法參數不存在潛在的歧義,那么當 bean 被實例化的時候,定義的構造方法參數的順序就是被提供到適當構造方法 參數的順序。請看下面的類:
```
package x.y;
public class Foo {
public Foo(Bar bar, Baz baz) {
// ...
}
}
```
沒有潛在的歧義存在,假設 Bar 和 Baz 類沒有繼承關系。因此下面的配置就可以使用 了,而且并不需要明確地在`<constructor-arg/>`元素中去指定構造方法參數的索引和/ 或類型。
```
<beans>
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
</bean>
<bean id="bar" class="x.y.Bar"/>
<bean id="baz" class="x.y.Baz"/>
</beans>
```
當另外一個 bean 被引用時,類型是明確的,那么匹配就能成功(前面示例中也是這樣 的)。當使用簡單類型時,比如`<value>true<value>`,Spring 不能決定值的類型,所以 沒有幫助是不能匹配的。看下面的示例:
```
package examples;
public class ExampleBean {
//計算最佳答案的年數
private int years;
// 生命,宇宙,所有問題的答案
private String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
```
構造方法參數類型匹配
在上面的情形下,如果你使用 type 屬性明確地為構造方法參數指定類型的話,容器可 以進行匹配簡單的類型。比如:
```
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
```
構造方法參數索引
使用 index 屬性來指定明確的構造方法參數索引。比如:
```
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
```
此外,為了解決多個簡單值的歧義,如果構造方法有兩個相同類型的參數時,指定所以 可以解決歧義。注意索引是基于 0 開始的。
構造方法參數名稱
在 Spring 3.0 中,你也可以使用構造方法參數名稱來消除歧義:
```
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateanswer" value="42"/>
</bean>
```
要記住要使得這種方式可用,代碼必須和內嵌的調試標識一起編譯,那樣 Spring 才可 以從構造方法中來查找參數。如果沒有和調試標識(或不想)一起編譯,那么可以使用 JDK 的注解[@ConstructorProperties](http://download.oracle.com/javase/6/docs/api/java/beans/ConstructorProperties.html) 來明確構造方法參數。那么示例代碼就如下所示:
```
package examples;
public class ExampleBean {
// 忽略屬性
@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
```
#### 4.4.1.2 基于 setter 方法的依賴注入
基于 setter 方法的依賴注入由容器在調用過無參數的構造方法或無參數的 static 工廠 方法來實例化 bean 之后,再調用 bean 的 setter 方法來完成的。
下面的示例展示了一個僅僅能使用純 setter 方法進行依賴注入的類。這是一個常見的 Java 類,是一個沒有依賴容器指定的接口,基類或注解的 POJO。
```
public class SimpleMovieLister {
// SimpleMovieLister對MovieFinder有依賴
private MovieFinder movieFinder;
// setter方法可以讓Spring容器來'注入'MovieFinder
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// 真正’使用’注入的MovieFinder的業務邏輯代碼被省略了...
}
```
ApplicationContext 對它管理的 bea n 支持基于構造方法和 setter 方法的依賴注入。
也 支 持 在 一 些 依 賴 已 經 通 過 構 造 方 法 注 入 之 后 再 進 行 setter 方 法 注 入 。 以
BeanDefinition 形式來配置依賴,使用 PropertyEditor 實例將屬性從一種形式格式 化到另一種。但很多 Spring 的用戶不直接(編程時)使用這些類,而是使用 XML 文件來定 義,之后會在內部轉換這些類的實例,需要加載整個 Spring IoC 容器的實例。
基于構造方法還是 setter 方法進行依賴注入? 因為你可以將二者混淆,那么對于基于構造方法或是 setter 方法的依賴注入,有一個很好的規則就是為強制依賴使用構造方法參數,而對于可選參數使用 setter 方法。要注意在 setter 方法上使用注解@Required(4.9.1 節),可用于 setter 方法所需的依賴。
Spring 團隊通常主張使用 setter 方法注入,因為大量的構造方法參數會使程序變得非 常笨拙,特別是當屬性為可選的時候。Setter 方法會讓該類的對象今后適合于重新配置或 重新注入。通過 JMX Mbean(第 23 章)來管理就是一個令人關注的用例。
一些人純粹贊成構造方法注入。提供所有對象的依賴意味著對象在完全初始化狀態 時,通常要返回客戶端(調用)代碼。這個缺點會使得對象變得不適合去重新配置或重新注入。
使用依賴注入的時候要特別注意一些類。當要選擇處理沒有源代碼時的第三方類庫 的時候。遺留的類可能沒有暴露任何 setter 方法,而構造方法注入則是唯一可用的依賴 注入方式。
#### 4.4.1.3 解決依賴過程
容器按如下步驟來解決 bean 的依賴:
1. ApplicationContext 和描述了所有 bean 的配置元數據一起被創建并初始化。配 置元數據可以通過 XML,Java 代碼或注解來指定。
2. 對于每一個 bean 來說,它的依賴被表述為屬性,構造方法參數的形式,如果你使用 了靜態工廠方法來代替構造方法,那么還會是靜態工廠方法參數的形式。當 bean 被實際創 建時,這些依賴被提供給 bean。
3. 每個屬性或構造方法參數就是一個要被設置的值或者是容器中其它 bean 的引用。
4. 每個屬性或構造方法參數值會被轉換特定格式的形式,去匹配屬性或構造方法參數的類型。默認情況下,Spring 可以轉換給定的字符串格式的值到內建的類型,比如 int,long, String,boolean 等。
當容器被創建時,Spring 容器會來驗證每個 bean 的配置,包括驗證 bean 的引用屬性是 否是一個合法的 bean。然而,bean 屬性本身直到 bean 真正被創建出來后才被設置進去。 當容器被創建時,bean 的范圍是單例時,會被設置成預實例(默認情況)來創建。范圍在 4.5 節,“bean 的范圍”部分來解釋。否則,bean 就會當被請求的時候被創建。一個 bean 的創建潛在地會引起一系列 bean 被創建,因為 bean 的依賴和它依賴的依賴(等等)要不 創建和定義出來。
循環依賴 如果你使用主要的構造方法注入,就可能會引起不可解決的循環依賴情形。 比如,類 A 需要通過構造方法注入獲得類 B 的實例,而類 B 也需要通過構造方法注入獲得類 A 的實例。如果把類 A 和類 B 進行相互注入,Spring 的 IoC 容器會在運行時檢 測到這是循環引用的情況,并且拋出 BeanCurrentlyInCreationException 異常。
一個可行的方案是編輯一些要配置的類的源碼,通過 setter 方法而不是構造方法進 行注入。而且,避免構造方法注入并僅僅使用 setter 方法注入。換句話說,盡管這不是推薦做法,你可以通過 setter 方法注入來配置循環依賴。
不像典型的用例(沒有循環依賴),在 bean A 和 bean B 之間的循環依賴強制一個 bean 被注入到另一個中會先于被完全初始化自己(就是經典的雞和蛋的問題)。
通常情況下你可以信任 Spring 做出正確的事情。它會在容器加載時來檢測配置問題, 比如引用了一個不存在的 bean 和循環依賴問題。當 bean 被實際創建出來后,Spring 設置屬 性和解決依賴會盡量地晚些。這就意味著 Spring 容器已經加載正確了但晚些時候可能會生 成異常,比如當你請求一個創建時發生問題的對象或者是它的依賴發送問題。例如,bean 因為丟失或非法屬性而拋出異常。這種潛在的一些配置問題的可見度延遲也就是為什么 ApplicationContext 的實現類默認情況都是預實例的單例 bean。在前期的時間和內存 消耗中,在 bean 真正需要前來創建這些 bean,當 ApplicationContext 被創建的時候, 你會發現這些配置問題,這還不晚。你也可以覆蓋這個默認的行為,那么單例 bean 就會延 遲加載,而不是預實例的了。
如果沒有循環依賴的存在,當一個或多個協作的 bean 被注入到一個獨立的 bean 時, 每個協作的 bean 就會在被注入之前完全被配置好。這就意味著如果 bean A 對 bean B 有依 賴,那么 Spring 的 IoC 容器會完全配置 bean B 而優先于調用 bean A 中的 setter 方法。換句 話說,bean 被實例化了(而不是預實例的單例 bean),它的依賴才被注入,相關的生命周 期方法(比如配置初始化方法(4.6.1.1 節)或 InitializingBea n 的回調方法(4.6.1.1 節))才 被調用。
#### 4.4.1.4 依賴注入示例
下面的示例使用了基于 XML 的配置元數據來進行基于 setter 方法的依賴注入。Spring XML 配置文件的一小部分來指定幾個 bean 的定義:
```
<bean id="exampleBean" class="examples.ExampleBean">
<!-- 使用嵌入<ref/>的元素來進行setter方法注入<ref/> -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<!-- 使用整潔的'ref'屬性來進行setter方法注入-->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i;
public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
}
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
}
public void setIntegerProperty(int i) {
this.i = i;
}
}
```
上面的示例中,setter 方法被聲明為匹配 XML 文件中指定的屬性。下面的示例使用基于 構造方法的依賴注入:
```
<bean id="exampleBean" class="examples.ExampleBean">
<!-- 使用嵌入的<ref/>元素進行構造方法注入 -->
<constructor-arg>
<ref bean="anotherExampleBean"/>
</constructor-arg>
<!-- 使用整潔的'ref'屬性來進行構造方法注入 -->
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg type="int" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i;
public ExampleBean(AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
this.beanOne = anotherBean;
this.beanTwo = yetAnotherBean;
this.i = i;
}
}
```
在 bean 中指定的構造方法參數會被用于 ExampleBean 的構造方法參數。 現在考慮一下這個示例的變化情況,要代替使用構造方法,Spring 被告知調用 static
工廠方法并返回一個對象的實例:
```
<bean id="exampleBean" class="examples.ExampleBean" factory-method="createInstance">
<constructor-arg ref="anotherExampleBean"/>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
// 私有的構造方法
private ExampleBean(...) {
...
}
// 靜態工廠方法; 這個方法的參數可以被認為是要返回bean的依賴,
// 而不管那些參數是如何被使用的。
public static ExampleBean createInstance (AnotherBean anotherBean,
YetAnotherBean yetAnotherBean, int i) {
ExampleBean eb = new ExampleBean (...);
// 其它的操作...
return eb;
}
}
```
static 工廠方法的參數通過`<constructor-arg/>`元素來提供,這和構造方法已經 被實際調用是完全一致的。由工廠方法返回的類的類型不需要和包含 static 工廠方法類 的類型相同,盡管在本例中是相同的。實例(非靜態)工廠方法可以被用于本質上相同的方 式(除了 factory-bean 屬性的使用,來代替 class 屬性),所以這里不討論它們的細節。
### 4.4.2 深入依賴和配置
正如之前章節中所提到的,你可以定義 bean 的屬性和構造方法參數作為其它被管理 bean(協作者)的引用,或者作為內聯值的定義。出于這個目的,Spring 的基于 XML 的配 置元數據支持使用`<property/>`和`<constructor-arg/>`元素的子元素類型。
#### 4.4.2.1 直接值(原生類型,String,等)
<property/>元素的 value 屬性指定了屬性或構造方法參數,這是人們可以閱讀的 字符串的表達。正如之前提到過的(6.4.2 節),JavaBean 的 PropertyEditor 可以用來轉 換這些字符串值從 String 到屬性或參數的真實類型。
```
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- setDriverClassName(String)方法調用的結果 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="masterkaoli"/>
</bean>
```
對于更簡潔的 XML 配置,下面的示例使用了 p-命名空間(4.4.2.6 節)。
```
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring -beans-3.0.xs d">
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3306/mydb" p:username="root" p:password="masterkaoli"/>
</beans>
```
上面的 XML 非常簡潔;然而,錯誤之處會在運行時被發現而不是設計的時候,除非在 你創建 bean 的時候,使用如 [IntelliJ IDEA](http://www.jetbrains.com/idea/) [或](http://www.springsource.com/products/sts) [SpringSource Tool Suite](http://www.springsource.com/products/sts)(STS,SpringSource 組織 開發的工具套件)這樣的 IDE 來支持自動地屬性補全。這樣的 IDE 幫助是強烈建議使用的。
你也可以這樣來配置 java.util.Properties 實例:
```
<bean id="mappings" class="org.springframework.beans.factory.config.PropertyPlac
eholderConfigurer">
<!-- 作為java.util.Properties類型 -->
<property name="properties">
<value>
jdbc.driver.className=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
</property>
</bean>
```
Spring 容器會使用 JavaBean 的 PropertyEditor 機制來轉換`<value/>`元素中的文本 到 java.util.Properties 實例。這是一個很好的捷徑,也是 Spring 團隊少有喜歡使用 嵌套的`<value/>`元素而不是 value 屬性方式的地方之一。
idref 元素
idref 元素是一種簡單防錯的形式來傳遞容器中另外一個 bean 的 id(字符串值而不是引用)到`<constructor-arg/>`或`<property/>`元素中。
```
<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean" />
</property>
</bean>
```
上面定義 bean 的代碼片段是和下面的片段完全等價(在運行時):
```
<bean id="theTargetBean" class="..." />
<bean id="client" class="...">
<property name="targetName" value="theTargetBean" />
</bean>
```
第一種形式比第二種形式可取,因為使用 idref 標簽允許容器在部署時來驗證被引用 的,命名的 bean 是否真的存在。第二種形式下,沒有對傳遞給 client bea n 的 targetName 屬性執行驗證。錯誤僅僅是在 client bean 被真正實例化的時候才會被發現(和很多可能 致命的結果)。如果 client bean 是 prototype(4.5 節)類型的 bean,這個錯誤和結果異常 可能僅僅在容器被部署很長一段時間后才會被發現。
此外,如果被引用的 bean 在同一個 XML 單元中,bean 的名稱就是 bean 的 id,那么你 還可以使用 local 屬性,這允許 XML 解析器本身在 XML 文檔解析的時候,及早地來驗證 bean 的 id。
```
<property name="targetName">
<!-- id為'theTargetBean'的bean必須存在;否則就會拋出異常 -->
<idref local="theTargetBean"/>
</property>
```
`<idref/>` 元 素 帶 來 的 一 個 相 同 之 處 ( 最 少 是 Spring 2.0 版 本 以 前 的 ) 是 值 在 ProxyFactoryBean 定義的 AOP 攔截器的配置中。當你指定攔截器名稱來防止拼錯攔截 器的 id 時,可以使用`<idref/>`元素。
#### 4.4.2.2 引用其它 bean(協作者)
ref 元素是`<constructor-arg/>`或`<property/>`定義元素中最后的一個。在這里 你可以為 bean 設置指定屬性的值,來引用被容器管理的另外一個 bean(協作者)。被引用 的 bean 就是要設置屬性的這個 bean 的一個依賴,并且是初始化的作為屬性設置之前的點 播。(如果協作者是一個單例的 bean,它可能已經被容器初始化過了。)所有引用最終都會 被引用到一個對象中。范圍和驗證基于通過 bean,local 或 parent 屬性指定 id/name 的其它對象。
通過`<ref/>`標簽的 bean 屬性來指定目標 bean 是最常用的方式,并允許創建引用到相 同容器或父容器的任意 bean 中,而不管它們是不是在同一個 XML 文件中。bean 屬性的值 可能和目標 bean 的 id 屬性相同,或者是目標 bean 的 name 屬性值之一。
```
<ref bean="someBean"/>
```
通過 local 屬性來指定目標 bean 是利用了 XML 解析器的能力,來驗證 XML 相同文件 內的 id 引用。local 屬性的值必須和目標 bean 的 id 屬性一致。如果沒有在相同的文件內 發現匹配的元素,那么 XML 解析器會報告問題。因此,如果目標 bean 在同一個 XML 文件 中的話,使用 local 這種形式是最佳選擇(為了更早地知道錯誤)。
```
<ref local="someBean"/>
```
通過 parent 屬性來指定目標 bea n 會為 bea n 創建引用,它是在當前容器的父容器中的。parent 屬性的值可能和目標 bean 的 id 屬性相同,或者是目標 bean 的 name 屬性值 之一,而且目標 bean 必須在當前容器的父容器中。當有一個容器繼承關系,可以使用這個 bean 的引用,或在你想使用和父 bean 有相同名稱的代理包裝一個父容器中已有 bean 時。
```
<!-- 在父上下文中-->
<bean id="accountService" class="com.foo.SimpleAccountService">
<!-- 在這里插入所需要的依賴 -->
</bean>
<!-- 在子(后繼)上下文中 -->
<bean id="accountService" <-- bean名稱和父bean相同 -->
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref parent="accountService"/>
<!-- 注意我們如何引用父bean -->
</property>
<!-- 在這里插入其它配置和所需的依賴 -->
</bean>
```
#### 4.4.2.3 內部 bean
在`<property/>`或`<constructor-arg/>`元素內部的`<bean/>`元素的定義被稱為內部 bean。
```
<bean id="outer" class="...">
<!-- 為了替代為目標bean使用引用,簡單內聯定義目標bean -->
<property name="target">
<bean class="com.example.Person"> <!-- 這就是內部bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>
```
內部 bean 的定義不需要定義 id 或 name;容器忽略這些值。也會忽略 scope 標識。內 部 bean 通常是匿名的,而且范圍通常是 prototype(4.5.2 節)的。注入內部 bean 到協作 bean 是不可能的,只能到包圍它的 bean 中。
#### 4.4.2.4 集合
在 `<list/>` , `<set/>` , `<map/>` 和 `<props/>` 元素中,你可以分別設置 Java 的 Collection 類型 List,Set,Map 和 Properties 的屬性和參數。
```
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop
key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
```
Map 類型的 key 或 value 的值,或 set 的值,也可以是下列元素之一:
+ bean
+ ref
+ idref
+ list
+ set
+ map
+ props
+ value
+ null
集合合并
在 Spring 2.0 中,容器支持集合的合并。應用開發人員可以定義父樣式的`<list/>`,`<map/>`,`<set/>`或`<props/>`元素,子樣式的`<list/>`,`<map/>`,`<set/>`或`<props/>`元素繼承或重寫來自父集合的值。也就是說,子集合的值是合并元素父與子集合中的元素,和子集合元素覆蓋父集合中指定值的結果。
本節關于導論父子 bean 合并的機制。如果讀者不熟悉父和子 bean 的定義,可能要先去 閱讀一下相關章節(4.7 節)。
下面的示例說明了集合合并:
```
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop
key="administrator">administrator@example.com</prop>
<prop key="support">support@example.com</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- 合并在*子*集合定義中來指定 definition -->
<props merge="true">
<prop key="sales">sales@example.com</prop>
<prop key="support">support@example.co.uk</prop>
</props>
</property>
</bean>
<beans>
```
注意在 child bean 中的 adminEmails 屬性下的`<props/>`元素中的 merge=true 屬性的使用。當 child bean 被容器處理并實例化時,結果實例中有一個 adminEmails Properties 的 集 合 , 包 含 了 合 并 子 bean 的 adminEmails 集合和父 bean 的 adminEmails 集合。
```
administrator=administrator@example.com
sales=sales@example.com
support=support@example.co.uk
```
子 bean 的 Properties 集合的值設置繼承了從父`<props/>`元素而來的所有屬性,子 bean 中 support 的值覆蓋了父 bean 中的值。
這種合并行為的應用和`<list/>`,`<map/>`和`<set/>`集合類型很相似。在`<list/>`元素特 定的情形下,和 List 集合類型相關的語義,也就是說,ordered 集合值的概念,是要維 護的;父值優先于所有子 list 的值。在 Map,Set 和 Properties 集合類型的情況下,沒有順序的存在。因此對于容器內部使用的,和 Map,Set 和 Properties 實現類型相關的 集合類型沒有排序語義的作用。
集合合并的限制
不能合并不同類型的集合(比如 Map 和 List),如果你要嘗試這么去做,那么就會拋 出 Exception。merge 屬性必須在低級的,繼承的,子 bean 中來指定;在父集合中指定 merge 屬性是冗余的,也不會看到想要的合并結果。合并特性僅在 Spring 2.0 和更高版本中 可用。
強類型集合(Java 5 以上版本)
在 Java 5 或更高版本中,你可以使用強類型集合(使用泛型)。也就是說,可以聲明一 個 Collection 類型,它可以僅僅包含 String 元素(作為示例)。如果你使用 Spring 來對強類型的 Collection 依賴注入到 bean 中,你可以利用 Spring 的類型轉換來支持這樣 強類型 Collection 實例的元素,在被加到 Collection 之前,可以轉換成合適的類型。
```
public class Foo {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
<beans>
<bean id="foo" class="x.y.Foo">
<property name="accounts">
<map>
<entry key="one" value="9.99"/>
<entry key="two" value="2.75"/>
<entry key="six" value="3.99"/>
</map>
</property>
</bean>
</beans>
```
當 foo bean 的 accounts 屬性準備好注入時,關于強類型元素 `Map<String, Float>` 類型的泛型信息就通過反射機制準備好了。因此 Spring 的類型轉換工具識別到各種元素的 值作為 Float 類型,字符串值 9.99,2.75 和 3.99 被轉換成實際的 Float 類型。
#### 4.4.2.5 null 和空字符串
Spring 將屬性的空參數當作空 String。下面基于 XML 的配置元數據片段設置了電子郵 件屬性為空 String 值("")。
```
<bean class="ExampleBean">
<property name="email" value=""/>
</bean>
```
上面的例子和下面的 Java 代碼是一樣的:exampleBean.setEmail("")。`<null/>` 元素控制 null 值。比如:
```
<bean class="ExampleBean">
<property name="email"><null/></property>
</bean>
```
上面的配置和下面的 Java 代碼一致:exampleBean.setEmail(null)。
#### 4.4.2.6 使用 p-命名空間的 XML 快捷方式
p-命名空間可以使你使用 bea n 的元素屬性,而不是內嵌的`<property/>`元素,來描述屬 性的值和/或協作的 bean。
Spring 2.0 和后續版本支持使用命名空間(附錄 C)的可擴展的配置格式,這是基于 XML的 Schema 定義的。本章中討論的 bea n 的配置格式是定義在 XML 的 Schema 下的。然而,p-命名空間則不是定義在 XSD 文件下的,僅僅存在于 Spring 的核心中。 下面的示例展示了兩個 XML 片段,解析得到相同的結果:第一個使用了標準的 XML 格式,第二個使用了 p-命名空間。
```
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema -instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring -beans-3.0.xsd">
<bean name="classic" class="com.example.ExampleBean">
<property name="email" value=["foo@bar.co](mailto:foo@bar.com)m"/>
</bean>
<bean name="p-namespace" class="com.example.ExampleBean" p:email=["foo@bar.co](mailto:foo@bar.com)m"/>
</beans>
```
示例展示了 p-命名空間下的屬性,在 bean 的定義中稱為 email。這就告訴 Spring 來包 含屬性聲明。正如前面提到的,p-命名空間沒有 schema 定義,所以你可以設置屬性的名稱 和 bean 中屬性的名稱一樣。
下面的示例包含了兩個 bean 的定義,兩者都有對其它 bean 的引用:
```
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema -instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring -beans-3.0.xsd">
<bean name="john-classic" class="com.example.Person">
<property name="name" value="John Doe"/>
<property name="spouse" ref="jane"/>
</bean>
<bean name="john-modern" class="com.example.Person" p:name="John Doe" p:spouse-ref="jane"/>
<bean name="jane" class="com.example.Person">
<property name="name" value="Jane Doe"/>
</bean>
</beans>
```
正如你所看到的一樣,這個例子包含著不僅僅使用了 p-命名空間的屬性值,也使用了 特殊格式來聲明屬性的引用。在第一個 bean 中 使用了`<property name="spouse" ref="jane"/>`來創建 john bean 對 jane bean 的引用關系,第二個 bean 中,使用了 p:spouse-ref="jane"作為屬性來做相同的事情。本例中,spouse 是屬性名,而-ref 部分表明了這不是一個直接值而是一個對其它 bean 的引用。
> 
> 注意
> P-命名空間沒有標準 XML 格式那么靈活。比如,聲明屬性引用的格式和以 Ref 結尾的 屬性相沖突,而標準的 XML 格式則不會。我們建議謹慎選擇所用的方法并和開發團隊成員 充分地交流,避免產生同時使用這三種方法的 XML 文檔。
#### 4.4.2.7 使用 c-命名空間的 XML 快捷方式
和 4.4.2.6 節,“使用 p-命名空間的 XML 快捷方式”相似,c-命名空間是在 Spring 3.1 中 被引入的,允許使用內聯屬性來配置構造方法參數而不是使用 constructor-arg 元素。
我們來看 4.4.1.1 節,“基于構造方法的依賴注入”中的示例,現在使用 c 命名空間:
```
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema -instance" xmlns:p="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bar" class="x.y.Bar"/>
<bean id="baz" class="x.y.Baz"/>
<-- '傳統的'聲明方式 -->
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
<constructor-arg value=["foo@bar.co](mailto:foo@bar.com)m"/>
</bean>
<-- 'c-命名空間'聲明方式 -->
<bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email=["foo@bar.co](mailto:foo@bar.com)m">
</beans>
```
c:命名空間使用了和 p:(以-ref 結尾的 bean 引用)相同的轉換機制通過它們的名稱 來設置構造方法參數。這樣一來,即便沒有在 XSD schema(但是存在于 Spring 核心的內部) 中定義,它還是需要聲明出來。
在極少數的情況下,構造方法參數名稱是不可用的(通常如果字節碼在編譯時沒有調試 信息),我們可以使用參數索引:
```
<-- 'c-命名空間'索引聲明 -->
<bean id="foo" class="x.y.Foo" c:_0-ref="bar" c:_1-ref="baz">
```
> 
> 注意
> 因為 XML 的語法,索引符號需要在其頭部使用_作為 XML 屬性名稱,因為 XML 中屬性 是不能以數字開頭的(盡管一些 IDE 允許這樣做)。
在實際運用中,構造方法解析機制(4.4.1.1 節)在匹配參數時是非常有效率的,所以除 非真有需要,我們建議在配置中使用名稱符號。
#### 4.4.2.8 復合屬性名稱
在設置 bean 的屬性時,只要路徑中的所有組件,除了最后一個屬性名稱是非 null 的, 可以使用復合或者嵌套的屬性名稱。參考下面的 bean 定義。
```
<bean id="foo" class="foo.Bar">
<property name="fred.bob.sammy" value="123" />
</bean>
```
foo bean 有一個 fred 屬性,它還有一個 bob 屬性,而它仍有一個 sammy 屬性,而最 終的 sammy 屬性被設置成數值 123。為了讓這樣的配置可用,foo 的屬性 fred,fred 的 屬性 bob 在 bean 被構造好后必須不能為 null,否則會拋出 NullPointerException 異常。
### 4.4.3 使用 depends-on
如果一個 bean 是另外一個 bean 的依賴,通常表明了它會被設置成另外一個的屬性。 典型的情況是在基于 XML 的配置元數據中使用`<ref/>`(4.4.2.2 節)元素來完成。然而,有 時在兩個 bean 之間的依賴并不是直接的;比如,類中的靜態初始化器需要觸發,就像數據 庫驅動程序的注冊。depends-on 屬性可以明確地強制一個或多個 bean 在使用這個元素的 bean 被初始化之前被初始化。下面的示例使用了 depends-on 屬性來表示一個獨立 bean 的依賴:
```
<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
```
為了表示對多個 bean 的依賴,提供一個 bean 名稱的列表作為 depends-on 屬性的值 即可,要用逗號,空白或分號分隔開,它們都是有效的分隔符:
```
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
```
> 
> 注意
> 在 bean 定義中的 depends-on 屬性可以指定初始化時的依賴,也可以是僅僅是單例(4.5.1 節)bean,對應銷毀時的依賴。和給定 bean 定義了 depends-on 關系的依賴 bean 首先被銷毀,先于給定的 bean 本身。因此 depends-on 也能控制關閉順序。
### 4.4.4 延遲初始化 bean
默認情況下,ApplicationContext 的實現類積極地創建并配置所有單例的 bean (4.5.1 節),作為初始化過程的一部分。通常來說,這種預實例化是非常可取的,因為在配 置或周邊環境中的錯誤可以直接被發現,而不是幾小時或幾天后去發現。當這種行為不可用時,你可以阻止單例 bean 的預實例化,在 bean 定義中使用延遲初始化來標記一下就可以 了。延遲初始化 bean 告訴 IoC 容器在該 bean 第一次被請求時再來實例化,而不是在啟動時 實例化。
在 XML 中,這個行為可以通過`<bean/>`元素的 lazy-init 屬性來控制;比如:
```
<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.foo.AnotherBean"/>
```
當前者配置被 ApplicationContext 處理時,命名為 lazy 的 bean 并不會在
ApplicationContext 啟動時被預實例化,而 not.lazy bean 會被先預實例化。 而到延遲初始化 bean 是一個單例 bean 的依賴時,且這個單例 bean 不是延遲初始化的,那么 ApplicationContext 也會在啟動時來創建延遲初始化的 bean,因為它必須滿足單 例 bean 的依賴。延遲初始化的 bean 被注入到單例 bean 中的時候它就不是延遲初始化的了。
你也可以在容器級別來控制延 遲初始化,在 `<beans/>` 元素上使用default-lazy-init 屬性;比如:
```
<beans default-lazy-init="true">
<!-- 那么就沒有bean是預實例化的了... -->
</beans>
```
### 4.4.5 自動裝配協作者
Spring 容器可以自動裝配協作 bean 之間的關系。你可以允許 Spring 自動為你的 bean 來 解析協作者(其它 bean),通過檢查 ApplicationContext 的內容即可。自動裝配有下 列優勢:
自動裝配可以顯著減少指定屬性或構造方法參數的需要。(如 bean 模板的機制,這將在 本章的 4.7 節來討論,在這方面是有價值的。)
自動裝配可以更新配置對象的演變。比如,如果你需要給一個類添加依賴,那個依賴可 以自動被填入而不需要修改配置。因此,自動裝配在開發期間是非常有用的,當代碼庫 變得更穩定時切換到明確的裝配也沒有否定的選擇。
當使用基于 XML 的配置元數據(4.4.1 節)時,你可以為 bean 的定義指定自動裝配模 式,在`<bean/>`元素上設置 autowire 屬性即可。自動裝配功能有五種模式。你可以為每個 bean 來指定自動裝配,因此可以選擇為哪一個來指定自動裝配。
表 4.2 自動裝配模式
| 模式 | 解釋 |
| --- | --- |
| no | (默認情況)沒有自動裝配。Bean 的引用必須通過 ref 元素來定義。對于大型的部署,修改默認設置是不推薦的,因為明確地指定協作者會給予更多的控制和清晰。某種程度上來說,它勾勒出了系統的結構。 |
| byName | 通過屬性名稱來自動裝配。Spring 以相同名稱來查找需要被自動裝配的 bean。比如,如果 bean 被設置成由名稱來自動裝配,并含有一個 master 屬性(也 就說,有 setMaster(..)方法),Spring 會查找名為 master 的 bean 定義,并且用它來設置屬性。 |
| byType | 如果 bean 的屬性類型在容器中存在的話,就允許屬性被自動裝配。如果存在多于一個,就會拋出致命的異常,這就說明了對那個 bean 不能使用 byType 進行自動裝配。如果沒有匹配的 bean 存在,就不會有任何效果;屬性不會 被設置。 |
| constructor | 和 byType 類似,但是是應用于構造方法參數的。如果在容器中沒有確定的構造方法參數類型的 bean 的存在,就會發生致命的錯誤。 |
使用 byType 或 constructor 自動裝配模式,你可以裝配數組和集合類型。這種情況下所有在容器內匹配期望類型的自動裝配候選者會被用來滿足依賴。如果期望的鍵類型是String,你可以自動裝配強類型的 Map。自動裝配的 Map 值會包括匹配期望類型的實例, 而且 Map 的鍵會包含對應 bean 的名稱。
你可以聯合自動裝配行為和依賴檢查,這會在自動裝配完成之后執行。
#### 4.4.5.1 自動裝配的限制和缺點
當在項目中一直使用時,自動裝配是非常不錯的。如果自動裝配通常是不使用的,它就 可能會迷惑開發人員來使用它去裝配僅僅一兩個 bean。
考慮一下自動裝配的限制和缺點:
* 在 property 和 constructor-arg 中設置的明確依賴通常覆蓋自動裝配。不能自動 裝配所謂的簡單屬性,比如原生類型,String 和 Class(還有這樣簡單屬性的數字)。這 是由于設計的限制。
* 自動裝配沒有明確裝配那么精確,盡管,在上面的表格中已經說明了,Spring 很小心地 避免在有歧義的情況下去猜測,但也可能會有意想不到的結果,在 Spring 管理的對象 中間的關系可能就不會再清晰地說明了。
* 裝配信息可能對從 Spring 容器中來生成文檔的工具來說不可用。
* 在容器中的多個 bean 定義可能通過 setter 方法或構造方法參數匹配指定的類型進行自 動裝配。對于數組,集合或 Map,這不一定是一個問題。而對期望簡單值的依賴,這 種歧義不能隨意解決。如果沒有唯一的 bean 可用,就會拋出異常。 在后面一種情況中,你有幾種選擇:
* 放棄自動裝配而使用明確的裝配。
* 避免設置它的 autowire-candidate 屬性為 false 來自動裝配 bean,這會在下一 節中來解釋。
* 設置`<bean/>`元素的 primary 屬性為 true 來指定單獨的 bean 作為主要的候選者。
* 如果你使用 Java 5 或更高版本,使用基于注解的配置實現更細粒度的控制,這會在 4.9 節,“基于注解的容器配置”中來解釋。
#### 4.4.5.2 從自動裝配中排除 bean
在每個 bean 的基礎上,你可以從自動裝配中來排除 bean。在 Spring 的 XML 格式配置 中,設置`<bean/>`元素的 autowire-candidate 屬性為 false;容器會把指定的 bean 對自動裝配不可用(包含注解風格的配置,比如@Autowired(4.9.2 節))。
你也可以基于 bean 名稱的模式匹配來限制自動裝配候選者。頂級的`<beans/>`元素中的 default-autowire-candidates 屬性接受一個或多個模式。比如,為了限制自動裝 配候選者到任意名稱以 Repository 結尾 bean 的狀態,提供*Repository 值。要提供多個模式,把它們定義在以逗號分隔的列表中。Bean 定義中 autowire-candidate 屬性的 true 或 false 明確的值通常是優先的,而且對于這些 bean 來說,模式匹配規則是不適用的。 這些技術對那些永遠不想通過自動裝配被注入到其它 bea n 中的 bea n 來說是很有用的。
這并不意味著未包含的 bean 不能使用自動裝配來配置。相反,bean 本身不是自動裝配其它 bean 的候選者。
### 4.4.6 方法注入
在很多應用場景中,很多容器中的 bean 是單例(4.5.1 節)的。當一個單例的 bean 需 要和其它單例的 bean 協作時,或者一個非單例的 bean 需要和其它非單例的 bean 協作時, 典型地做法是通過定義一個 bean 作為另外一個的屬性來控制依賴。當 bean 的生命周期不 同時問題就產生了。假設單例 bean A 需要使用非單例(prototype,原型)bean B,或許在 A 的每個方法調用上。容器僅僅創建單例 bean A 一次,因此僅僅有一次機會去設置屬性。容 器不能每次為 bean A 提供所需的 bean B 新的實例。
解決方法就是放棄一些控制反轉。你可通過實現 ApplicationContextAware 接口 以讓 bean A 去感知容器(4.6.2 節),而且在每次 bean A 需要 bean B 的實例時,可以讓容器 調用 getBean(“B”)(4.2.3 節)去獲取(一個新的)bean B。下面的代碼就是這種方式的例子:
```
// 使用了有狀態的命令風格的類來執行一些處理
package fiona.apple;
// 導入Spring的API
import org.springframework.beans.BeansException;
import org.springframework.context.Applicationcontext;
import org.springframework.context.ApplicationContextAware;
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
// 抓取相應命令的新實例
Command command = createCommand();
// 在命令實例上(希望標記新的)設置狀態
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// 注意Spring API的依賴!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
}
```
前面的做法是不可取的,因為這些業務代碼感知并耦合到了 Spring 框架中。方法注入, 這種 Spring IoC 容器中的有點先進的功能,允許以一種干凈的方式來處理這個用例。
你可以在[博客文章](http://blog.springsource.com/2004/08/06/method-injection/)中來閱讀更多關于方法注入的動機。
#### 4.4.6.1 查找方法注入
查找方法注入是容器在其管理的 bean 上來覆蓋方法的能力,來返回容器中其它命名 bean 的查找結果。查找,典型的情況是涉及原型 bean,這是在之前章節中描述的情景。Spring Framework 從 CGLIB 類庫中,通過使用字節碼生成機制實現了這種方法注入,來動態地生成 覆蓋方法的子類。
> 
> 注意
> 要讓這些動態子類起作用,在類路徑下必須有 CGLIB 的 jar 文件。這些 Spring 容器中的 子類不能是 final 類型的,要被覆蓋的方法也不能是 final 類型的。而且,測試有 abstract 方法的類要求你自己去編寫類的子類并提供 abstract 方法的實現。最后,是 方法注入目標的對象還不能被序列化。
看一下之前代碼片段中的 CommandManager 類,你會看到 Spring 容器會動態地覆蓋 createCommand()方法的實現。CommandManager 類不會有任何 Spring 的依賴,在重新設計 的例子中你會看到:
```
package fiona.apple;
// 沒有Spring API的導入!
public abstract class CommandManager {
public Object process(Object commandState) {
// 抓取一個心得合適的Command接口的實例
Command command = createCommand();
//在命令實例上(希望標記新的)設置狀態
command.setState(commandState);
return command.execute();
}
// 好的... 但是這個方法的實現在哪兒?
protected abstract Command createCommand();
}
```
在客戶端類中包含要被注入(本例中的 CommandManager)的方法,要被注入的方法 需要從下面的示例中編寫一個簽名:
```
<public|protected> [abstract] <return-type> theMethodName(no-arguments);
```
如果方法是 abstract 的,動態生成的子類就實現這個方法。否則,動態生成的子類覆蓋 定義在源類中的確定方法。比如:
```
<!-- 部署為原型的(非單例的)有狀態的bean -->
<bean id="command" class="fiona.apple.AsyncCommand" scope="prototype">
<!-- 注入所需要的依賴 -->
</bean>
<!-- commandProcessor使用statefulCommandHelper -->
<bean id="commandManager" class="fiona.apple.CommandManager">
<lookup-method name="createCommand" bean="command"/>
</bean>
```
當需要 command bean 的新的實例時,標識為 commandManager 的 bean 調用它自己的 方法 createCommand()。部署 command bean 為原型的可必須要小心,那確實就是需要 的才行。如果被部署為單例的(4.5.1 節),那么每次會返回相同的 command bean 的實例。
> 
> 提示
> 感 興 趣 的 讀 者 可 能 會 發 現 要 使 用 ServiceLocatorFactoryBean (在 org.springframework.beans.factory.config 包下)。在 ServiceLocatorFactoryBean 中的使用的方法和其它工具類是相似的,ObjectFactoryCreatingFactoryBean,但是它允許你去指定你自己的查找接口而不是 Spring 特定的查找接口。對這些類查詢一下 JavaDoc 文檔,還有[博客文章](http://blog.arendsen.net/index.php/2006/10/05/on-the-servicelocatorfactorybean-dlas-and-the-sustainability-of-code-and-design/)來獲取 ServiceLocatorFactoryBean 的額外的信息。
#### 4.4.6.2 任意方法的替代
在方法注入中,用處不如查找方法注入大的一種形式,就是使用另外一個方法實現來替 換被容器管理的 bean 中的任意方法的能力。用戶可以安全地跳過本節的其它部分,直到你 真正需要這些功能的時候來回過頭來看。
使用基于 XML 的配置元數據,對于部署的 bean,你可以使用 replaced-method 元 素來使用另外一個方法替換已有的方法實現。看看下面這個類,有一個我們想要去覆蓋的 computeValue 方法:
```
public class MyValueCalculator {
public String computeValue(String input) {
// 真正的代碼...
}
// 其它方法...
}
```
實現了 org.springframework.beans.factory.support.MethodReplacer 接口的類提供新的方法定義。
```
/** 也就是要在MyValueCalculator中實現用來覆蓋已有的方法
computeValue(String)
*/
public class ReplacementComputeValue implements MethodReplacer {
public Object reimplement(Object o, Method m, Object[] args)
throws Throwable {
// 獲取輸入值,并處理它,返回一個計算的結果
String input = (String) args[0];
...
return ...;
}
}
```
部署源類的 bean 定義和指定的方法覆蓋可以是這樣的:
```
<bean id="myValueCalculator" class="x.y.z.MyValueCalculator">
<!-- 任意方法替換 -->
<replaced-method name="computeValue" replacer="replacementComputeValue">
<arg-type>String</arg-type>
</replaced-method>
</bean>
<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>
```
你可以在`<replaced-method/>`元素中使用一個或多個包含的`<arg-type/>`元素來 指示被覆蓋方法的方法簽名。如果方法是被重載的并在類中有很多種形式的存在,那么參數 的簽名是必須的。為了簡便,字符串類型的參數可能是類型全名的一個子串。比如,下面所 有的都匹配 java.lang.String:
```
java.lang.String
String
Str
```
因為用參數的數量用來區分每一個可能的選擇通常是足夠的,這種快捷方式可以節省大 量的輸入,允許你去輸入匹配參數類型的最短的字符串。
- Spring 中文文檔 3.1
- 第一部分 Spring framework 概述
- 第 1 章 Spring Framework 介紹
- 1.1 依賴注入和控制反轉
- 1.2 模塊
- 1.3 使用方案
- 第二部分 Spring 3 的新特性
- 第 2 章 Spring 3.0 的新特性和增強
- 2.1 Java 5
- 2.2 改進的文檔
- 2.3 新的文章和教程
- 2.4 新的模塊組織方式和系統構建方式
- 2.5 新特性概述
- 第 3 章 Spring 3.1 的新特性和增強
- 3.1 新特性概述
- 第三部分 核心技術
- 第 4 章 IoC 容器
- 4.1 Spring IoC 容器和 bean 的介紹
- 4.2 容器概述
- 4.3 Bean 概述
- 4.4 依賴
- 4.5 Bean 的范圍
- 4.6 自定義 bean 的性質
- 4.7 Bean 定義的繼承
- 4.8 容器擴展點
- 4.9 基于注解的容器配置
- 4.10 類路徑掃描和管理的組件
- 4.11 使用 JSR 330 標準注解
- 4.12 基于 Java 的容器配置
- Hibernate 中文文檔 3.2
- 前言
- 1. 翻譯說明
- 2. 版權聲明
- 第 1 章 Hibernate入門
- 1.1. 前言
- 1.2. 第一部分 - 第一個Hibernate應用程序
- 1.2.1. 第一個class
- 1.2.2. 映射文件
- 1.2.3. Hibernate配置
- 1.2.4. 用Ant構建
- 1.2.5. 啟動和輔助類
- 1.2.6. 加載并存儲對象
- 1.3. 第二部分 - 關聯映射
- 1.3.1. 映射Person類
- 1.3.2. 單向Set-based的關聯
- 1.3.3. 使關聯工作
- 1.3.4. 值類型的集合
- 1.3.5. 雙向關聯
- 1.3.6. 使雙向連起來
- 1.4. 第三部分 - EventManager web應用程序
- 1.4.1. 編寫基本的servlet
- 1.4.2. 處理與渲染
- 1.4.3. 部署與測試
- 1.5. 總結
- 第 2 章 體系結構(Architecture)
- 2.1. 概況(Overview)
- 2.2. 實例狀態
- 2.3. JMX整合
- 2.4. 對JCA的支持
- 2.5. 上下文相關的(Contextual)Session
- 第 3 章 配置
- 3.1. 可編程的配置方式
- 3.2. 獲得SessionFactory
- 3.3. JDBC連接
- 3.4. 可選的配置屬性
- 3.4.1. SQL方言
- 3.4.2. 外連接抓取(Outer Join Fetching)
- 3.4.3. 二進制流 (Binary Streams)
- 3.4.4. 二級緩存與查詢緩存
- 3.4.5. 查詢語言中的替換
- 3.4.6. Hibernate的統計(statistics)機制
- 3.5. 日志
- 3.6. 實現NamingStrategy
- 3.7. XML配置文件
- 3.8. J2EE應用程序服務器的集成
- 3.8.1. 事務策略配置
- 3.8.2. JNDI綁定的SessionFactory
- 3.8.3. 在JTA環境下使用Current Session context (當前session上下文)管理
- 3.8.4. JMX部署
- 第 4 章 持久化類(Persistent Classes)
- 4.1. 一個簡單的POJO例子
- 4.1.1. 實現一個默認的(即無參數的)構造方法(constructor)
- 4.1.2. 提供一個標識屬性(identifier property)(可選)
- 4.1.3. 使用非final的類 (可選)
- 4.1.4. 為持久化字段聲明訪問器(accessors)和是否可變的標志(mutators)(可選)
- 4.2. 實現繼承(Inheritance)
- 4.3. 實現equals()和hashCode()
- 4.4. 動態模型(Dynamic models)
- 4.5. 元組片斷映射(Tuplizers)
- 第 5 章 對象/關系數據庫映射基礎(Basic O/R Mapping)
- 5.1. 映射定義(Mapping declaration)
- 5.1.1. Doctype
- 5.1.1.1. EntityResolver
- 5.1.2. hibernate-mapping
- 5.1.3. class
- 5.1.4. id
- 5.1.4.1. Generator
- 5.1.4.2. 高/低位算法(Hi/Lo Algorithm)
- 5.1.4.3. UUID算法(UUID Algorithm )
- 5.1.4.4. 標識字段和序列(Identity columns and Sequences)
- 5.1.4.5. 程序分配的標識符(Assigned Identifiers)
- 5.1.4.6. 觸發器實現的主鍵生成器(Primary keys assigned by triggers)
- 5.1.5. composite-id
- 5.1.6. 鑒別器(discriminator)
- 5.1.7. 版本(version)(可選)
- 5.1.8. timestamp (可選)
- 5.1.9. property
- 5.1.10. 多對一(many-to-one)
- 5.1.11. 一對一
- 5.1.12. 自然ID(natural-id)
- 5.1.13. 組件(component), 動態組件(dynamic-component)
- 5.1.14. properties
- 5.1.15. 子類(subclass)
- 5.1.16. 連接的子類(joined-subclass)
- 5.1.17. 聯合子類(union-subclass)
- 5.1.18. 連接(join)
- 5.1.19. 鍵(key)
- 5.1.20. 字段和規則元素(column and formula elements)
- 5.1.21. 引用(import)
- 5.1.22. any
- 5.2. Hibernate 的類型
- 5.2.1. 實體(Entities)和值(values)
- 5.2.2. 基本值類型
- 5.2.3. 自定義值類型
- 5.3. 多次映射同一個類
- 5.4. SQL中引號包圍的標識符
- 5.5. 其他元數據(Metadata)
- 5.5.1. 使用 XDoclet 標記
- 5.5.2. 使用 JDK 5.0 的注解(Annotation)
- 5.6. 數據庫生成屬性(Generated Properties)
- 5.7. 輔助數據庫對象(Auxiliary Database Objects)
- 第 6 章 集合類(Collections)映射
- 6.1. 持久化集合類(Persistent collections)
- 6.2. 集合映射( Collection mappings )
- 6.2.1. 集合外鍵(Collection foreign keys)
- 6.2.2. 集合元素(Collection elements)
- 6.2.3. 索引集合類(Indexed collections)
- 6.2.4. 值集合于多對多關聯(Collections of values and many-to-many associations)
- 6.2.5. 一對多關聯(One-to-many Associations)
- 6.3. 高級集合映射(Advanced collection mappings)
- 6.3.1. 有序集合(Sorted collections)
- 6.3.2. 雙向關聯(Bidirectional associations)
- 6.3.3. 雙向關聯,涉及有序集合類
- 6.3.4. 三重關聯(Ternary associations)
- 6.3.5. 使用&amp;lt;idbag&amp;gt;
- 6.4. 集合例子(Collection example)
- 第 7 章 關聯關系映射
- 7.1. 介紹
- 7.2. 單向關聯(Unidirectional associations)
- 7.2.1. 多對一(many to one)
- 7.2.2. 一對一(one to one)
- 7.2.3. 一對多(one to many)
- 7.3. 使用連接表的單向關聯(Unidirectional associations with join tables)
- 7.3.1. 一對多(one to many)
- 7.3.2. 多對一(many to one)
- 7.3.3. 一對一(one to one)
- 7.3.4. 多對多(many to many)
- 7.4. 雙向關聯(Bidirectional associations)
- 7.4.1. 一對多(one to many) / 多對一(many to one)
- 7.4.2. 一對一(one to one)
- 7.5. 使用連接表的雙向關聯(Bidirectional associations with join tables)
- 7.5.1. 一對多(one to many) /多對一( many to one)
- 7.5.2. 一對一(one to one)
- 7.5.3. 多對多(many to many)
- 7.6. 更復雜的關聯映射
- 第 8 章 組件(Component)映射
- 8.1. 依賴對象(Dependent objects)
- 8.2. 在集合中出現的依賴對象 (Collections of dependent objects)
- 8.3. 組件作為Map的索引(Components as Map indices )
- 8.4. 組件作為聯合標識符(Components as composite identifiers)
- 8.5. 動態組件 (Dynamic components)
- 第 9 章 繼承映射(Inheritance Mappings)
- 9.1. 三種策略
- 9.1.1. 每個類分層結構一張表(Table per class hierarchy)
- 9.1.2. 每個子類一張表(Table per subclass)
- 9.1.3. 每個子類一張表(Table per subclass),使用辨別標志(Discriminator)
- 9.1.4. 混合使用“每個類分層結構一張表”和“每個子類一張表”
- 9.1.5. 每個具體類一張表(Table per concrete class)
- 9.1.6. Table per concrete class, using implicit polymorphism
- 9.1.7. 隱式多態和其他繼承映射混合使用
- 9.2. 限制
- 第 10 章 與對象共事
- 10.1. Hibernate對象狀態(object states)
- 10.2. 使對象持久化
- 10.3. 裝載對象
- 10.4. 查詢
- 10.4.1. 執行查詢
- 10.4.1.1. 迭代式獲取結果(Iterating results)
- 10.4.1.2. 返回元組(tuples)的查詢
- 10.4.1.3. 標量(Scalar)結果
- 10.4.1.4. 綁定參數
- 10.4.1.5. 分頁
- 10.4.1.6. 可滾動遍歷(Scrollable iteration)
- 10.4.1.7. 外置命名查詢(Externalizing named queries)
- 10.4.2. 過濾集合
- 10.4.3. 條件查詢(Criteria queries)
- 10.4.4. 使用原生SQL的查詢
- 10.5. 修改持久對象
- 10.6. 修改脫管(Detached)對象
- 10.7. 自動狀態檢測
- 10.8. 刪除持久對象
- 10.9. 在兩個不同數據庫間復制對象
- 10.10. Session刷出(flush)
- 10.11. 傳播性持久化(transitive persistence)
- 10.12. 使用元數據
- 第 11 章 事務和并發
- 11.1. Session和事務范圍(transaction scope)
- 11.1.1. 操作單元(Unit of work)
- 11.1.2. 長對話
- 11.1.3. 關注對象標識(Considering object identity)
- 11.1.4. 常見問題
- 11.2. 數據庫事務聲明
- 11.2.1. 非托管環境
- 11.2.2. 使用JTA
- 11.2.3. 異常處理
- 11.2.4. 事務超時
- 11.3. 樂觀并發控制(Optimistic concurrency control)
- 11.3.1. 應用程序級別的版本檢查(Application version checking)
- 11.3.2. 擴展周期的session和自動版本化
- 11.3.3. 脫管對象(deatched object)和自動版本化
- 11.3.4. 定制自動版本化行為
- 11.4. 悲觀鎖定(Pessimistic Locking)
- 11.5. 連接釋放模式(Connection Release Modes)
- 第 12 章 攔截器與事件(Interceptors and events)
- 12.1. 攔截器(Interceptors)
- 12.2. 事件系統(Event system)
- 12.3. Hibernate的聲明式安全機制
- 第 13 章 批量處理(Batch processing)
- 13.1. 批量插入(Batch inserts)
- 13.2. 批量更新(Batch updates)
- 13.3. StatelessSession (無狀態session)接口
- 13.4. DML(數據操作語言)風格的操作(DML-style operations)
- 第 14 章 HQL: Hibernate查詢語言
- 14.1. 大小寫敏感性問題
- 14.2. from子句
- 14.3. 關聯(Association)與連接(Join)
- 14.4. join 語法的形式
- 14.5. select子句
- 14.6. 聚集函數
- 14.7. 多態查詢
- 14.8. where子句
- 14.9. 表達式
- 14.10. order by子句
- 14.11. group by子句
- 14.12. 子查詢
- 14.13. HQL示例
- 14.14. 批量的UPDATE和DELETE
- 14.15. 小技巧 & 小竅門
- 第 15 章 條件查詢(Criteria Queries)
- 15.1. 創建一個Criteria 實例
- 15.2. 限制結果集內容
- 15.3. 結果集排序
- 15.4. 關聯
- 15.5. 動態關聯抓取
- 15.6. 查詢示例
- 15.7. 投影(Projections)、聚合(aggregation)和分組(grouping)
- 15.8. 離線(detached)查詢和子查詢
- 15.9. 根據自然標識查詢(Queries by natural identifier)
- 第 16 章 Native SQL查詢
- 16.1. 使用SQLQuery
- 16.1.1. 標量查詢(Scalar queries)
- 16.1.2. 實體查詢(Entity queries)
- 16.1.3. 處理關聯和集合類(Handling associations and collections)
- 16.1.4. 返回多個實體(Returning multiple entities)
- 16.1.4.1. 別名和屬性引用(Alias and property references)
- 16.1.5. 返回非受管實體(Returning non-managed entities)
- 16.1.6. 處理繼承(Handling inheritance)
- 16.1.7. 參數(Parameters)
- 16.2. 命名SQL查詢
- 16.2.1. 使用return-property來明確地指定字段/別名
- 16.2.2. 使用存儲過程來查詢
- 16.2.2.1. 使用存儲過程的規則和限制
- 16.3. 定制SQL用來create,update和delete
- 16.4. 定制裝載SQL
- 第 17 章 過濾數據
- 17.1. Hibernate 過濾器(filters)
- 第 18 章 XML映射
- 18.1. 用XML數據進行工作
- 18.1.1. 指定同時映射XML和類
- 18.1.2. 只定義XML映射
- 18.2. XML映射元數據
- 18.3. 操作XML數據
- 第 19 章 提升性能
- 19.1. 抓取策略(Fetching strategies)
- 19.1.1. 操作延遲加載的關聯
- 19.1.2. 調整抓取策略(Tuning fetch strategies)
- 19.1.3. 單端關聯代理(Single-ended association proxies)
- 19.1.4. 實例化集合和代理(Initializing collections and proxies)
- 19.1.5. 使用批量抓取(Using batch fetching)
- 19.1.6. 使用子查詢抓取(Using subselect fetching)
- 19.1.7. 使用延遲屬性抓取(Using lazy property fetching)
- 19.2. 二級緩存(The Second Level Cache)
- 19.2.1. 緩存映射(Cache mappings)
- 19.2.2. 策略:只讀緩存(Strategy: read only)
- 19.2.3. 策略:讀/寫緩存(Strategy: read/write)
- 19.2.4. 策略:非嚴格讀/寫緩存(Strategy: nonstrict read/write)
- 19.2.5. 策略:事務緩存(transactional)
- 19.3. 管理緩存(Managing the caches)
- 19.4. 查詢緩存(The Query Cache)
- 19.5. 理解集合性能(Understanding Collection performance)
- 19.5.1. 分類(Taxonomy)
- 19.5.2. Lists, maps 和sets用于更新效率最高
- 19.5.3. Bag和list是反向集合類中效率最高的
- 19.5.4. 一次性刪除(One shot delete)
- 19.6. 監測性能(Monitoring performance)
- 19.6.1. 監測SessionFactory
- 19.6.2. 數據記錄(Metrics)
- 第 20 章 工具箱指南
- 20.1. Schema自動生成(Automatic schema generation)
- 20.1.1. 對schema定制化(Customizing the schema)
- 20.1.2. 運行該工具
- 20.1.3. 屬性(Properties)
- 20.1.4. 使用Ant(Using Ant)
- 20.1.5. 對schema的增量更新(Incremental schema updates)
- 20.1.6. 用Ant來增量更新schema(Using Ant for incremental schema updates)
- 20.1.7. Schema 校驗
- 20.1.8. 使用Ant進行schema校驗
- 第 21 章 示例:父子關系(Parent Child Relationships)
- 21.1. 關于collections需要注意的一點
- 21.2. 雙向的一對多關系(Bidirectional one-to-many)
- 21.3. 級聯生命周期(Cascading lifecycle)
- 21.4. 級聯與未保存值(Cascades and unsaved-value)
- 21.5. 結論
- 第 22 章 示例:Weblog 應用程序
- 22.1. 持久化類
- 22.2. Hibernate 映射
- 22.3. Hibernate 代碼
- 第 23 章 示例:復雜映射實例
- 23.1. Employer(雇主)/Employee(雇員)
- 23.2. Author(作家)/Work(作品)
- 23.3. Customer(客戶)/Order(訂單)/Product(產品)
- 23.4. 雜例
- 23.4.1. "Typed" one-to-one association
- 23.4.2. Composite key example
- 23.4.3. 共有組合鍵屬性的多對多(Many-to-many with shared composite key attribute)
- 23.4.4. Content based discrimination
- 23.4.5. Associations on alternate keys
- 第 24 章 最佳實踐(Best Practices)
- HttpClient 教程
- 前言
- 第一章 基礎
- 第二章 連接管理
- 第三章 HTTP狀態管理
- 第四章 HTTP認證
- 第五章 HTTP客戶端服務
- 第六章 高級主題
- Mybatis 中文文檔 3.4
- 參考文檔
- 簡介
- 入門
- XML 映射配置文件
- Mapper XML 文件
- 動態 SQL
- Java API
- SQL語句構建器類
- Logging
- 項目文檔
- 項目總體信息
- 訪問
- 提醒方法
- 項目依賴
- Dependency Information
- Overview
- 問題跟蹤
- 項目授權
- 項目郵件列表
- Project Plugin Management
- Project Build Plugins
- Project Report Plugins
- 團隊
- Web訪問
- 匿名訪問
- 開發者訪問
- 通過防火墻訪問
- 項目概要
- 生成報表
- MyBatis Generator 用戶手冊
- MyBatis Generator介紹
- MyBatis Generator新增功能
- MyBatis Generator 快速入門指南
- 運行 MyBatis Generator
- 從命令行運行 MyBatis Generator
- 使用Ant運行 MyBatis Generator
- 通過Maven運行 MyBatis Generator
- 使用Java運行 MyBatis Generator
- 運行 MyBatis Generator 后的任務
- Migrating from Ibator
- Migrating from Abator
- MyBatis Generator XML 配置參考
- &lt;classPathEntry&gt; 元素
- &lt;columnOverride&gt; 元素
- &lt;columnRenamingRule&gt; 元素
- &lt;commentGenerator&gt; 元素
- &lt;context&gt; 元素
- &lt;generatedKey&gt; 元素
- &lt;generatorConfiguration&gt; 元素
- &lt;ignoreColumn&gt; 元素
- &lt;javaClientGenerator&gt; 元素
- The &lt;javaModelGenerator&gt; Element
- The &lt;javaTypeResolver&gt; Element
- &lt;jdbcConnection&gt; 元素
- &lt;plugin&gt; 元素
- &lt;properties&gt; 元素
- &lt;property&gt; 元素
- &lt;sqlMapGenerator&gt; 元素
- &lt;table&gt; 元素
- 使用生成的對象
- JAVA實體對象
- SQL映射文件
- Java客戶端對象
- Example類使用說明
- 擴展Example類
- 使用注意事項
- DB2 使用注意事項
- MySql 使用注意事項
- Oracle 使用注意事項
- PostgreSQL 使用注意事項
- 參考資料
- 從源碼構建
- 擴展MyBatis Generator
- 開發插件
- 日志信息
- 提供的插件
- 設計理念
- Velocity 中文文檔
- 1. 關于
- 2. 什么是Velocity?
- 3. Velocity 可以做什么?
- 3.1. Mud Store 示例
- 4. Velocity模板語言(VTL): 介紹
- 5. Hello Velocity World!
- 6. 注釋
- 7. 引用
- 7.1. 變量Variables
- 7.2. 屬性
- 7.3. 方法
- 8. 形式引用符Formal Reference Notation
- 9. 安靜引用符Quiet Reference Notation
- 11. Case Substitution
- 12. 指令
- 12.1. #set
- 12.2. 字面字符串
- 12.3. 條件
- 12.3.1 If / ElseIf / Else
- 12.3.2 關系和邏輯操作符
- 12.4. 循環
- 12.4.1. Foreach 循環
- 12.5. 包含
- 12.6. 解析
- 12.7. 停止
- 12.10. 宏
- 12.10.1. Velocimacro 參數
- 12.10.2. Velocimacro 屬性
- 12.10.3. Velocimacro Trivia
- 13. Getting literal
- 13.1. 貨幣字符
- 13.2. 轉義 有效的 VTL 指令
- 13.3. 轉義 無效的 VTL 指令
- 14. VTL 格式化問題
- 15. 其它特征和雜項
- 15.1. 數學特征
- 15.2. 范圍操作符
- 15.3. 進階:轉義和!
- 15.4. Velocimacro 雜記
- 15.5. 字符串聯
- Google Guava官方教程(中文版)
- 1-基本工具
- 1.1-使用和避免null
- 1.2-前置條件
- 1.3-常見Object方法
- 1.4-排序: Guava強大的”流暢風格比較器”
- 1.5-Throwables:簡化異常和錯誤的傳播與檢查
- 2-集合
- 2.1-不可變集合
- 2.2-新集合類型
- 2.3-強大的集合工具類:java.util.Collections中未包含的集合工具
- 2.4-集合擴展工具類
- 3-緩存
- 4-函數式編程
- 5-并發
- 5.1-google Guava包的ListenableFuture解析
- 5.2-Google-Guava Concurrent包里的Service框架淺析
- 6-字符串處理:分割,連接,填充
- 7-原生類型
- 8-區間
- 9-I/O
- 10-散列
- 11-事件總線
- 12-數學運算
- 13-反射
- JFreeChart 開發者指南
- 1 簡介
- 1.1 什么是JFreeChart
- 1.2 使用文檔
- 1.3 感謝
- 1.4 建議
- 2 圖表實例
- 2.1 介紹
- 2.2 餅圖(Pie Charts)
- 2.3 直方條形圖(Bar Charts)
- 2.4 折線圖(Line Charts)
- 2.5 XY(散點圖)
- 2.6 時序圖
- 2.7 柱狀圖
- 2.8 面積圖
- 2.9 差異圖
- 2.10 梯形圖
- 2.11 甘特圖
- 2.12 多軸圖
- 2.13 復合/覆蓋圖
- 2.14 開發遠景
- 3 下載和安裝JFreeChart 1.0.6
- 3.1 簡介
- 3.2 下載
- 3.3 解包
- 3.4 運行演示實例
- 3.5 編譯源代碼
- 3.6 產生javadoc文檔
- 4 使用JFreeChart1.0.6
- 4.1 概述
- 4.2 創建第一個圖表
- 5 餅圖(Pie Charts)
- 5.1 簡介
- 5.2 創建一個簡單的餅圖(Pie Charts)
- 5.3 片區顏色
- 5.4 片區外廓
- 5.5 空置、零值和負值
- 5.6 片區和圖例標簽
- 5.7 “取出”某個片區
- 5.8 3D餅圖
- 5.9 多餅圖
- 5.10 實例講解
- 6 直方條形圖(Bar Charts)
- 6.1 簡介
- 6.2 創建一個直方條形圖
- 6.3 ChartFactory類
- 6.4 直方條形圖的簡單定制
- 6.5 定制外觀
- 6.6 示例代碼解讀
- 7 折線圖
- 7.1 簡介
- 7.2 使用categoryDataset數據集創建折線圖
- 7.3 使用XYDataset數據集創建折線圖
- 8 時序圖
- 8.1 簡介
- 8.2 創建時序圖
- 9 定制圖表(Customising Charts)
- 9.1 簡介
- 9.2 圖表屬性
- 9.3 圖區屬性
- 9.4 軸屬性
- 9.5 心得體會
- 10 動態圖(Dynamic Charts)
- 10.1 簡介
- 10.2 知識背景
- 10.3 實例應用
- 11 圖表工具條(Tooltips)
- 11.1 概述
- 11.2 創建圖表工具條
- 11.3 收集圖表工具條
- 11.4 顯示圖表工具條
- 11.5 隱藏圖表工具條
- 11.6 定制圖表工具條
- 12 圖表條目標簽(Item Label)
- 12.1 簡介
- 12.2 顯示條目標簽
- 12.3 條目標簽外觀
- 12.4 條目標簽位置
- 12.5 定制條目標簽文本
- 12.6 實例1
- 12.7 實例2
- 13 多軸和數據源圖表(Multi Axis and Dataset)
- 13.1 簡介
- 13.2 實例
- 13.3 建議和技巧
- 14 組合圖表(Combined Charts)
- 14.1 簡介
- 14.2 組合X種類圖區
- 14.3 組合Y種類圖區
- 14.4 組合X-XY圖區
- 14.5 組合Y-XY圖區
- 15 數據源和JDBC(Dataset And JDBC)
- 15.1 簡介
- 15.2 關于JDBC
- 15.3 樣本數據
- 15.4 PostgreSQL
- 15.5 JDBC驅動
- 15.6 應用演示
- 16 導出圖表為PDF格式
- 16.1 簡介
- 16.2 什么是Acrobat PDF
- 16.3 IText
- 16.4 Graphics2D
- 16.5 開始導出
- 16.6 實例應用
- 16.7 查看PDF 文件
- 16.8 Unicode字符問題
- 17 導出圖表為SVG格式
- 17.1 簡介
- 17.2 背景
- 17.3 實例代碼
- 18 Applet
- 18.1 簡介
- 18.2 問題
- 18.3 實例應用
- 19 Servlets
- 19.1 介紹
- 19.2 編寫一個簡單的Servlet應用
- 19.3 編譯實例Servlet
- 19.4 部署實例Servlet
- 19.5 在HMTL頁面種嵌入圖表
- 19.6 支持文件
- 19.7 部署Servlets
- 20 JFreeChart相關技術
- 20.1 簡介
- 20.2 X11/Headless Java
- 20.3 JSP
- 20.4 加載圖片
- 21 包
- 21.1 概述