spring 注解
随着spring注解的引入,越来越多的开发者开始使用注解,这篇文章将对注解的机制进行串联式的讲解,不求深入透彻,但求串起spring beans注解的珍珠,展示给大家。
spring beans常用的注解:
- 自动装配
@Autowired
:可以对成员变量、方法和构造函数进行标注,来完成自动装配的工作。
- 配置属性
@Configurable
注解中的autowire属性就可以让Spring来自动装配了:
@Configurable(autowire=Autowire.BY_TYPE)
或者 @Configurable(autowire=Autowire.BY_NAME)
,这样就可以按类型或者按名字自动装配了。
- 属性
@Value
:用于注入SpEL表达式,可以放置在字段方法或参数上。
- 限定描述符
@Qualifier
:指定限定描述符,对应于基于XML配置中的 <qualifier>
标签,@Qualifier限定描述符除了能根据名字进行注入,但能进行更细粒度的控制如何选择候选者
@Qualifier(value = "限定标识符")
用来标识可能存在冲突的属性信息。
- 依赖检查
@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).
注解 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
其中,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
AnnotatedTypeMetadata 定义访问特定类型的注解,不需要加载类。
主要方法有:
boolean isAnnotated(String annotationType)是否有匹配的注解类型
Map<String,Object> getAnnotationAttributes(String annotationType,boolean classValuesAsString)获取特定类型注解的属性
AnnotationMetadata 的子类实现
StandardAnnotationMetadata
AnnotationMetadata的标准实现类StandardAnnotationMetadata,它使用标准的反射来获取制定类的内部注解信息。
主要方法有:
getAllAnnotationAttributes(String annotationType)
getAnnotatedMethods(String annotationType)
hasMetaAnnotation(String annotationType)
isAnnotated(String annotationType)
hasAnnotatedMethods(String annotationType)
AnnotationMetadataReadingVisitor
AnnotationMetadata 还有一个子类:AnnotationMetadataReadingVisitor,它是字节码访问实现。
class ClassMetadataReadingVisitor extends ClassVisitor implements ClassMetadata {
}
Visitor 模式
让我们了解一下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
uml 结构图如下:
vistor 设置模式把状态抽象出来成为一个接口(访问者),不同的状态就作为状态的不同实现类(不同的访问者)。
注解bean的实现类
AnnotatedGenericBeanDefinition
继承了GenericBeanDefinition,增加了对注解元素的支持,这种支持是通过AnnotationBeanDefinition暴露的的注解元素接口。
GenericBeanDefinition主要用来测试AnnotatedBeanDefinition上的操作的,
例如:在spring的component扫描支持的实现中(默认实现类是ScannedGenericBeanDefinition,它同样实现了AnnotatedBeanDefinition接口)
ConfigurationClassBeanDefinition
ConfigurationClassBeanDefinition是ConfigurationClassBeanDefinitionReader的内部类,ConfigurationClassBeanDefinitionReader读取一组完全填充了属性的配置实例,通过context内给定的BeanDefinitionRegistry进行注册bean definition。
这个类在BeanDefinitionReader这层后就改造,但没有继承或者扩展配置类。
ScannedGenericBeanDefinition
基于asm的类解析器,是GenericBeanDefinition类的扩展,支持注解元数据,这种支持通过AnnotatedBeanDefinition接口实现基于asm的类解析器,是GenericBeanDefinition类的扩展,支持注解元数据,这种支持通过AnnotatedBeanDefinition接口实现。
@Autowired 注解实现 AutowiredAnnotationBeanPostProcessor
ps: 每一个注解有一个专门的处理实现类。这就是架构优秀的地方。
接口
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
其中,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)
.
钩子函数
BeanPostProcessor 是一个非常强大的钩子函数,可以在基础的属性定义完成之后,进一步对对象进行处理。
@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);
}
}
}
@Qualifier 的注解实现类 QualifierAnnotationAutowireCandidateResolver
接口
public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwareAutowireCandidateResolver {}
public class GenericTypeAwareAutowireCandidateResolver extends SimpleAutowireCandidateResolver
implements 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注解。
@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类似,不一一赘述了。
初始化和销毁方法的注解实现类 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自带依赖注入注解
-
@Required:依赖检查;
-
@Autowired:自动装配
自动装配,用于替代基于XML配置的自动装配基于@Autowired的自动装配,默认是根据类型注入,可以用于构造器、字段、方法注入
- @Value:注入SpEL表达式
用于注入SpEL表达式,可以放置在字段方法或参数上
@Value(value = "SpEL表达式")
@Value(value = "#{message}")
- @Qualifier:限定描述符,用于细粒度选择候选者
@Qualifier限定描述符除了能根据名字进行注入,但能进行更细粒度的控制如何选择候选者
@Qualifier(value = "限定标识符")
JSR-250注解
- @Resource:自动装配
默认根据类型装配,如果指定name属性将根据名字装配,可以使用如下方式来指定字段或setter方法
@Resource(name = "标识符")
- @PostConstruct和PreDestroy:
通过注解指定初始化和销毁方法定义
JSR-330注解
@Inject:等价于默认的@Autowired,只是没有required属性
@Named:指定Bean名字,对应于Spring自带@Qualifier中的缺省的根据Bean名字注入情况
@Qualifier:只对应于Spring自带@Qualifier中的扩展@Qualifier限定描述符注解,即只能扩展使用,没有value属性
个人收获
架构的设计
spring 将注解相关作为 spring 的核心,但是 spring-beans 是反射的基石。
这种分工设计是非常棒的,设计基础本身就应该不依赖于任何注解。
JSR 标准
实现的时候,可以多参考标准。
不然还要做兼容。
参考资料
spring beans源码解读之–Bean的注解(annotation)
- spring 注解
- 注解 bean 的定义 AnnotatedBeanDefinition
- Visitor 模式
- 注解bean的实现类
- @Autowired 注解实现 AutowiredAnnotationBeanPostProcessor
- @configurable注解实现AnnotationBeanWiringInfoResolver
- @Qualifier 的注解实现类 QualifierAnnotationAutowireCandidateResolver
- @Required 注解实现类 RequiredAnnotationBeanPostProcessor
- 初始化和销毁方法的注解实现类 InitDestroyAnnotationBeanPostProcessor
- 小结:
- 个人收获
- 参考资料