1. 程式人生 > >spring beans原始碼解讀之--Bean的註解(annotation)

spring beans原始碼解讀之--Bean的註解(annotation)

隨著spring註解的引入,越來越多的開發者開始使用註解,這篇文章將對註解的機制進行串聯式的講解,不求深入透徹,但求串起spring beans註解的珍珠,展示給大家。

1. spring beans常用的註解:

  public @interface Autowired:可以對成員變數、方法和建構函式進行標註,來完成自動裝配的工作。

Marks a constructor, field, setter method or config method as to be autowired by Spring's dependency injection facilities.
Only one constructor (at max) of any given bean class may carry this annotation, indicating the constructor to autowire when used as a Spring bean. Such a constructor does not have to be public.

Fields are injected right after construction of a bean, before any config methods are invoked. Such a config field does not have to be public.

Config methods may have an arbitrary name and any number of arguments; each of those arguments will be autowired with a matching bean in the Spring container. Bean property setter methods are effectively just a special case of such a general config method. Such config methods do not have to be public.

In the case of multiple argument methods, the 'required' parameter is applicable for all arguments.

In case of a Collection or Map dependency type, the container will autowire all beans matching the declared value type. In case of a Map, the keys must be declared as type String and will be resolved to the corresponding bean names.

Note that actual injection is performed through a BeanPostProcessor which in turn means that you cannot use @Autowired to inject references into BeanPostProcessor or BeanFactoryPostProcessor types. Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor class (which, by default, checks for the presence of this annotation).

Since:
2.5

  public @interface Configurable @Configurable 註解中的autowire屬性就可以讓Spring來自動裝配了: @Configurable(autowire=Autowire.BY_TYPE) 或者 @Configurable(autowire=Autowire.BY_NAME,這樣就可以按型別或者按名字自動裝配了。

Marks a class as being eligible for Spring-driven configuration.
Typically used with the AspectJ AnnotationBeanConfigurerAspect.

Since:
2.0
public @interface Value:用於注入SpEL表示式,可以放置在欄位方法或引數上。
Annotation at the field or method/constructor parameter level that indicates a default value expression for the affected argument.
Typically used for expression-driven dependency injection. Also supported for dynamic resolution of handler method parameters, e.g. in Spring MVC.

A common use case is to assign default field values using "#{systemProperties.myProp}" style expressions.

Note that actual processing of the @Value annotation is performed by a BeanPostProcessor which in turn means that you cannot use @Value within BeanPostProcessor or BeanFactoryPostProcessor types. Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor class (which, by default, checks for the presence of this annotation).

Since:
3.0
public @interface Qualifier:指定限定描述符,對應於基於XML配置中的<qualifier>標籤,@Qualifier限定描述符除了能根據名字進行注入,但能進行更細粒度的控制如何選擇候選者
@Qualifier(value = "限定識別符號") 。
This annotation may be used on a field or parameter as a qualifier for candidate beans when autowiring. It may also be used to annotate other custom annotations that can then in turn be used as qualifiers.
Since:
2.5
public @interface Required 依賴檢查;
Marks a method (typically a JavaBean setter method) as being 'required': that is, the setter method must be configured to be dependency-injected with a value.
Please do consult the javadoc for the RequiredAnnotationBeanPostProcessor class (which, by default, checks for the presence of this annotation).

Since:
2.0

2. 註解bean的定義AnnotatedBeanDefinition

public interface AnnotatedBeanDefinition extends BeanDefinition {

    /**
     * Obtain the annotation metadata (as well as basic class metadata)
     * for this bean definition's bean class.
     * @return the annotation metadata object (never {@code null})
     */
    AnnotationMetadata getMetadata();

}

   該介面繼承了BeanDefinition,提供了一個getMetadata()方法來獲取該bean definition的註解元資料。

其中,AnnotationMetadata定義了訪問特定類的註解的抽象介面,它不需要載入該類即可訪問。

public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
}
ClassMetadata定義了一個特定類的抽象元資料,不需要載入此類。主要方法如下:
String getClassName()返回該類的名稱。boolean isInterface()返回該類是否是介面。boolean isAbstract()返回該類是否為抽象類。boolean isConcrete()返回該類是否為具體類。boolean isFinal()返回該類是否為final類boolean hasSuperClass()返回該類是否有父類
String getSuperClassName()返回父類的名稱,沒有的話返回null.
String[] getInterfaceNames()返回繼承的介面陣列,如果沒有,返回空.
String[] getMemberClassNames()返回引用的類的名稱。

