spring-ioc-annotation

####7.9基於註解的容器配置 ####前言:註解配置好仍是xml配置好? 兩者各有千秋.java

  • 註解配置:更短更簡潔,缺點:配置分散,不宜管理;須要從新編譯.
  • xml配置:不直接與代碼交互,易於管理;缺點:冗長
  • 使用基於Java配置,能夠更好的糅合雙方的優勢

在字節碼文件裏注入組件而不是角括號申明.開發者能夠將註解添加在相關的類,方法,屬性聲明上歷來注入依賴組件.使用bean後處理器來糅合註解是spring ioc 容器擴展的通用方式.例如,spring2.0引用了強制要求的@Required註解.值得一提的是,@Autowired註解提供了和7.4.5部分中的"Autowiring collaborators"相同的做用功能,但具備更好的控制和更廣的應用.@PostConstruct,@PreDestroy,@Inject,@Namedspring

你能夠在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:annotation-config/>

</beans>

已詳細註冊的後處理器,包括AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor;緩存

context:annotation-config/只查找上下文中定義的註解. ####7.9.1 @Required 這個註解使用bean中屬性的Setter方法;app

public class SimpleMovieLister {

		private MovieFinder movieFinder;

		@Required
		public void setMovieFinder(MovieFinder movieFinder) {
			this.movieFinder = movieFinder;
		}

		// ...

	}

這個註解申明其標註的屬性必須在配置時間被操做,經過一些指定值或經過自動裝配.若是屬性沒有被操做,spring啓動會有明確的失敗,以免以後的空指針異常.使用它能夠保障必須引用.工具

####7.9.2 @Autowired @Inject註解能夠替代@Autowired註解. 你可使用@Inject註解來替代@Autowired註解;ui

能夠在構造器中使用@Autowired註解this

public class MovieRecommender {

		private final CustomerPreferenceDao customerPreferenceDao;

		@Autowired
		public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
			this.customerPreferenceDao = customerPreferenceDao;
		}

		// ...

	}

在spring4.3中,bean若是隻定義了一個構造器,@Autowired註解沒有使用必要.多個構造器才必須這麼作.代理

  • 將@Autorwired註解標記在set方法上
  • 加在任何參數,任何名字的方法上
  • 加載數組類型上.
  • 加在集合類型參數上
  • 能夠經過Orderder接口,@Order或@Priority註解來實現Array或list裏元素排序
  • Map類型的參數,key是bean的名稱,values包含bean的全部期待值

通常而言,若是沒有可選的beans,那麼註解將會失敗,默認的行爲是將該註解下的方法,字段,構造器視爲必須的依賴,然能夠以下改變它.指針

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired(required=false)
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...

}

一個類只有一個構造器標誌爲required,但non-required的構造器能夠有不少.這種狀況下,爲了使每個候選者都會考慮,spring將會使用最貪婪的構造器(擁有最多的參數),這樣依賴都會適配.

@Autowired註解裏的Required屬性,若是是false,代表若是沒法注入,是能夠接受的,不是必須的.若是是true,則是必須的,若是沒法注入,容器沒法啓動

你能夠用@Autowired來解決一些經常使用的依賴:Beanfactory,ApplicationContext,Environment,ResourceLoader,ApplicationEventPublisher,MessageSource.這些接口和他們的擴展接口,如ConfigurableApplicationContext,ResourcePatternResolver,均可以自注入.無需安裝.

如@Autowired,@Inject,@Resource,@Value註解只能被spring的BeanPostProcessor實現處理,你本身的beanPostProcessor或BeanPostProcessor類型沒法處理他們.這些類型必須由xml或spring的帶有Bean的方法來注入.

由於自動注入可能會致使混合選項,全部有必要對其選擇過程進行控制.一種方式是使用@Primary註解.@Primary代表一個特定的bean在不少同一類型的候選中,必需要選擇該bean的實例注入.

@Configuration
public class MovieConfiguration {

    @Bean
    @Primary
    public MovieCatalog firstMovieCatalog() { ... }

    @Bean
    public MovieCatalog secondMovieCatalog() { ... }

    // ...

}

下文中注入的是名爲firstMovieCatalog的bean的實例; public class MovieRecommender {

@Autowired
private MovieCatalog movieCatalog;

// ...

}

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:annotation-config/>

    <bean class="example.SimpleMovieCatalog" primary="true">
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>

####7.9.4 Fine-tuning annotation-based autowiring with qualifiers(基於註解的候選者的自動注入的微調) @Qualifier是@Autowired控制的另外一個工具.

  • 最簡單的例子,Qualifier能夠是一個簡單的值

public class MovieRecommender {

@Autowired
@Qualifier("main")
private MovieCatalog movieCatalog;

// ...

}

這個@Qualifier註解能夠指定構造器參數或方法參數;

public class MovieRecommender {

		private MovieCatalog movieCatalog;

		private CustomerPreferenceDao customerPreferenceDao;

