?
このドキュメントでは、 php中國語ネットマニュアル リリース
到目前為止本章中的大多數(shù)例子都使用XML來指定配置元數(shù)據(jù),
這些元數(shù)據(jù)會生成Spring容器中的每個BeanDefinition
。
上一節(jié)(第?3.11?節(jié) “基于注解(Annotation-based)的配置”)演示了如何使用代碼級注解來提供大量配置元數(shù)據(jù)。
然而,即使是在那些例子中,“基礎”bean定義還是顯式地定義在XML文件中,注解只是用來驅(qū)動依賴注入的。
本節(jié)中會介紹一種方法,通過掃描classpath并匹配過濾器來隱式地檢測候選組件 (candidate components)。
從Spring 2.0開始,引入了@Repository
注解,
用它來標記充當儲存庫(又稱 Data Access Object或DAO)角色或典型的類。利用這個標記可以做很多事,
其中之一就是對第?12.6.4?節(jié) “異常轉(zhuǎn)化”中描述的異常進行自動轉(zhuǎn)換。
Spring 2.5引入了更多典型化注解(stereotype annotations):
@Component
、@Service
和
@Controller
。
@Component
是所有受Spring管理組件的通用形式;
而@Repository
、@Service
和
@Controller
則是@Component
的細化,
用來表示更具體的用例(例如,分別對應了持久化層、服務層和表現(xiàn)層)。也就是說,
你能用@Component
來注解你的組件類,
但如果用@Repository
、@Service
或@Controller
來注解它們,你的類也許能更好地被工具處理,或與切面進行關(guān)聯(lián)。
例如,這些典型化注解可以成為理想的切入點目標。當然,在Spring Framework以后的版本中,
@Repository
、@Service
和
@Controller
也許還能攜帶更多語義。如此一來,如果你正在考慮服務層中是該用
@Component
還是@Service
,
那@Service
顯然是更好的選擇。同樣的,就像前面說的那樣,
@Repository
已經(jīng)能在持久化層中進行異常轉(zhuǎn)換時被作為標記使用了。
Spring可以自動檢測“被典型化”(stereotyped)的類,在ApplicationContext
中注冊相應的BeanDefinition
。例如,下面的這兩個類就滿足這種自動檢測的要求:
@Service public class SimpleMovieLister { private MovieFinder movieFinder; @Autowired public SimpleMovieLister(MovieFinder movieFinder) { this.movieFinder = movieFinder; } }
@Repository
public class JpaMovieFinder implements MovieFinder {
// implementation elided for clarity
}
要檢測這些類并注冊相應的bean,需要在XML中包含以下元素,其中'basePackage'是兩個類的公共父包 (或者可以用逗號分隔的列表來分別指定包含各個類的包)。
<?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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:component-scan base-package="org.example"/> </beans>
此外,在使用組件掃描元素時,AutowiredAnnotationBeanPostProcessor
和CommonAnnotationBeanPostProcessor
會隱式地被包括進來。
也就是說,連個組件都會被自動檢測并織入 -
所有這一切都不需要在XML中提供任何bean配置元數(shù)據(jù)。
通過加入值為'false'的annotation-config屬性可以禁止注冊這些后置處理器。
默認情況下,用@Component
、
@Repository
、@Service
或
@Controller
(或本身使用了@Component
注解的自定義注解)
注解的類是唯一會被檢測到的候選組件。但是可以很方便地通過自定義過濾器來改變并擴展這一行為。
可以用'component-scan
'的include-filter或
exclude-filter子元素來進行添加。
每個過濾器元素都要求有'type
'和'expression
'屬性。
下面給出了四個已有的可選過濾器。
表?3.7.?過濾器類型
過濾器類型 | 表達式范例 |
---|---|
annotation |
|
assignable |
|
regex | org\.example\.Default.* |
aspectj |
|
下面這個XML配置會忽略所有的@Repository
注解并用“stub”儲存庫代替。
<beans ...> <context:component-scan base-package="org.example"> <context:include-filter type="regex" expression=".*Stub.*Repository"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/> </context:component-scan> </beans>
你也可以用<component-scan/>元素的use-default-filters="false"
屬性來禁用默認的過濾器。這會關(guān)閉對使用了@Component
、
@Repository
、@Service
或
@Controller
的類的自動檢測。
當一個組件在某個掃描過程中被自動檢測到時,會根據(jù)那個掃描器的BeanNameGenerator
策略生成它的bean名稱。默認情況下,任何包含name
值的Spring“典型”注解
(@Component
、@Repository
、
@Service
和@Controller
)
會把那個名字提供給相關(guān)的bean定義。如果這個注解不包含name
值或是其他檢測到的組件
(比如被自定義過濾器發(fā)現(xiàn)的),默認bean名稱生成器會返回小寫開頭的非限定(non-qualified)類名。
例如,如果發(fā)現(xiàn)了下面這兩個組件,它們的名字會是'myMovieLister'和'movieFinderImpl':
@Service("myMovieLister")
public class SimpleMovieLister {
// ...
}
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
如果你不想使用默認bean命名策略,可以提供一個自定義的命名策略。首先實現(xiàn)
BeanNameGenerator
接口,確認包含了一個默認的無參數(shù)構(gòu)造方法。然后在配置掃描器時提供一個全限定(fully-qualified)類名:
<beans ...> <context:component-scan base-package="org.example" name-generator="org.example.MyNameGenerator" /> </beans>
作為一條常規(guī),當其他組件可能會顯式地引用一個組件時可以考慮用注解來指定名稱。 另一方面,當容器負責織入時,自動生成的名稱就足夠了。
通常受Spring管理的組件,默認或者最常用的作用域是“singleton”。然而,有時也會需要其他的作用域。
因此Spring 2.5還引入了一個新的@Scope
注解。只要在注解中提供作用域的名稱就行了,
比方說:
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
如果你想提供一個自定義的作用域解析策略,不使用基于注解的方法,實現(xiàn)ScopeMetadataResolver
接口,確認包含一個默認的沒有參數(shù)的構(gòu)造方法。然后在配置掃描器時提供全限定類名:
<beans ...> <context:component-scan base-package="org.example" scope-resolver="org.example.MyScopeResolver" /> </beans>
當使用某些非singleton的作用域時,可能需要為這些作用域中的對象生成代理。 原因在標題為第?3.4.4.5?節(jié) “作用域bean與依賴”的章節(jié)中已經(jīng)說過了。 為了這個目的,'component-scan'元素有一個scoped-proxy屬性。 三個可能值是:'no'、'interfaces'和'targetClass'。比方說,下面的配置會產(chǎn)生標準的JDK動態(tài)代理:
<beans ...> <context:component-scan base-package="org.example" scoped-proxy="interfaces" /> </beans>
在名為第?3.11.2?節(jié) “基于注解的自動連接微調(diào)”的章節(jié)里引入了@Qualifier
注解。
那節(jié)的例子中演示了@Qualifier
注解的用法,以及如何用自定義限定符注解在自動織入解析時提供精細控制。
那些例子是基于XML bean定義的,所以限定符元數(shù)據(jù)是在XML中由'bean
'元素的
'qualifier
'或'meta
'子元素提供。使用classpath掃描來自動檢測組件時,
限定符元數(shù)據(jù)可以由候選類上的類別級(type-level)注解來提供。下面的三個例子就演示了這個技術(shù)。
@Component @Qualifier("Action") public class ActionMovieCatalog implements MovieCatalog { // ... }
@Component @Genre("Action") public class ActionMovieCatalog implements MovieCatalog { // ... }
@Component @Offline public class CachingMovieCatalog implements MovieCatalog { // ... }