AnnotatedTypeMetadata定義訪問特定型別的註解,不需要載入類。主要方法有:

boolean isAnnotated(String annotationType)是否有匹配的註解型別
Map<String,Object> getAnnotationAttributes(String annotationType,boolean classValuesAsString)獲取特定型別註解的屬性

AnnotationMetadata的標準實現類StandardAnnotationMetadata,它使用標準的反射來獲取制定類的內部註解資訊。主要方法有:

getAllAnnotationAttributes(String annotationType) 
getAnnotatedMethods(String annotationType) 
hasMetaAnnotation(String annotationType) 
isAnnotated(String annotationType) 
hasAnnotatedMethods(String annotationType) 

AnnotationMetadata還有一個子類:AnnotationMetadataReadingVisitor,它是位元組碼訪問實現。

class ClassMetadataReadingVisitor extends ClassVisitor implements ClassMetadata {
}

讓我們瞭解一下visitor模式:

定義:

The Gang of Four defines the Visitor as: "Represent an operation to be performed on elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates."—″≤

The nature of the Visitor makes it an ideal pattern to plug into public APIs thus allowing its clients to perform operations on a class using a “visiting” class without having to modify the source.

uml 結構圖如下:

 小結:vistor設定模式把狀態抽象出來成為一個介面(訪問者),不同的狀態就作為狀態的不同實現類(不同的訪問者)。

 3. 註解bean的實現類

    3.1 AnnotatedGenericBeanDefinition

          繼承了GenericBeanDefinition,增加了對註解元素的支援,這種支援是通過AnnotationBeanDefinition暴露的的註解元素介面。

    GenericBeanDefinition主要用來測試AnnotatedBeanDefinition上的操作的,例如:在spring的component掃描支援的實現中(預設實現類是ScannedGenericBeanDefinition,它同樣實現了AnnotatedBeanDefinition介面)

  3.2 ConfigurationClassBeanDefinition

    ConfigurationClassBeanDefinition是ConfigurationClassBeanDefinitionReader的內部類,ConfigurationClassBeanDefinitionReader讀取一組完全填充了屬性的配置例項,通過context內給定的BeanDefinitionRegistry進行註冊bean definition。這個類在BeanDefinitionReader這層後就改造,但沒有繼承或者擴充套件配置類。

   3.3 ScannedGenericBeanDefinition

   基於asm的類解析器,是GenericBeanDefinition類的擴充套件,支援註解元資料,這種支援通過AnnotatedBeanDefinition介面實現。

4. 註解的解析與處理

4.1 @Autowired註解實現AutowiredAnnotationBeanPostProcessor

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
        implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
}
AutowiredAnnotationBeanPostProcessor 間接繼承了BeanPostProcessor,它自動繫結註解的field,setter方法和任意的配置方法。當檢測到5個java註解時這些成員被注入其中。spring預設的註解為@Autowired和@Value。
另外:也支援JSR-330的@inject註解,作為@Autowired的替代方案。

當制定bean 類的唯一構造方法帶有required 註解引數,且required值設定為true時,表明當作為spring一個bean時,構造方法預設自動繫結。若多個構造方法帶有non-required 註解引數,它們將作為自動繫結的候選項。帶有大量依賴的構造方法可以通過spring容器中的匹配的bean來構造,如果沒有候選者滿足條件,則會使用預設的構造器。註解構造器不一定是public的。
Field注入是在構造方法之後,配置方法之前,這種配置field不要求一定為public
配置方法可以有任意的名稱和不定的引數列表,這些引數則被自動注入到spring容器中的匹配的bean。bean的屬性setter方法僅僅是通用的配置方法的一個特例而已。配置方法不要求方法一定為public
注意:預設註冊AutowiredAnnotationBeanPostProcessor的方式有<context:annotation-config> 和<context:component-scan> xml標籤,如果你指定了一個自定義的AutowiredAnnotationBeanPostProcessor bean definition,移除或者關閉預設的註解配置。

其中,MergedBeanDefinitionPostProcessor的定義如下:
public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {

    /**
     * Post-process the given merged bean definition for the specified bean.
     * @param beanDefinition the merged bean definition for the bean
     * @param beanType the actual type of the managed bean instance
     * @param beanName the name of the bean
     */
    void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);

}
BeanPostProcessor 是一個可以定製修改一個新的bean例項的工廠鉤子,例如:檢查marker介面或者使用代理包裝他們。
applicationContext可以在他們的bean容器中自動識別BeanPostProcessor bean,並將它們應用到接下來所建立的bean。一般的bean factory通過程式設計來註冊Post-processor,並將它們應用到整個bean factory建立bean的過程中。