		@Autowired
		public void prepare(@Qualifier("main")MovieCatalog movieCatalog,
				CustomerPreferenceDao customerPreferenceDao) {
			this.movieCatalog = movieCatalog;
			this.customerPreferenceDao = customerPreferenceDao;
		}

		// ...

	}

根據上面的的類定義,將會匹配qualifier的值爲'mian'的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/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier value="main"/>

        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier value="action"/>

        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>

通常而言,bean的名字會默認是qualifier的值.所以,你可使用'main'來替代內嵌的限定元素(它會致使相同的匹配結果).然而,儘管你可使用本公約以名字來制定特定的bean,然@Autowired其實是類型驅動注入包含語義限制的.這意味着限定符的值,同bean的名字回收,一般只是窄化類型匹配的集合;他們沒有從語法上指向一個獨一無二的bean的id.好的限制符,如'main','EMEA'或者'persistent',表達了一個特定的不一樣於bean的id的獨立組件,畢竟bean的id會在匿名的bean定義裏自動產生;

Qualifiers也適用於類型集合,例如,上文所說的Set<MovieCatalog>.在這種狀況下,全部匹配的bean會依據宣佈的匹配符注入爲一個集合.它代表限制符不是惟一的,他們只是簡單的構成過濾條件.例如,你能夠定義混合的MovieCatalog的bean以相同的限制符'action'.全部的符合@Qualifier("action")條件的bean將注入到Set<MovieCatalog>集合裏.

  • 若是你要傾向於經過名字的註解驅動注入,不推薦@Autowired,即便經過@Qualifier值來指向一個bean是技術可行的.你應該使用@Resource註解,它在語義上經過惟一的名字來定義目標的組件,而他們的申明類型並不會參與匹配.@Atuowired則是另外的語義:經過類型選擇候選者以後,纔會考慮特定的string的qualifier的值,只有匹配該值的qualifier的bean才能注入.

  • 對於定義成list/map或者數組類型的bean是來講,@Resource是一個好的方案,經過一個惟一的名字指向特定的數組或集合.這意味着,在4.3中,集合或數組類型能夠經過spring的@Autowired進行類型匹配.

  • 在4.3中,@Autowired也能夠考慮自注入,即引用到正在注入的bean.自注入是一個回退;常規注入仍然有優先級.也就是說,自引用不是常規候選項,所以他沒有優先級;相反,他們(自注入)的優先級是最低的.實際上,使用自引用是最後的手段.例如:經過bean的事務代理調用相同bean的其餘方法,在此場景下能夠考慮將受影響的方法分解到單獨的代理bean中.

  • @Autowired適用於字段,構造器,混成參數方法,經過@Qualifier註解來限制參數範圍.相反的,@Resource註解支持字段,bean的單參數的set方法.所以,它會嚴格按照qualifiers來匹配你構造器或混合參數方法的注入目標.

######使用自定義的qualifier; 定義以下:

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {

    String value();
}

以下使用該註解

public class MovieRecommender {

    @Autowired
    @Genre("Action")
    private MovieCatalog actionCatalog;
    private MovieCatalog comedyCatalog;

    @Autowired
    public void setComedyCatalog(@Genre("Comedy") MovieCatalog comedyCatalog) {
        this.comedyCatalog = comedyCatalog;
    }

    // ...

}

你能夠在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:annotation-config/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="Genre" value="Action"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="example.Genre" value="Comedy"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>

即在<bean>標籤裏使用<qualifier>標籤,其屬性爲type,value;

使用無具體值的自定義qualifier;

註解Offline定義以下:

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Offline {

}
  • 以下使用註解
public class MovieRecommender {

    @Autowired
    @Offline
    private MovieCatalog offlineCatalog;

    // ...

}
  • 用Offline定義一個Bean
<bean class="example.SimpleMovieCatalog">
    <qualifier type="Offline"/>
    <!-- inject any dependencies required by this bean -->
</bean>

你能夠自定義一個註解接受命名參數來替代簡單的註解,

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MovieQualifier {

    String genre();

    Format format();

}

Format枚舉以下:

public enum Format {
    VHS, DVD, BLURAY
}

這些字段經過自定義匹配符註解來自動注入的包括如下屬性的值:genre,format.

public class MovieRecommender {

    @Autowired
    @MovieQualifier(format=Format.VHS, genre="Action")
    private MovieCatalog actionVhsCatalog;

    @Autowired
    @MovieQualifier(format=Format.VHS, genre="Comedy")
    private MovieCatalog comedyVhsCatalog;

    @Autowired
    @MovieQualifier(format=Format.DVD, genre="Action")
    private MovieCatalog actionDvdCatalog;

    @Autowired
    @MovieQualifier(format=Format.BLURAY, genre="Comedy")
    private MovieCatalog comedyBluRayCatalog;

    // ...

}

