隨着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