通常意義上,post-processor 設定bean屬性通過marker 介面或者類似於實現postProcessBeforeInitialization(java.lang.Object, java.lang.String);使用代理包裝bean通常實現postProcessAfterInitialization(java.lang.Object, java.lang.String).

4.2 @configurable註解實現AnnotationBeanWiringInfoResolver 

設定 @Configurable 註解中的autowire屬性就可以讓Spring來自動裝配了: @Configurable(autowire=Autowire.BY_TYPE) 或者 @Configurable(autowire=Autowire.BY_NAME,這樣就可以按型別或者按名字自動裝配了。

    AnnotationBeanWiringInfoResolver 繼承自BeanWiringInfoResolver,BeanWiringInfoResolver使用configurable註解來查詢哪些類需要自動繫結。

public class AnnotationBeanWiringInfoResolver implements BeanWiringInfoResolver {
}

實現了BeanWiringInfoResolver的resolveWiringInfo方法

@Override
    public BeanWiringInfo resolveWiringInfo(Object beanInstance) {
        Assert.notNull(beanInstance, "Bean instance must not be null");
        Configurable annotation = beanInstance.getClass().getAnnotation(Configurable.class);
        return (annotation != null ? buildWiringInfo(beanInstance, annotation) : null);
    }

    /**
     * Build the BeanWiringInfo for the given Configurable annotation.
     * @param beanInstance the bean instance
     * @param annotation the Configurable annotation found on the bean class
     * @return the resolved BeanWiringInfo
     */
    protected BeanWiringInfo buildWiringInfo(Object beanInstance, Configurable annotation) {
        if (!Autowire.NO.equals(annotation.autowire())) {
            return new BeanWiringInfo(annotation.autowire().value(), annotation.dependencyCheck());
        }
        else {
            if (!"".equals(annotation.value())) {
                // explicitly specified bean name
                return new BeanWiringInfo(annotation.value(), false);
            }
            else {
                // default bean name
                return new BeanWiringInfo(getDefaultBeanName(beanInstance), true);
            }
        }
    }

 4.3 @qualifier的註解實現類QualifierAnnotationAutowireCandidateResolver

public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwareAutowireCandidateResolver {
}

public class GenericTypeAwareAutowireCandidateResolver implements AutowireCandidateResolver, BeanFactoryAware {
}

其中,AutowireCandidateResolver是一個策略介面,由它來決定特定的bean definition對特定的依賴是否可以作為一個自動繫結的候選項,它的主要方法有:

boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor)

Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor,String beanName)

Object getSuggestedValue(DependencyDescriptor descriptor)

 QualifierAnnotationAutowireCandidateResolver間接實現了AutowireCandidateResolver,對要自動繫結的field或者引數和bean definition根據@qualifier註解進行匹配。同時也支援通過@value註解來繫結表示式的值。

另外,還只是JSR-330的javax.inject.Qualifier註解。

4.4 @required註解實現類RequiredAnnotationBeanPostProcessor。

public class RequiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
        implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
}

和AutowiredAnnotationBeanPostProcessor一樣,間接繼承自BeanPostProcessor,它增加了對javaBean屬性配置的約束,java 5 註解可以檢測bean的required屬性,spring預設是@Required註解。

注意:預設註冊AutowiredAnnotationBeanPostProcessor的方式有<context:annotation-config> 和<context:component-scan> xml標籤,如果你指定了一個自定義的
預設註冊AutowiredAnnotationBeanPostProcessor的方式有<context:annotation-config> 和<context:component-scan> xml標籤,如果你指定了一個自定義的AutowiredAnnotationBeanPostProcessor bean definition,移除或者關閉預設的註解配置。其餘和AutowiredAnnotationBeanPostProcessor類似,不一一贅述了。

4.5 初始化和銷燬方法的註解實現類InitDestroyAnnotationBeanPostProcessor

public class InitDestroyAnnotationBeanPostProcessor
        implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {
}

InitDestroyAnnotationBeanPostProcessor間接繼承了BeanPostProcess,實現了通過註解來初始化和銷燬方法,是spring的InitializingBean和DisposableBean回撥介面的註解實現。

它通過"initAnnotationType"和"destroyAnnotationType"屬性來檢查指定的註解型別,任何自定義的註解都可以使用。

