天天看點

Spring 核心(IOC)- 基于注解的容器配置

目錄

      • 基于注解的容器配置
          • 1. 使用@Autowired
          • 2.使用@Order
          • 3. 使用@Primary
          • 4. 使用@Qualifier
          • 5. 使用@Resource
          • 6. 使用@Value
          • 7. 使用@PostConstruct和@PreDestroy

基于注解的容器配置

注解配置和XML配置實作的功能是一樣的,隻是實作方式不同而已。并且,注解配置在XML配置之前執行。

首先通過在XML中通過配置可以隐式的注冊一些元件,當然你也可以顯式的定義bean。(注意引入context命名空間)

隐式注冊包含的元件有:

AutowiredAnnotationBeanPostProcessor

CommonAnnotationBeanPostProcessor

PersistenceAnnotationBeanPostProcessor

RequiredAnnotationBeanPostProcessor

1. 使用@Autowired

使用

@Autowired

實作注解式自動裝配。

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

    //指定此依賴性是否為非必須,預設true。
	boolean required() default true;

}
           

通常作用在變量上或方法上,首先按照byType注入,隻要容器中有唯一的bean對象類型相比對,則注入成功,若無比對,則報錯,若比對多個,則在其中再按照byName注入,若無比對,則報錯。此時set方法不是必須的了,見上文可知。

四種形式案例:

作用在構造方法上

public class UserServie {

    private UserDao userDao;

    @Autowired
    public UserServie(UserDao userDao) {
        this.userDao = userDao;
    }
}
           
  • 在單一構造方法場景下,即使不使用@Autowired注解,也會被用來進行自動裝配。
  • 在單一構造方法場景下,使用@Autowired注入存在着特殊規則,如多元素注入(數組、集合、Map等),在沒有比對bean時允許為空解析。
  • 在多個構造方法場景下,所有構造方法的@Autowired必須設定required為false,以便其都作為自動裝配的候選,自動裝配會選擇Spring容器比對bean可以滿足最大數量依賴項的構造方法,若無比對,則選擇主選項或預設項構造方法。

作用在set方法上

public class UserServie {

    private UserDao userDao;

    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}
           

作用在多個參數方法上

public class UserServie {

    private UserDao userDao;
    
    private ClubDao clubDao;

    @Autowired
    public void prepare(UserDao userDao, ClubDao clubDao) {
        this.userDao = userDao;
        this.clubDao = clubDao;
    }
}
           

作用在字段上

public class UserServie {
	
    @Autowired
    private UserDao userDao;
    
    //@Autowired 也可以和構造方法混用
    public UserServie(UserDao userDao) {
        this.userDao = userDao;
    }
}
           
  • 在XML配置的自動裝配中,屬性是通過set方法進行set注入的,而在注解注入中注解作用在字段上則可以不需要set方法。其原因是:@autowired注解關閉了通路控制權限,不再需要通過set注入了,直接通過已開放的屬性通過Java反射機制進行注入(即使它是私有的)。
  • 你還可以為複雜/集合類型進行注解注入,前提該類型bean以配置在容器中(建議在注入集合類型bean時,使用XML配置方式和注解配置方式混用)

Spring5版本中,你還可以在方法形參上使用

@Nullable

注解來使這個參數允許為空。

你也可以使用

@Autowired

注入一些可解析的依賴項:

BeanFactory

,

ApplicationContext

,

Environment

,

ResourceLoader

,

ApplicationEventPublisher

MessageSource

,或是其擴充接口

ConfigurableApplicationContext

ResourcePatternResolver

2.使用@Order

通過

@Order

注解使用在不同地方擁有不同的功能,數字越小優先級越高:

  • 使用在@Bean方法或元件類上時,可以在注入時調整其優先級順序。(如對數組/集合類型進行注入時,集合項中的順序由

    @Order

    決定)
  • 使用在配置類中,可以調整這些配置類容器的初始化順序。