最後,這個bean定義必須包含匹配符的值.這個例子也說明bean的元屬性能夠用來替代<qualifier>的下級元素.通常狀況下,<qualifier/>和它的屬性有優先級,但若是沒顯示的匹配符,那麼自動裝配機制將會使用meta標籤.下面的例子至少有兩種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/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="MovieQualifier">
            <attribute key="format" value="VHS"/>
            <attribute key="genre" value="Action"/>
        </qualifier>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="MovieQualifier">
            <attribute key="format" value="VHS"/>
            <attribute key="genre" value="Comedy"/>
        </qualifier>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <meta key="format" value="DVD"/>
        <meta key="genre" value="Action"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <meta key="format" value="BLURAY"/>
        <meta key="genre" value="Comedy"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

</beans>

####7.9.5 使用泛型做爲自動裝配的匹配符 除了@Qualifier註解外,你還能夠用java原生類型做爲匹配符的一種形式,通常狀況下,你須要如此配置:

@Configuration
public class MyConfiguration {

    @Bean
    public StringStore stringStore() {
        return new StringStore();
    }

    @Bean
    public IntegerStore integerStore() {
        return new IntegerStore();
    }

}

上面的bean實現了泛型接口,好比Store<String>和Store<Integer>,你可使用@Autowire進行注入,泛型將會做爲匹配符:

@Autowired
private Store<String> s1; // <String> qualifier, injects the stringStore bean

@Autowired
private Store<Integer> s2; // <Integer> qualifier, injects the integerStore bean

泛型匹配符也能夠用來注入List,Maps,Arrays

// Inject all Store beans as long as they have an <Integer> generic
// Store<String> beans will not appear in this list
@Autowired
private List<Store<Integer>> s;

###7.9.6 CustomAutowireConfigurer(自定義自動專配配置器) 使用了CustomAutowireConfigurer(自己是一個BeanFactoryPostProcessor組件)以後,即便你的自定義qualifier沒有加上@Qualifier註解,你也能夠註冊你的自定義qualifier;

<bean id="customAutowireConfigurer"
        class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
    <property name="customQualifierTypes">
        <set>
            <value>example.CustomQualifier</value>
        </set>
    </property>
</bean>

AutowireCandidateResolver經過如下判斷注入條件:

  • 經過每一個bean定義裏的autowire-candidate值
  • 經過<beans/>標籤裏的default-autowire-candidates模式
  • 經過顯式的@Qualifier註解和任何經過CustomAutowireConfigurer註冊的自定義匹配符註解

當一個混合的beans的匹配符做爲自動裝配候選者,主要的候選者以下肯定:假如一個候選者bean定義中設置了primary屬性爲true,它就會被選中.

@Resource

spring也支持使用@Resource註解來修飾字段或bean的屬性設置方法.這是java EE 5和6中的公共模式,例如JSF1.2中的被管理bean或JAX-WS2.0端點.spring也支持該模式.

@Resource 提供了一個name屬性,spring默認會攔截bean的名稱進行過濾.也就是說,它遵循經過名稱語法,就想下面例子所示:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Resource(name="myMovieFinder")
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

}

若是名字沒有且明確指出,那麼默認名稱未來源於字段名稱或set方法.若是是字段,它取字段名稱;若是是set方法,它取設置的屬性名稱.因此如下的例子中將把名字爲'movieFinder'的bean注入到這個setter方法裏;

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Resource
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

}

######注 由@Resource註解提供的名字會經過CommonAnnotationBeanPostProcessor感知而被ApplicationContext處理爲bean的名稱.若是你明確的註冊了SimpleJndiBeanFactory,這些名字會由JNDI進行處理.可是,提醒一下,你最好依賴容器默認行爲並少使用spring的JNDI查找能力,這樣能夠保持間接的水平.

若是@Resource沒有指定具體的名稱,用法同@Autowired相同,@Resource會進行類型匹配以替代適配符匹配並用來解決一些經常使用的依賴:beanFactory,ApplicationContext,ResourceLoader,ApplicationEventPublisher,MessageSource接口.

下面的例子中,customerPerferenceDao字段首先查找一個名爲customPerferenceDao的bean,若是失敗則查看類型是否匹配CusstomerPreferencceDao.這個"context"字段將依據已知的依賴類型ApplicationContext進行注入.

public class MovieRecommender {

    @Resource
    private CustomerPreferenceDao customerPreferenceDao;

    @Resource
    private ApplicationContext context;

    public MovieRecommender() {
    }

    // ...

}

####7.9.8 @PostConstruct and @PreDestroy 構造以後,銷燬以前 CommonAnnotationBeanPostProcessor不只識別@Resourece註解,也識別JSR-250中生命週期註解.在spring2.5中引入的,對這些註解的支持提供了初始化回調和銷燬回調時的其餘可選項.經過被spring ApplicationContext註冊的CommonAnnotationBeanPostProcessor,一個帶有一個或多個註解的方法能夠在什麼週期同一點上被調用,做爲spring的生命週期接口方法或顯示的申明回調方法.下面的例子中,這些緩存會再初始化以前操做,並在銷燬以後清理.

public class CachingMovieLister {

    @PostConstruct
    public void populateMovieCache() {
        // populates the movie cache upon initialization...
    }

    @PreDestroy
    public void clearMovieCache() {
        // clears the movie cache upon destruction...
    }

}
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息