Spring-Bean的字段填充阶段处理
对CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor从源码分析了其依赖的解析、创建流程
CommonAnnotationBeanPostProcessor
专用来处理非Srping官方提供,而是javax的通用如下注解:
- @javax.annotation.Resource
- @javax.annotation.PostConstruct
- @javax.annotation.PreDestroy
- @javax.ejb.EJB
- @javax.xml.ws.WebServiceRef
其主要有两个重要过程,一是提取这些注解所在字段或方法的元数据。之后才是使用这些注解
其架构如下图所示。1被用在解析注解所在字段的元数据,2则是使用这些注解的处理器接口,3则表示它也具备Init和Destory注解解析的功能
CommonAnnotationBeanPostProcessor架构
解析Field和方法
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 调用父接口,解析@PostConstruct和@PreDestroy相关方法
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
// 解析其余的注解
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
// 构建当前bean的缓存key,用于存放这个bean的所有依赖
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 先从injectionMetadataCache缓存中拿,没有再构造,最后放入缓存
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
metadata = buildResourceMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
// 开始解析@WebServiceRef,@EJB和@Resource
// 这里面任意一个解析后都会进行Modifier.isStatic判断。可知静态字段或方法不支持自动注入,直接抛出了异常
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 遍历这个class的所有field,依次对每个field进行处理
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// @WebServiceRef注解处理
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
}
currElements.add(new WebServiceRefElement(field, field, null));
}
// @EJB注解处理
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static fields");
}
currElements.add(new EjbRefElement(field, field, null));
}
// @Resource注解处理
else if (field.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
currElements.add(new ResourceElement(field, field, null));
}
}
});
// 再遍历这个class的所有method,处理以set方法进行注入的方式
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
}
else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
}
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static methods");
}
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) {
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
}
if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new ResourceElement(method, bridgedMethod, pd));
}
}
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}
ResourceElement源码
以@Resource注解解析后的数据ResourceElement为例,可以发现beanName默认为@Resource的name字段。如果没有则为field字段(注解在field上)。或者则去掉前面的set,再将下个字母变为小写作为beanName(注解在set方法上)
private class ResourceElement extends LookupElement {
/**
* 存在@Lazy注解,且value为true,这个值就为true
*/
private final boolean lazyLookup;
public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
super(member, pd);
Resource resource = ae.getAnnotation(Resource.class);
// @Resource的name字段
String resourceName = resource.name();
Class<?> resourceType = resource.type();
this.isDefaultName = !StringUtils.hasLength(resourceName);
if (this.isDefaultName) { // name字段为空
// 先获取这个字段名
resourceName = this.member.getName();
if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) { // 注解在set方法上,则去掉前面的set,再将下个字母变为小写作为beanName
resourceName = Introspector.decapitalize(resourceName.substring(3));
}
}
else if (embeddedValueResolver != null) { // 支持占位符解析
resourceName = embeddedValueResolver.resolveStringValue(resourceName);
}
if (Object.class != resourceType) {
checkResourceType(resourceType);
}
else {
// No resource type specified... check field/method.
resourceType = getResourceType();
}
// 默认字段名
this.name = (resourceName != null ? resourceName : "");
// 默认当前字段的Class类型
this.lookupType = resourceType;
String lookupValue = resource.lookup();
this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName());
Lazy lazy = ae.getAnnotation(Lazy.class);
this.lazyLookup = (lazy != null && lazy.value());
}
/**
字段注入方法,如果需要懒加载,则会创建一个代理对象
*/
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
getResource(this, requestingBeanName));
}
}
字段注入
bean的populateBean调用了InstantiationAwareBeanPostProcessor#postProcessProperties方法,开始字段的注入
CommonAnnotationBeanPostProcessor#postProcessProperties
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 找出上一步缓存的元数据
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
// 开始注入
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
return pvs;
}
InjectionMetadata.InjectedElement#inject
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
throws Throwable {
if (this.isField) { // 字段注入
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
// 根据不同的子类getResourceToInject实现,获取对应的bean。会触发依赖bean的创建
// 依赖bean创建完毕并返回后,再将其赋予给field
field.set(target, getResourceToInject(target, requestingBeanName));
}
else { // set方法注入
if (checkPropertySkipping(pvs)) {
return;
}
try {
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
method.invoke(target, getResourceToInject(target, requestingBeanName));
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
总结
CommonAnnotationBeanPostProcessor
是标准注解(@Resource/@PostConstruct/@PreDestroy
)的解析者,通过元数据提前解析+生命周期钩子回调,实现了依赖注入和生命周期管理。
- CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinition:负责扫描
@Resource
、@PostConstruct
、@PreDestroy
注解,把解析结果封装成InjectionMetadata
(字段、方法对应的ResourceElement
等),再缓存下来,等待后续注入或生命周期回调使用 - CommonAnnotationBeanPostProcessor#postProcessProperties:负责根据解析好的
InjectionMetadata
真正进行注入 - InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization: 在 Bean 初始化前,调用所有
@PostConstruct
标注的方法- InitDestroyAnnotationBeanPostProcessor#postProcessBeforeDestruction:在 Bean 销毁前,调用所有
@PreDestroy
标注的方法。
- InitDestroyAnnotationBeanPostProcessor#postProcessBeforeDestruction:在 Bean 销毁前,调用所有
AutowiredAnnotationBeanPostProcessor
根据构造方法可知,它专用来处理Spring提供的这些注解
public AutowiredAnnotationBeanPostProcessor() {
// @Autowired支持
this.autowiredAnnotationTypes.add(Autowired.class);
// @Value支持
this.autowiredAnnotationTypes.add(Value.class);
try {
// javax提供的@Value支持
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Value", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
- @org.springframework.beans.factory.annotation.Autowired
- @org.springframework.beans.factory.annotation.Value
- @javax.inject.Inject
整体流程和上面的CommonAnnotationBeanPostProcessor差不多。都是在postProcessMergedBeanDefinition方法里进行bean内部有上诉3个注解的字段或方法进行解析并缓存。然后在postProcessProperties进行依赖注入