天天看點

Spring5參考指南:基于注解的容器配置

文章目錄

    • @Required
    • @Autowired
    • @primary
    • @Qualifier
    • 泛型
    • @Resource
    • @PostConstruct和@PreDestroy

Spring的容器配置可以有兩種方式,一種基于XML檔案, 一種基于注解。注解注入在XML注入之前執行。是以,當兩個同時使用時,XML配置會覆寫注解注入的屬性。

本文會主要介紹 @Required,@Autowired, @PostConstruct, @PreDestroy 和 @Resource 這幾個注解。

這幾個注解都是由 context:annotation-config/ 來引入的。本質上引入這個配置會隐式的注冊AutoWiredAnnotationBeanPostProcessor(提供@Autowired),CommonAnnotationBeanPostProcessor(提供@PostConstruct, @PreDestroy, @Resource),RequiredAnnotationBeanPostProcessor(提供 @Required),進而提供各個注解的功能。

下面我們會分别介紹各個注解的功能。

@Required 一般用在方法上面,表示該方法的參數必須能通過配置或者自動裝載來填充。通常如果某個屬性是必須的,我們會使用這個注解。

不過從Spring Framework 5.1開始,@Required注解正式被棄用,取而代之的是使用構造函數注入用于所需的屬性,或使用InitializingBean.afterPropertiesSet()的自定義實作以及bean屬性setter方法。

示例代碼如下:

public class RequiredBean {

    private BeanA  beanA;

    @Required
    public void setBeanA(BeanA beanA){
        this.beanA=beanA;

    }
}      

@Autowired 就是自動注入所需要的字段,參數等。JSR 330的@Inject注解可以代替spring的@Autowired注解。

你可以将@Autowired注解到構造器中,如下所示:

public class AutowiredBean {

    private BeanA beanA;

    @Autowired
    public AutowiredBean(BeanA beanA){
        this.beanA=beanA;
    }
}      

從SpringFramework4.3開始,如果目标bean隻定義了一個構造函數,那麼就不再需要在此類構造函數上使用@Autowired注解。但是,如果有多個構造函數可用,則必須至少對其中一個進行注解,以告訴容器使用哪一個。

@Autowired也可以注解到傳統的setter方法,如下例子所示:

public class AutowiredBean {

    private BeanB beanB;

    @Autowired
    public void setBeanB(BeanB beanB){
        this.beanB=beanB;
    }
}      

也可以把注解應用到任何名字和多個參數,如下所示:

    @Autowired
    public void configAB(BeanA beanA , BeanB beanB){
        this.beanA=beanA;
        this.beanB=beanB;
        
    }      

@Autowired也可以用在字段上,如下所示:

    @Autowired
    private BeanC beanC;      

還可以通過将注解添加到需要該類型數組的字段或方法,那麼可以從ApplicationContext中擷取到該特定類型的所有bean,如下例所示:

    @Autowired
    private BeanC[] beanCList;      

如果希望數組或清單中的項按特定順序排序,目标bean可以實作org.springframework.core.Ordered接口,或者可以使用@Order或标準的@Priority注解。

否則,它們的順序遵循容器中相應目标bean定義的注冊順序。

Map執行個體也可以被注入,隻要key是String類型。Map value包括了所有的類型比對的Bean,keys是該bean的名字。如下所示:

    @Autowired
    public void configMapA(Map<String,BeanA> mapA){
    this.mapA=mapA;
    }      

@Autowired有個required屬性,如果要注入的bean有可能不存在,則可以如下所示:

    @Autowired(required = false)
    public void setBeanC(BeanC beanC){
    }      

建議使用@Autowired的’required’屬性而不是使用setter方法上的@Required注解。“required”屬性表示自動裝載需要該屬性, 如果無法自動裝載,則忽略該屬性。而對于@Required來說,如果未定義任何值,則會報異常。

也可以通過Java 8的java.util.Optional表示特定依賴項的非必需性質,如下示例顯示:

    @Autowired
    public void setMovieFinder(Optional<BeanC> BeanC) {
    }      

在Spring Framework 5.0中,你也可以使用@Nullable注解:

    @Autowired
    public void setMovieFinderC(@Nullable BeanC beanC) {
    }      

Spring可以使用@Autowired來自動解析一些預設存在的bean如:BeanFactory、ApplicationContext、Environment、ResourceLoader、ApplicationEventPublisher和MessageSource。這些接口及其擴充接口(如ConfigurableApplicationContext或ResourcePatternResolver)。

如下所示,自動注入ApplicationContext:

    @Autowired
    private ApplicationContext context;      

注意: @Autowired, @Inject, @Value, 和 @Resource 注解是在Spring的BeanPostProcessor中處理的,這意味着你不能将這些注解用在你自己的BeanPostProcessor,BeanFactoryPostProcessor類型。

當按類型注入的時候,可能會有多個候選項,則可以通過@Primary注解表示優先的對象。如下所示:

@Configuration
public class ConfigBean {

    @Bean
    @Primary
    public BeanA firstBeanA() { return new BeanA(); }

    @Bean
    public BeanA secondBeanA() {  return new BeanA();}

}      

@Primary是一種在多個執行個體中按類型使用自動裝載的有效方法,但是如果你希望對注入的Bean進行更細粒度的控制時候,可以使用@Qualifier。如下所示:

    @Bean
    @Qualifier("main")
    public BeanC beanC() {  return new BeanC();}      
    @Autowired
    @Qualifier("main")
    private BeanA beanA;

    @Autowired
    public void setBeanA(@Qualifier("main") BeanA beanA){

    }      

限定符的值并不是唯一的,它隻是一個過濾标準。

@Autowired一般用來通過類型比對,@Resource則是通過名稱比對。

也可以建立自定義注解:

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

        String value();
}      

除了@Qualifier注解外,還可以使用Java泛型類型作為隐式的限定形式。例如,假設您具有以下配置:

public class StringStore implements Store<String> {
}

public class IntegerStore implements Store<Integer> {
}      
    @Bean
    public StringStore stringStore() {
        return new StringStore();
    }

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

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

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

    // 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;

}      

@Resource用在字段或者Setter方法上,預設情況下@Resource通過名字來注入。

public class ResourceBean {
    
    @Resource(name = "beanA")
    private BeanA BeanA;
}      

如果未顯式指定名稱,則從字段名或setter方法派生預設名稱.

在@Resource用法中,如果沒有指定顯式名稱,并且類似于@Autowired,@Resource會找到一個主類型比對,而不是指定的bean,并解析已知的可解析依賴項:BeanFactory、ApplicationContext、ResourceLoader、ApplicationEventPublisher,和MessageSource接口。

這兩個注解主要用做生命周期回調。如下所示:

public class ConstructBean   {

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

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

與@Resource一樣,@PostConstruct和@PreDestroy注解類型是JDK 6到8标準Java庫的一部分。然而,整個javax.annotation包與JDK 9中的核心Java子產品分離,并最終在JDK 11中被删除。如果需要,javax.annotation-api工件現在需要通過maven central獲得,隻需像其他庫一樣添加到應用程式的類路徑中即可。

  • 區塊鍊從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特币等持續更新
  • Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續更新
  • Spring 5.X系列教程:滿足你對Spring5的一切想象-持續更新
  • java程式員從小工到專家成神之路(2020版)-持續更新中,附詳細文章教程