初始化和銷燬註解可以用在任意可見的方法:public,package-protected,protected,private等。儘管可以對多個方法進行註解,但我們推薦只在一個初始化和銷燬方法上各自進行註解。

小結:

 Spring3的基於註解實現Bean依賴注入支援如下三種註解:
Spring自帶依賴注入註解: Spring自帶的一套依賴注入註解;
JSR-250註解:Java平臺的公共註解,是Java EE 5規範之一,在JDK6中預設包含這些註解,從Spring2.5開始支援。
JSR-330註解:Java 依賴注入標準,Java EE 6規範之一,可能在加入到未來JDK版本,從Spring3開始支援;

其中,
Spring自帶依賴注入註解

1 @Required:依賴檢查;
2 @Autowired:自動裝配2 
自動裝配,用於替代基於XML配置的自動裝配
基於@Autowired的自動裝配,預設是根據型別注入,可以用於構造器、欄位、方法注入
3 @Value:注入SpEL表示式
用於注入SpEL表示式,可以放置在欄位方法或引數上
@Value(value = "SpEL表示式")  
@Value(value = "#{message}")  
4 @Qualifier:限定描述符,用於細粒度選擇候選者
@Qualifier限定描述符除了能根據名字進行注入,但能進行更細粒度的控制如何選擇候選者
@Qualifier(value = "限定識別符號") 


JSR-250註解

1 @Resource:自動裝配,預設根據型別裝配,如果指定name屬性將根據名字裝配,可以使用如下方式來指定
@Resource(name = "識別符號")  
欄位或setter方法 

2 @PostConstruct和PreDestroy:通過註解指定初始化和銷燬方法定義

JSR-330註解
1 @Inject:等價於預設的@Autowired,只是沒有required屬性
2 @Named:指定Bean名字,對應於Spring自帶@Qualifier中的預設的根據Bean名字注入情況
3 @Qualifier:只對應於Spring自帶@Qualifier中的擴充套件@Qualifier限定描述符註解,即只能擴充套件使用,沒有value屬性

參考文獻:
1. http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/annotation/
2. http://blog.csdn.net/wangshfa/article/details/9712379




相關推薦

spring beans原始碼解讀--Bean註解(annotation)

隨著spring註解的引入,越來越多的開發者開始使用註解,這篇文章將對註解的機制進行串聯式的講解,不求深入透徹,但求串起spring beans註解的珍珠,展示給大家。 1. spring beans常用的註解:   public @interface Autowired:可以對成員變數、方法和建構函式進

spring beans原始碼解讀--bean definiton解析器

spring提供了有兩種方式的bean definition解析器:PropertiesBeanDefinitionReader和XmLBeanDefinitionReader即屬性檔案格式的bean definition解析器和xml檔案格式的bean definition解析器。 我們先從簡單的Prop

spring beans原始碼解讀--Bean的定義及包裝

  bean的定義,包裝是java bean的基礎。再怎麼強調它的重要性都不為過,因此深入 瞭解這塊的程式碼對以後的程式碼研究可以起到事半功倍的功效。 1. Bean的定義BeanDefinition 1.1 BeanDefinition 作用 一個BeanDefinition描述了一個bean的例項,

spring beans原始碼解讀 ioc容器始祖--DefaultListableBeanFactory

spring Ioc容器的實現,從根源上是beanfactory,但真正可以作為一個可以獨立使用的ioc容器還是DefaultListableBeanFactory,因此可以這麼說, DefaultListableBeanFactory 是整個spring ioc的始祖,研究透它

spring beans原始碼解讀--總結篇

spring beans下面有如下原始檔包: org.springframework.beans, 包含了操作java bean的介面和類。org.springframework.beans.annotation, 支援包,提供對java 5註解處理bean樣式的支援。org.springframework

spring beans原始碼解讀--XmlBeanFactory

導讀: XmlBeanFactory繼承自DefaultListableBeanFactory,擴充套件了從xml文件中讀取bean definition的能力。從本質上講,XmlBeanFactory等同於DefaultListableBeanFactory+XmlBeanDefinitionReader

Spring原始碼解讀——bean的生命週期(隨筆)

bean建立---初始化----銷燬的過程 容器管理bean的生命週期; 我們可以自定義初始化和銷燬方法;容器在bean進行到當前生命週期的時候來呼叫我們自定義的初始化和銷燬方法 構造(物件建立)     單例項:在容器啟動的時候建立物件     多例項:在每次獲取的時

