這篇講解Bean管理的注解實現(xiàn)及例子
主要內(nèi)容有:
- Classpath掃描與組件管理
- 類的自動檢測和注冊Bean
- <context:annotation-config/>
- @Component、@Repository、@Service迈窟、@Controller
- @required
- @Autowired
- @Qualifier
- @Resource
一、classpath掃描與組件管理
- 從Spring3.0開始忌栅,SpringJavaConfig項目提供了很多特性车酣,包括使用Java而不是xml定義bean,比如@Configuration索绪、@Bean湖员、@Import、@DependsOn等等瑞驱。之所以使用注解娘摔,主要是為了降低使用xml設(shè)置bean的工作量。
- @Component是一個通用注解唤反,可用于任何bean凳寺;
- @Repository、@Service彤侍、@Controller是更有針對性的注解读第,也是@Component的子注解:
- @Repository通常用于注解Dao類,即持久層
- @Service通常用于注解Service類拥刻,即服務層
- @Controller通常用于注解Controller類怜瞒,即控制層(MVC)
元注解(Meta-annotations)
- 許多Spring提供的注解可以作為自己的代碼,即“元數(shù)據(jù)注解”般哼,元注解是一個簡單的注解吴汪,可以應用到另一個注解。
- 除了value()蒸眠,元注解還可以有其他屬性漾橙,允許自定義
關(guān)于注解可以參考,我之前寫的一篇文章:理解java注解
類的自動檢測及bean的注冊
- Spring可以自動檢測類并注冊bean到ApplicationContext中楞卡。其中注解可以注冊在類上也可以注冊在方法霜运、變量上。
<context:annotation-config/>:
- 通過在基于XML的Spring配置如下標簽(請注意包含上下文命名空間)
- <context:annotation-config/>僅會查找在同一個ApplicaitonContext中的bean注解
- 可以掃描已經(jīng)注冊在IoC容器中的bean的基于方法或者成員變量的注解
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<context:annotation-config/>
</beans>
- 為了能夠檢測這些類并注冊相應的bean蒋腮,需要下面內(nèi)容
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<context:component-scan base-package="org.example"/>
</beans>
- <context:component-scan>可以掃描基于類的注解
- <context:component-scan>包含<context:annotation-config>淘捡,通常在使用<context:component-scan>后,就不再使用<context:annotation-config>
- AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor也會被包含進來
使用過濾器進行自定義掃描
- 默認情況下池摧,類被自動發(fā)現(xiàn)并注冊bean的條件是:使用@Component焦除,@Repository,@Service作彤,@Controller注解或者使用@Component的自定義注解
- 可以通過過濾器修改上面的行為膘魄,如乌逐,下面的例子的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>
- 還可以使用use-default-filters="false"禁用自動發(fā)現(xiàn)與注冊梭冠。
過濾類別 | 示例 | 說明 |
---|---|---|
annotation | org.example.SomeAnnotation | 所有標注了SomeAnnotation的類。該類型采用目標類是否標注了某個注解進行過濾 |
assignable | org.example.SomeClass | 所有繼承或擴展SomeClass的類只嚣。該類型采用目標類是否繼承或擴展某個特定類進行過濾 |
aspectj | org.example..*Service+ | 所有類名以Service結(jié)束的類及繼承或擴展了它們的類灿渴。該類型采用AspectJ表達式進行過濾 |
regex | org\.example\.Default.* | 所有org.example.Default包下的類成黄。該類型采用正則表達式根據(jù)類的類名進行過濾 |
custom | org.example.MyTypeFiflter | 采用MyTypeFiflter通過代碼的方式定義過濾規(guī)則。該類必須實現(xiàn)org.springframework.core.type.TypeFiflter接口 |
理解spring注解逻杖,參考:JAVA 注解的學習和對Spring注解的理解
定義BeanName(IoC容器總的beanId)
- 掃描過程中組件被自動檢測奋岁,那么Bean名稱是由BeanNameGenerator生成的(@Component、@repository荸百、@Service闻伶、@Controller都會有個name屬性用于顯式設(shè)置Bean Name)
例如:
顯式設(shè)置beanName,也就是直接設(shè)置IoC文件中的beanId:
@Service("TestResourceService")
public class TestResource implements ApplicationContextAware {
//……
}
不顯式設(shè)置beanName的話够话,BeanNameGenerator會根據(jù)一定規(guī)則生成beanName蓝翰,即類名首字母小寫:
@Service
public class TestResource implements ApplicationContextAware {
//……
}
- 可自定義bean命名策略,實現(xiàn)BeanNameGenerator接口女嘲,并一定要包含一個無參數(shù)構(gòu)造器畜份。
記得在IoC注冊,例如:
<beans>
<context:component-scan base-package="org.example"
name-generator="org.example.MyNameGenerator"/>
</beans>
作用域(Scope)
- 通常情況下自動查找的Spring組件欣尼,其scope是singleton爆雹,Spring2.5提供了一個標識scope的注解@Scope。
@Scope("prototype")
@Service("TestResourceService")
public class TestResource implements ApplicationContextAware {
//……
}
- 也可以自定義scope策略愕鼓,實現(xiàn)ScopeMetadataResolver接口并提供一個無參構(gòu)造器钙态。
<beans>
<context:component-scan base-package="org.example"
scope-resolver="org.example.MyScopeResolver"/>
</beans>
代理方式
- 可以使用scoped-proxy屬性指定代理,有三個值可選:no菇晃、interfaces册倒、targetClass
<beans>
<context:component-scan base-package="org.example"
scope-proxy="interfaces"/>
</beans>
寫個示例:
- IoC容器中添加<context:component-scan>:
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<context:component-scan base-package="test9"></context:component-scan>
</beans>
- 在test9包下新增一個BeanAnnotation類并使用@Component注解:
package test9;
import org.springframework.stereotype.Component;
@Component
public class BeanAnnotation {
public void say(String str) {
System.out.println("BeanAnnotation:" + str);
}
}
- junit測試:
@Test
public void test9(){
BeanAnnotation beanAnnotation=super.getBean("beanAnnotation");
beanAnnotation.say("類的自動檢測及bean的注冊");
}
- 顯式指定beanName:
@Component("myBeanAnnotation")
public class BeanAnnotation {
public void say(String str) {
System.out.println("BeanAnnotation:" + str);
}
}
- junit測試:
@Test
public void test9(){
BeanAnnotation beanAnnotation=super.getBean("myBeanAnnotation");
beanAnnotation.say("類的自動檢測及bean的注冊");
}
- 在類中增加@Scope注解和showHashCode()方法
@Scope("prototype")
@Component("myBeanAnnotation")
public class BeanAnnotation {
public void say(String str) {
System.out.println("BeanAnnotation:" + str);
}
public void showHashCode(){
System.out.println("HashCode:" + hashCode());
}
}
- junit測試:
@Test
public void test9(){
BeanAnnotation beanAnnotation=super.getBean("myBeanAnnotation");
beanAnnotation.showHashCode();
BeanAnnotation beanAnnotation2=super.getBean("myBeanAnnotation");
beanAnnotation2.showHashCode();
}
-
結(jié)果如下圖,使用@Scope注解修改作用域成功~:
Paste_Image.png 將@Scope的值去掉磺送,還原它本身的樣子
@Scope
@Component("myBeanAnnotation")
public class BeanAnnotation {
public void say(String str) {
System.out.println("BeanAnnotation:" + str);
}
public void showHashCode(){
System.out.println("HashCode:" + hashCode());
}
}
-
再次執(zhí)行junit測試驻子,結(jié)果如圖:
Paste_Image.png
@Required
- @Required注解適用于bean屬性的setter方法。
- 這個注解僅僅表示估灿,受影響的bean屬性必須在配置時被填充崇呵,通過在bean的定義或通過自動裝配的一個明確屬性值。
@Component("myBeanAnnotation")
public class BeanAnnotation {
private TestResource testResource;
@Required
public void setTestResource(TestResource testResource) {
this.testResource = testResource;
}
}
@Autowired
- 可以將@Autowired注解理解為“傳統(tǒng)”的setter方法甲捏。
@Component("myBeanAnnotation")
public class BeanAnnotation {
private TestResource testResource;
@Autowired
public void setTestResource(TestResource testResource) {
this.testResource = testResource;
}
- 可用于構(gòu)造器或成員變量
@Component("myBeanAnnotation")
public class BeanAnnotation {
@Autowired
private TestResource testResource;
private AutoWiringDao autoWiringDao;
@Autowired
public BeanAnnotation(AutoWiringDao autoWiringDao) {
}
}
- 默認情況下演熟,如果因找不到合適的bean將會導致autowiring失敗拋出異常,可以通過下面的方式避免司顿。
@Component("myBeanAnnotation")
public class BeanAnnotation {
private TestResource testResource;
@Autowired(required = false)
public void setTestResource(TestResource testResource) {
this.testResource = testResource;
}
}
- 每個類只能有一個構(gòu)造器被標記為required=true
- @Autowired的必要屬性芒粹,建議使用@Required注解
關(guān)于Spring自動裝配可以參考:spring的自動裝配
關(guān)于Autowired自動裝配的示例:
- service層實現(xiàn)類:
@Service
public class TestServiceImpl implements TestService {
//@Autowired用于成員變量(不需要寫setter方法了)
@Autowired
private TestDao testDao;
@Override
public void save(String str) {
//模擬業(yè)務操作
System.out.println("TestServiceImpl接收參數(shù):" + str);
str = str + ":" + this.hashCode();
testDao.save(str);
}
}
- junit測試:
@Test
public void test10() {
TestServiceImpl testService = super.getBean("testServiceImpl");
testService.save("this is autowired");
}
-
結(jié)果:
Paste_Image.png - 修改service層,將@Autowire設(shè)置在setTestDao()方法上:
@Service
public class TestServiceImpl implements TestService {
private TestDao testDao;
//@Autowired用于setter方法和用于變量是一個意思
@Autowired
public void setTestDao(TestDao testDao) {
this.testDao = testDao;
}
@Override
public void save(String str) {
//模擬業(yè)務操作
System.out.println("TestServiceImpl接收參數(shù):" + str);
str = str + ":" + this.hashCode();
testDao.save(str);
}
}
-
結(jié)果:
Paste_Image.png 修改service層大溜,將@Autowire設(shè)置在構(gòu)造器方法上:
@Service
public class TestServiceImpl implements TestService {
private TestDao testDao;
//@Autowired用構(gòu)造
@Autowired
public TestServiceImpl(TestDao testDao) {
this.testDao = testDao;
}
@Override
public void save(String str) {
//模擬業(yè)務操作
System.out.println("TestServiceImpl接收參數(shù):" + str);
str = str + ":" + this.hashCode();
testDao.save(str);
}
}
-
結(jié)果:
Paste_Image.png
繼續(xù)學習@Autowired
- 可以使用@Autowired注解那些眾所周知的解析依賴性接口化漆。比如:BeanFactory、ApplicationContext钦奋、Environment座云、resourceLoader、ApplicationEventPublisher付材、MessageSource朦拖。
- 可以給集合添加@Autowired注解,例如List<interface>厌衔,ApplicationContext中所有符合條件的此接口的實現(xiàn)類(bean)會傳入到List中璧帝。
@Autowired
private List<BeanInterface> list;
- 可以給Map<String,Interface>添加@Autowired注解,例如:Map<String,BeanInterface>富寿,在ApplicationContext中符合條件的此接口實現(xiàn)類會自動被加入到map中睬隶。其中key為beanId,Value是bean本身页徐。
@Autowired
private Map<String,BeanInterface> map;
- 如果希望集合有序苏潜,可以讓bean實現(xiàn)org.springframework.core.Ordered接口或使用@Order注解
- @Antowired是由Spring BeanPostProcessor處理的,所以不能在自己的BeanPostProcessor或BeanFactoryPostProcessor類型應用這些注解变勇,這些類型必須通過xml或者Spring的@Bean注解加載恤左。
數(shù)組及Map的自動注入例子
- 準備工作
- 新建一個接口
package test11;
/**
* Created by amber on 2017/6/15.
*/
public interface BeanInterface {
}
* 新建兩個它的實現(xiàn)類BeanImplOne 、BeanImplTwo 并添加通用注解@Component
package test11;
import org.springframework.stereotype.Component;
/**
* Created by amber on 2017/6/15.
*/
@Component
public class BeanImplOne implements BeanInterface {
}
package test11;
import org.springframework.stereotype.Component;
/**
* Created by amber on 2017/6/15.
*/
@Component
public class BeanImplTwo implements BeanInterface {
}
- 新建一個調(diào)用類BeanInvoker 在其類上添加了注解@Component搀绣,兩個屬性 List<BeanInterface>和Map<String,BeanInterface>也添加了@Autowired注解赃梧。
package test11;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
/**
* Created by amber on 2017/6/15.
*/
@Component
public class BeanInvoker {
@Autowired
private List<BeanInterface> list;
@Autowired
private Map<String,BeanInterface> map;
public void say(){
if(list!=null){
System.out.println("list is not null! ");
for(BeanInterface item : list){
System.out.println("className: "+item.getClass().getName());
}
}else {
System.out.println("list is null! ");
}
if(map!=null){
System.out.println("map is not null! ");
for(Map.Entry item : map.entrySet()){
System.out.println("key: "+item.getKey()+ " className: "+item.getValue().getClass().getName());
}
}else {
System.out.println("map is null! ");
}
}
}
- 測試函數(shù):
@Test
public void test11() {
BeanInvoker invoker=super.getBean("beanInvoker");
invoker.say();
}
-
結(jié)果:
Paste_Image.png - 增加集合類型的排序,在兩個實現(xiàn)類上使用@Order
package test11;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* Created by amber on 2017/6/15.
*/
@Order(2)
@Component
public class BeanImplOne implements BeanInterface {
}
package test11;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* Created by amber on 2017/6/15.
*/
@Order(1)
@Component
public class BeanImplTwo implements BeanInterface {
}
經(jīng)過排序豌熄,BeanImplTwo 就對照@Order(1)授嘀,先被加入到list中了。
Qualifier
- 因為@Autowired默認是按類型查找注入的锣险,所以可能多個bean實例的情況蹄皱,這時可以使用Spring的Qualifier注解(變成按名稱查找)縮小范圍或指定唯一,也可以用于指定單獨的構(gòu)造器參數(shù)或方法參數(shù)芯肤。
- 可用于注解集合類型變量巷折。
- 如果通過名字進行注解注入,主要使用的不是@Autowired(即使在技術(shù)上能夠通過@Qualifier指定bean的名字)崖咨,替代方式是使用JSR-250@Resource注解锻拘,它是通過其獨特的名稱來定義來識別特定的目標(這是一個與所聲明類型無關(guān)的匹配過程)。
- 因語義的差異,集合或Map類型的bean署拟,無法通過@Autowired來注入婉宰,因為沒有類型匹配到這樣的bean,為這些bean使用@Resource注解推穷,通過唯一名稱引用集合或者Map的bean心包。
- @Autowired適用于局部變量、構(gòu)造馒铃、多參數(shù)方法這些允許在參數(shù)級別使用@Qualifier注解縮小范圍的情況蟹腾。
- @Resource適用于成員變量、只有一個參數(shù)的setter方法区宇,所以在目標是構(gòu)造器或一個多參數(shù)的方法時娃殖,最好的方式是使用@Qualifier。
在xml配置文件中使用qualifier 议谷,就相當于beanid:
<bean class="test11.BeanImplOne">
<qualifier value="main"/>
</bean>
上一個測試得知BeanInterface 有兩個實現(xiàn)類炉爆,我現(xiàn)在使用@Qualifier注解指定只注入其中一個:
@Autowired
@Qualifier("beanImplOne")
private BeanInterface beanInterface;
public void say(){
if(beanInterface!=null){
System.out.println("name: "+beanInterface.getClass().getName());
}else {
System.out.println("beanInterface is null! ");
}
}
結(jié)果:
基于Java容器的注解@Bean
- @Bean標識一個用于配置和初始化一個由ApringIoC容器管理的新對象的方法,類似于xml配置文件的<bean/>柿隙。
- 可以在Spring的@Componet注解的類中使用@Bean注解任何方法(僅僅是可以)叶洞。
- 通常和@Bean結(jié)合使用的是@Configuration。
- @Bean在方法上注解禀崖,方法名是bean默認的id衩辟。
示例:
- 創(chuàng)建一個Store接口:
package test12;
/**
* Created by amber on 2017/6/15.
*/
public interface Store {
}
- 創(chuàng)建一個它的是實現(xiàn)類,StringStore:
package test12;
/**
* Created by amber on 2017/6/15.
*/
public class StringStore implements Store {
}
- 創(chuàng)建StringConfig
package test12;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Created by amber on 2017/6/15.
*/
@Configuration
public class StringConfig {
@Bean
public Store getStringStore(){
return new StringStore();
}
}
- 測試方法:
@Test
public void test12() {
Store store=super.getBean("getStringStore");
System.out.println("store name: "+store.getClass().getName());
}
結(jié)果:
- 指定@Bean(name="xx")
package test12;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Created by amber on 2017/6/15.
*/
@Configuration
public class StringConfig {
@Bean(name = "stringStore")
public Store getStringStore(){
return new StringStore();
}
}
@Test
public void test12() {
Store store=super.getBean("stringStore");
System.out.println("store name: "+store.getClass().getName());
}
結(jié)果:
- 指定這個bean的init和destroy方法
@Bean(name = "stringStore",initMethod="init",destroyMethod = "destroy")
public Store getStringStore(){
return new StringStore();
}
StringStore類添加init和destroy方法:
package test12;
/**
* Created by amber on 2017/6/15.
*/
public class StringStore implements Store {
public void init(){
System.out.println("StringStore初始化");
}
public void destroy(){
System.out.println("StringStore銷毀");
}
}
運行結(jié)果:
基于Java容器的注解@ImportResource和@Value注解進行資源文件讀取并把結(jié)果注入到對應屬性
- 使用xml進行配置:
- 通過<context:property-placeholder location="classpath:jdbc.properties"/>加載配置文件
- <property name="url" value="${db.url}"></property>通過EL表達式獲取對應屬性的值
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: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/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<context:component-scan base-package="test12"></context:component-scan>
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${db.url}"></property>
<property name="username" value="${db.username}"></property>
<property name="password" value="${db.password}"></property>
</bean>
</beans>
jdbc.properties文件:
db.driverLocation=I:/IdeaProjects/mysql-connector-java-5.1.6-bin.jar
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://127.0.0.1:3306/ambermall?characterEncoding=utf-8
db.username=root
db.password=amber
- 使用注解進行配置:
創(chuàng)建MyDriverManager類:
package test12;
/**
* Created by amber on 2017/6/16.
*/
public class MyDriverManager {
public MyDriverManager(){}
public MyDriverManager(String url,String userName,String password){
System.out.println("url: "+url+"\nuserName: "+userName+"\npassword: "+password);
}
}
修改之前的StringConfig類如下:
因為我加載的是.properties文件波附,所以注解使用@PropertySource艺晴。如果加載xml文件,請使用@ImportResource
package test12;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.PropertySource;
/**
* Created by amber on 2017/6/15.
*/
@Configuration
@PropertySource("classpath:jdbc.properties")
public class StringConfig {
@Value("${db.url}")
private String url;
@Value("${db.username}")
private String userName;
@Value("${db.password}")
private String password;
@Bean
public MyDriverManager myDriverManager(){
return new MyDriverManager(url,userName,password);
}
}
測試方法:
@Test
public void test12() {
MyDriverManager manager = super.getBean("myDriverManager");
if(manager!=null)
System.out.println(manager.getClass().getName());
}
結(jié)果:
@Bean和@Scope
- 使用@Bean注解掸屡,默認是單例模式的封寞。可以通過作用域注解@Scope仅财,更改其他模式狈究。
- @Scope的取值是:singleton、prototype盏求、request抖锥、session、global session碎罚。
下面示例:
- 更改StringConfig類
package test12;
import org.springframework.context.annotation.*;
/**
* Created by amber on 2017/6/15.
*/
@Configuration
public class StringConfig {
@Bean(name = "stringStore",initMethod = "init",destroyMethod = "destroy")
@Scope("prototype")
public Store stringStore() {
return new StringStore();
}
}
- 測試方法:
@Test
public void test12() {
for(int i=0;i<2;i++){
StringStore store = super.getBean("stringStore");
System.out.println(store.hashCode());
}
}
- 結(jié)果:細心的小伙伴可能發(fā)現(xiàn)磅废,多例之后,沒有執(zhí)行destroy的方法了荆烈,那是因為多例模式拯勉,每產(chǎn)生一個實例在使用完成后,都會自動被JVM垃圾回收器回收。
基于泛型的自動裝配
示例:
- 修改Store接口:
package test12;
/**
* Created by amber on 2017/6/15.
*/
public interface Store<T>{
}
- 修改實現(xiàn)類StringStore :
package test12;
/**
* Created by amber on 2017/6/15.
*/
public class StringStore implements Store<String> {
}
增加IntegerStore:
package test12;
/**
* Created by amber on 2017/6/16.
*/
public class IntegerStore implements Store<Integer> {
}
- 更改StringConfig 類:
package test12;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
/**
* Created by amber on 2017/6/15.
*/
@Configuration
public class StringConfig {
@Autowired
private StringStore s1;
@Autowired
private IntegerStore s2;
@Bean
public Store store() {
System.out.println("s1: "+s1.getClass().getName());
System.out.println("s2: "+s2.getClass().getName());
return new StringStore();
}
@Bean
public StringStore stringStore(){
return new StringStore();
}
@Bean
public IntegerStore integerStore(){
return new IntegerStore();
}
}
- 測試
@Test
public void test12() {
super.getBean("store");
}
-
結(jié)果:
Paste_Image.png
CustomAutowireConfigurer
- CustomAutowireConfigurer是一個BeanFactoryPostProcessor子類宫峦,這個后置處理器可以注冊開發(fā)者自己的限定符注解岔帽,讓開發(fā)者的注解不依賴于Spring限定符注解。
- 通過CustomAutowireConfigurer可以注冊自己的qualifier注解類型(即使沒有使用Spring的@qualifier注解)
<bean id="customAutowireConfigurer"
class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
<property name="customQualifierTypes">
<set>
<value>example.CustomQualifier</value>
</set>
</property>
</bean>
AutowireCandidateResolver用來處理customQualifierTypes的斗遏,通過以下的幾種方式來決定自動裝載的候選Bean:
* Bean定義中的autowire-candidate的值
* 任何<beans/>標簽中定義的default-autowire-candidates的值
* @Qualifier注解和任何在CustomAutowireConfigurer中定義的自定義的限定符注解
* 當多個Bean限定為自動裝載的候選時山卦, 前文中提到的primary屬性是優(yōu)先考慮的鞋邑。
@Resource
- Spring還支持使用JSR-250@Resource注解的變量或setter方法诵次,這是一種在java EE 5和6的通用方式,Spring管理的對象也支持這種模式枚碗。
- @Resource有一個name屬性逾一,并且默認Spring解釋該值,作為被注入bean的名稱肮雨。
- 如果沒有顯式地指定@Resource的name遵堵,默認的名稱是從屬性名或者setter方法得出。
- 注解提供的名字怨规,被解析為一個bean名稱陌宿,這是由ApplicationContext中的CommonAnnotationBeanPostProcesser發(fā)現(xiàn)并處理的。
@PostConstruct 和 @PreDestroy
- CommonAnnotationBeanPostProcesser類不僅能識別JSR-250中的生命周期注解@Resource波丰,在Spring2.5中引入支持初始化回調(diào)(@PostConstruct)和銷毀回調(diào)( @PreDestroy)壳坪,前提是CommonAnnotationBeanPostProcesser類是Spring的ApplicationContext中注冊的。
下面示例:
- 創(chuàng)建JsrDao 類:
package test13;
import org.springframework.stereotype.Repository;
/**
* Created by amber on 2017/6/16.
*/
@Repository
public class JsrDao {
public void save(){
System.out.println("JsrDao invoked");
}
}
- 創(chuàng)建JsrService 類:
package test13;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* Created by amber on 2017/6/16.
*/
@Service
public class JsrService {
//@Resource注解在成員變量上或者方法上都是一樣的效果掰烟,二者選其一即可爽蝴,此處為了展示才都寫上了。此處也可以替換成@Autowired纫骑,效果也是一樣的
@Resource
private JsrDao jsrDao;
//@Resource注解在成員變量上或者方法上都是一樣的效果蝎亚,二者選其一即可,此處為了展示才都寫上了先馆。此處也可以替換成@Autowired发框,效果也是一樣的
@Resource
public void setJsrDao(JsrDao jsrDao) {
this.jsrDao = jsrDao;
}
public void save(){
jsrDao.save();
}
}
- 測試:
@Test
public void test13() {
JsrService jsrService=super.getBean("jsrService");
jsrService.save();
}
-
結(jié)果:
Paste_Image.png - 在JsrService 中添加@PostConstruct 和 @PreDestroy
package test13;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
/**
* Created by amber on 2017/6/16.
*/
@Service
public class JsrService {
@Resource
private JsrDao jsrDao;
@Resource
public void setJsrDao(JsrDao jsrDao) {
this.jsrDao = jsrDao;
}
@PreDestroy //銷毀回調(diào)
public void destroy(){
System.out.println("我是銷毀回調(diào)");
}
@PostConstruct //初始化回調(diào)
public void init(){
System.out.println("我是初始化回調(diào)");
}
public void save(){
jsrDao.save();
}
}
-
結(jié)果:
Paste_Image.png
使用JSR330標準注解
- 從Spring3.0開始支持JSR330標準注解(依賴注入注解),其掃描方式與Spring注解一致煤墙。
- 使用JSR330需要依賴javax.inject包
- 使用Maven引入方式
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
@Inject
- @Inject等效于@Autowired梅惯,可以使用于類、屬性番捂、方法个唧、構(gòu)造器。
@Named
- 如果想使用特定名稱進行依賴注入设预,使用@Named徙歼。
- @Named與@Component是等效的。
- @Named與@Qualifier類似。
下面示例:
- 修改JSRService類的注解@Service改成@Named
package test13;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Named;
/**
* Created by amber on 2017/6/16.
*/
@Named
public class JsrService {
@Inject
private JsrDao jsrDao;
@Inject
public void setJsrDao(JsrDao jsrDao) {
this.jsrDao = jsrDao;
}
@PreDestroy //銷毀回調(diào)
public void destroy(){
System.out.println("我是銷毀回調(diào)");
}
@PostConstruct //初始化回調(diào)
public void init(){
System.out.println("我是初始化回調(diào)");
}
public void save(){
jsrDao.save();
}
}
-
運行結(jié)果:
Paste_Image.png