注意:

@Order

并不會影響Bean的單例啟動順序(加載順序)。
3. 使用@Primary

由于byType方式自動裝配可能會比對多個候選對象,是以我們通常對于選擇需要更多的控制,我們可以使用

@Primary

實作候選優先權,當多個bean成為候選對象時,應優先考慮

@Primary

标記的bean。

//這是基于Java的容器配置方式
@Configuration
public class MovieConfiguration {

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

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

    // ...
}

//這是基于注解的容器配置方式
@Primary
@Component
public class FirstMovieCatalog implements MovieCatalog{
    // ...
}
           
當然,你也可以在XML中進行配置,見上文。
4. 使用@Qualifier

通過

@Qualifier

搭配

@Autowired

組合實作byName方式自動裝配。(不能單獨使用)

作用在字段上:

public class UserServie {
	
    @Autowired
    @Qualifier("userDao")
    private ParentDao parentDao;
}
           

作用在方法參數上:

public class UserServie {

    private ParentDao parentDao;

    @Autowired
    public void setUserDao(@Qualifier("userDao") ParentDao parentDao) {
        this.parentDao = parentDao;
    }
}
           
  • 使用

    @Qualifier

    并不意味着與byType無關,自動裝配其實還是先通過byType篩選出候選對象,再通過指定的限定符(@Qualifier值)找出指定對象的。如果要避開類型比對的過程,可以使用

    @Resource

    注解,後續會講解。
  • 如果你嘗試将來自@Bean方法的傳回結果注入到同一配置類中,建議将要注入bean的@Bean方法設定為靜态方法,将其與配置類執行個體和生命周期解耦合。原因是自動裝配會優先選擇其他配置類的候選對象,而本配置類的候選對象會放在最後選擇。

同時,你還可以通過泛型作為隐式的限定符來代替

@Qualifier

@Autowired
private Store<String> s1;

@Autowired
private Store<Integer> s2;
           

此外,你還可以自定義

@Qualifier

注解,詳見官方文檔

5. 使用@Resource

Spring也支援JSR-250中的

@Resource

注解進行自動裝配。它可以看作是byName形式的自動裝配,通過其屬性name來指定限定符。與

@Autowired

相比,它并沒有類型比對的過程,完全通過限定符進行比對。

public class UserServie {

    @Resource(name="userDao") 
    private ParentDao parentDao;

    public void setUserDao(ParentDao parentDao) {
        this.parentDao = parentDao;
    }
}
           
若你沒有寫name屬性,它預設的會按照字段名或set方法名進行比對。
6. 使用@Value

你可以通過

@Value

注解進行基本類型、String類型的注入。此外,它還支援${}和SpEL表達式。

注入字面量:

public class User{
    
    @Value("張三")
    private String name;
    
    @Value("aa,bb,cc,dd")
    private String[] alias;
    
    //...
    
}
           
Spring提供的内置轉換器支援簡單類型和String類型的類型轉換,多個逗号分隔可以自動轉換為數組。

注入屬性檔案的屬性值:

public class User{
    
    @Value("${userconfig.name}")
    private String name;
    
    //...
    
}
           

注入SpEL表達式:

public class User{
    
    @Value("#{10+2}")
    private int age;
    
    //...
    
}
           
7. 使用@PostConstruct和@PreDestroy

你可以通過JSR-250生命周期的

@PostConstruct

@PreDestroy

來實作建立和銷毀時的回調方法。

@Resource、@PostConstruct和@PreDestroy注解都是由

CommonAnnotationBeanPostProcessor

Bean識别的,而這個Bean一般通過隐式的注冊,也就是

<context:annotation-config/>

完成的。

需要注意的是,在JDK9中,整個javax.annotation注解包從Java源碼子產品分離出來,而在JDK11中完全移除,需要Maven進行依賴加入才能使用(wdnmd),同時JSR-330也是需要依賴加入才能使用的。