Spring Ioc 原始碼分析Bean的載入和構造

我們都知道,Spring Ioc和Aop是Spring的核心的功能,因此花一點時間去研究還是很有意義的,如果僅僅是知其所以然,也就體會不到大師設計Spring的精華,還記得那句話,Spring為JavaEE開發帶來了春天。IOC就是Inversion of control 也就是控制反轉的意思,另一種稱呼叫做

Spring Cloud 原始碼解讀 【這也太神奇了,RestTemplate加上一個@LoadBalanced註解就能實現負載均衡!】

前提概要: 前天,有個前端大佬問了我兩個問題:為啥不引入Ribbon依賴就能使用Ribbon?為啥RestTemplate加上@LoadBalanced註解就能負載均衡了?我也表示很疑惑,而我自己其實也真的沒去了解過,所以趁著工作不太忙,趕緊去研究一波。 第一個問題比較簡單,一般都是其他依賴引入了Ribbon

Spring原始碼解讀核心容器上節

Spring架構圖 說明 Spring的流行程度就不用我來說了,相信大家如果使用JAVA開發就一定知道它。寫這篇文章的初衷在於:1.瞭解Spring底層實現原理,提升對Spring的認識與理解。2.學習優秀框架程式設計實現,學習優秀的設計模式。3.使用Spring三年多,對於底層細節希望知道更多,便於

深入理解spring註解@Bean註解

本文主要從以下幾個方面來學習一下spring的註解@Bean: 基於xml方式bean使用回顧 註解@Bean詳細使用說明 註解@Bean的原始碼解析 1,基於xml方式bean使用回顧 新建一個maven專案增加spring-con

Spring原始碼解讀核心容器下節

續 上一篇我們通過ClassPathXmlApplicationContext載入xml檔案,通過BeanFactory獲取例項bean的demo程式碼去解讀了Spring Core Container中的spring-beans,spring-core,spring-context三個元件之間的一些具體類

Spring原始碼解讀Spring MVC HandlerMapping元件(二)

一、HandlerMapping HandlerMapping作用是根據request找到相應的處理器Handler和Interceptors,並將Handler和Interceptors封裝成HandlerExecutionChain 物件返回。Handler

Spring原始碼解讀——元件註冊(隨筆)

@ComponentScan  value:指定要掃描的包 excludeFilters = Filter[] :指定掃描的時候按照什麼規則排除那些元件 includeFilters = Filt

spring原始碼解讀 JdbcTemplate原始碼

    在Spring中,JdbcTemplate是經常被使用的類來幫助使用者程式操作資料庫,在JdbcTemplate為使用者程式提供了許多便利的資料庫操作方法,比如查詢,更新等,而且在Spring中,有許多類似 JdbcTemplate的模板,比如HibernateT

Spring原始碼解讀——自動裝配(隨筆)

Spring利用依賴注入(DI),完成對IOC容器中中各個元件的依賴關係賦值; 1、@Autowired:自動注入:     1)、預設優先按照型別去容器中找對應的元件:applicationContext.getBean(BookDao.class);找到就賦值   

Spring原始碼窺探註解方式的AOP原理

AOP入口程式碼分析 通過註解的方式來實現AOP1. @EnableAspectJAutoProxy通過@Import註解向容器中注入了AspectJAutoProxyRegistrar這個類,而它在容器中的名字是org.springframework.aop.config.internalAutoP

Spring原始碼閱讀Bean載入(xml)1

先上兩張圖,簡單的畫了一下beanFactory各個類之間的關係,XmlBeanFactory是bean載入的入口和核心。Spring中大量使用了設計模式和UML中的設計原則,比如單一職責原則,從類圖可以看出,BeanFactory派生的各個介面,根據名字的不同,都增加了

Spring原始碼解析bean的建立

閱讀須知 Spring原始碼版本:4.3.8 文章中使用/* */註釋的方法會做深入分析 正文 之前我們都是在圍繞 ApplicationContext applicationContext = new ClassPathXmlApplicati

Spring原始碼解讀BeanFactoryPostProcessor的處理

前言     前段時間旁聽了某課堂兩節Spring原始碼解析課,剛好最近自己又在重新學習中,便在這裡記錄一下學習所得。我之前寫過一篇博文,是介紹BeanFactoryPostProcessor跟BeanPostProcessor是如何發揮作用的,當時覺得講的還行,但是現在看來,太粗劣了,