1. 程式人生 > >全註解下的Spring IoC

全註解下的Spring IoC

文章目錄

1. 引言

Spring最成功的是其提出的理念,而不是技術本身,他所依賴的兩個核心理念,一個是控制反轉(Inversion of Control,IoC),另一個是面向切面程式設計(Aspect Oriented Programming,AOP)。IoC容器是Spring的核心,可以說Spring是一個基於IoC容器程式設計的框架。
Spring Boot並不建議使用XML,而是通過註解的描述生成物件。Spring不僅要生成各種物件,同時還提供了依賴注入功能,使得我們可以通過描述來管理各個物件之間的關係。在Spring中把每一個需要管理的物件稱為Spring Bean(簡稱Bean),而Spring是管理這些Bean的容器,被我們稱為Spring IoC容器(簡稱IoC容器),IoC容器需要具備兩個基本功能:

  • 通過描述管理Bean,包括髮布和獲取Bean
  • 通過描述完成Bean之間的依賴關係
public interface BeanFactory {

	
	String FACTORY_BEAN_PREFIX = "&";

        //多個getBean的方法
	Object getBean(String name) throws BeansException;

	<T> T getBean(String name, Class<T> requiredType) throws BeansException;

	Object getBean(String name, Object... args) throws BeansException;

	<T> T getBean(Class<T> requiredType) throws BeansException;
	
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
	
	<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
    
        //是否包含Bean
	boolean containsBean(String name);

        //是否單例模式
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	//是否原型模式
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	//是否型別匹配
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
	
	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

        //獲取Bean的型別
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	//獲取Bean的別名
	String[] getAliases(String name);

}

值得注意的是多個getBean()方法,這也是IoC容器最重要的方法之一,他的意義是從IoC容器中獲取Bean,他可以按型別或者名稱獲取Bean。
預設情況下Spring IoC容器的Bean都是以單例存在的,也就是用getBean()方法返回的都是同一個物件,與isSingleton()方法相反的是isPrototype()方法,用來判斷是否為原型模式,如果返回的是true,那麼使用getBean()方法返回Bean的時候,Spring IoC容器就會建立一個新的Bean返回給一個呼叫者。
為了進一步完善IoC容器的功能,在BeanFactory的基礎上,還設計了一個更為高階的子介面ApplicationContext。

2. 裝配Bean

2.1 通過@Configuration方式

@Configuration代表這是一個Java配置檔案,Spring容器會根據他來生成IoC容器去裝配Bean
@Bean(String name)會將被其註解的方法返回的例項裝配到IoC容器中,name屬性定義這個Bean的名稱,預設與標準方法名相同。

2.2 通過@Component方式

Spring允許通過掃描裝配Bean到IoC容器中,對於掃描裝配而言使用的註解是@Component和@ComponentScan。@Component標明哪個類被掃描進入Spring IoC容器,而@ComponentScan則是標明採用何種策略去掃描裝配Bean。
@Component(String value)設定Bean的名稱,預設為類名首字母小寫。
@ComponentScan預設掃描當前註解類所在的包和子包,可以通過basePackages,basePackageClasses等修改掃描位置。

3. 依賴注入(Dependency Injection)

@Autowird是依賴注入中使用最多的註解之一,關於依賴注入這種設計模式的詳細解釋請至傳送門,他注入的機制最基本的一條是根據型別查詢Bean,即BeanFactory介面中的

<T> T getBean(Class<T> requiredType) throws BeansException;

需要注意的是@Autowired是一個預設必須找到對應Bean的註解,如果不能確定其標註屬性一定存在,可以將required=false,他首先會根據型別查詢Bean,如果對應的Bean不是唯一的,那麼他會根據屬性名稱和Bean的名稱進行匹配。

3.1 消除歧義性——@Primary和@Qualifier

@Primary告訴Spring IoC容器發現多個同樣型別的Bean時,優先使用此註解的Bean

...
@Component
@Primary
public class demo{
	...
}

@Qualifier通過配置項value字串定義需要的Bean name,與@Autowired組合使用,底層是通過BeanFactory藉口的geatBean方法

<T> T getBean(String name,Class<T> requiredType) throws BeansException;

使用方法為

@Autowired
@Qualifier("name")
public ClassName instance = null;

4. 生命週期

Spring IoC管理Bean的生命週期大致分為4個部分:
Bean定義、Bean初始化、Bean的生存期、Bean的銷燬。

4.1 Bean定義過程

Spring會通過配置比如@ComponentScan掃面帶有@Component註解的類定位資源,解析之後會將定義資訊儲存起來,然後將Bean定義釋出到IoC容器中,注意這個過程中只有Bean的定義而沒有例項生成。
Spring初始化Bean

Spring 初始化Bean
可以通過設定@ComponentScan中的lazyInit來實現延遲載入,預設情況下為false在注入前已經例項化。

4.2 Spring Bean生命週期

Spring Bean生命週期

這裡有幾個需要注意的地方:
介面BeanNameAware,BeanFactoryAware,ApplicationContextAware,InitializingBean,DisposableBean分別對應單個Bean的生命週期中的各個階段:定義,初始化和銷燬。而方法postProcessBeforeInitialization和postProcessAfterInitialization是介面BeanPostProcessor中的兩個方法,針對的是全部的Bean生效

public interface BeanPostProcessor {
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
	return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
	return bean;
    }
}

名為…Aware結尾的介面可以感知到其前面的含義的變化並注入到Bean例項中,例如BeanNameAware便可以感知到Bean的name並注入

public interface BeanNameAware extends Aware {
    void setBeanName(String name);
}

可以通過圖中的註解執行自定義的方法。