spring中BeanPostProcessor之四:AutowiredAnnotationBeanPostProcessor(01)
在《spring中BeanPostProcessor之二:CommonAnnotationBeanPostProcessor(01)》中分析了CommonAnnotationBeanPostProcessor类中的postProcessMergedBeanDefinition方法的作用,即是对类中的@Resources、@WebServiceRef、@EJB三个注解进行解析并缓存起来,以便后续执行postProcessProperties方法的时候用到缓存的信息。在spring启动过程中还有一个和CommonAnnotationBeanPostProcessor类相似的bean后置处理器,该类就是AutowiredAnnotationBeanPostProcessor,该bean后置处理器的作用是处理@Autowired、@Value、@Inject注解。
一、概述
前面说到AutowiredAnnotationBeanPostProcessor类是解析@Autowired注解的,那么该注解的作用是什么那,是怎么定义的那
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired { /**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() default true; }
上面是该注解的定义,该注解的作用是自动注入,该注解是Spring提供的注解(@Resource、@WebServiceRef、@EJB均是java提供的)。
AutowriedAnnotationBeanPostProcessor要解析@Autowired注解那么按照前面分析的CommonAnnotationBeanPostProcessor和InitDestroyBeanPostProcessor两个类,必须要先有要解析的类型,也就是初始化解析的类型,看AutoworedAnnotationBeanPostProcessor的构造方法,
@SuppressWarnings("unchecked")
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", 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.
}
}
上面是其默认的构造方法,可以看到向autowiredAnnotationTypes中加了三个注解:@Autowired、@Value、@Inject,其中@Inject是java中的注解,其余两个均是Spring提供的注解。那么这里其实是说明AutowiredAnnotationBeanPostProcessor类是解析这三个注解的,我们继续往下分析。
二、详述
1、方法概述
下面看AutoWiredAnnotationBeanPostProcessor类中的方法,
上面给出了AutoWiredAnnotationBeanPostProcessor类中的主要的方法,重点看postProcessMergedBeanDefinition和postProcessProperties方法,postProcessPropertyValue方法在前边已经说过该方法已经废弃了,调用的是postProcessProperties方法。
2、postProcessMergedBeanDefinition
该方法的作用是解析类中标记了@AutoWired、@Value、@Inject注解的属性和方法,下面看具体的方法定义,
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
2.1、findAutowiringMetadata
下面看findAutowiringMetadata方法
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
//从缓存中获得该类的信息
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);
}
//查找目标类clazz中的标识了@AutoWired、@Value、@Inejct注解
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
从上面的代码中可以看出最终是把标识了@AutoWired、@Value、@Inject注解的方法或字段信息封装为Metadata然后放在了injectionMetadataCache中,重点看buildAutowiringMetadata方法,
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
/**autowiredAnnotationTypes中得值为
* @AutoWired org.springframework.beans.factory.annotation.Autowired
* @Value org.springframework.beans.factory.annotation.Value
* @Inject javax.inject.Inject
*
*/ if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
} List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz; do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>(); //判断字段上是否存在autowiredAnnotationTypes中的注解
ReflectionUtils.doWithLocalFields(targetClass, field -> {
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
}); //判断方法上是否存在autowiredAnnotationTypes中的注解
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
}); elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class); return InjectionMetadata.forElements(elements, clazz);
}
该代码比较多,主要是对目标类中的方法和字段信息进行了检查,判断是否标注了@AutoWired、@Value、@Inject三个注解,最后返回InjectionMetadata.forElements该方法是做什么的那,由于前边生成的对象是elements的对象,看elements对象的类型,
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
是一个ArrayList类型,泛型是InjectionMetadata.InejctedElement,下面看该方法,
public static InjectionMetadata forElements(Collection<InjectedElement> elements, Class<?> clazz) {
return (elements.isEmpty() ? InjectionMetadata.EMPTY : new InjectionMetadata(clazz, elements));
}
从上面的代码可以看到,最终是new了一个InjectionMetadata的实例。最终buildAutowiringMetadata方法返回的是一个InjectionMetadata的实例。
buildAutowiringMetadata方法执行完以后,在findAutowiringMetadata方法中,把返回的InjectionMetadata实例放入了injectionMetadataCache中,最终返回一个InjectionMetadata实例。
2.2、checkConfigMembers
在postProcessMergedBeanDefinition方法中的第二行代码即调用了checkConfigMembers方法
metadata.checkConfigMembers(beanDefinition);
该方法的定义如下,
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
Set<InjectedElement> checkedElements = new LinkedHashSet<>(this.injectedElements.size());
for (InjectedElement element : this.injectedElements) {
Member member = element.getMember();
if (!beanDefinition.isExternallyManagedConfigMember(member)) {
beanDefinition.registerExternallyManagedConfigMember(member);
checkedElements.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Registered injected element on class [" + this.targetClass.getName() + "]: " + element);
}
}
}
this.checkedElements = checkedElements;
}
从上面的代码中可以看出首先new了一个checkedElements,使用的是injectedElements的长度,injectedElements是什么那,怎么赋值的那。在buildAutowiringMetadata方法的最后调用了InectionMetadata.forElements方法,在该方法中最后生成了一个InjectionMetadata对象,传入了elements对象,便是该对象。
checkConfiMembers方法主要是调用了beanDefintion.isExternallyManagedConfigMemgber方法,该方法暂时不讨论。
3、postProcessProperties
上面分析了postProcessMergedBeanDefinition方法后,我们知道该方法的作用就是收集类中的标注了@AutoWired、@Value、@Inject注解的字段或方法,那么postProcessProperties方法便是在进行赋值的时候调用的,
//完成@AutoWired属性的注入
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//再次获取了类中标注了@AutoWired、@Value、@Inject属性的信息
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
//属性注入
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
在该方法中又一次获取了类中标注了@AutoWired、@Value、@Inject属性的信息,重点是下面这行代码,
//属性注入
metadata.inject(bean, beanName, pvs);
下面看inject方法,
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
//如果checkedElements为空,则取injectedElements
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
//进行属性注入
element.inject(target, beanName, pvs);
}
}
}
上面在进行属性注入的时候调用了element.inject方法,该方法在InjectionMetadata.InjectedElement类中,进去该方法看到如下,
/**
* Either this or {@link #getResourceToInject} needs to be overridden.
*/
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
throws Throwable { if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}
else {
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();
}
}
}
看这方法的注释,意思是需要覆盖该方法,也就是说这里调用的不是上面的inject方法,在回到下面的代码
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
//如果checkedElements为空,则取injectedElements
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
//进行属性注入
element.inject(target, beanName, pvs);
}
}
}
遍历elementsToIterate,通过调试我们看到这里的element是下面的类型
再来看AutowiredFieldElement是什么,
AutowiredFieldElement是AutowiredAnnotationBeanPostProcessor中的内部类,继承了InjectionMetadata.InjectedElement类,上面提到了该方法,那么该类中肯定覆盖了inject方法
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
此方法的具体执行逻辑暂时不说。
三、使用场景
上面大体分析了AutowiredAnnotationBeanPostProcessor类中的postProcessMergedBeanDefinition和postProcessProperties两个方法,了解了其作用及执行时机,文中遗留的问题后面会继续分析。
有不当之处,欢迎指正,感谢!
spring中BeanPostProcessor之四:AutowiredAnnotationBeanPostProcessor(01)的更多相关文章
- spring中BeanPostProcessor之三:InitDestroyAnnotationBeanPostProcessor(01)
在<spring中BeanPostProcessor之二:CommonAnnotationBeanPostProcessor(01)>一文中,分析到在调用CommonAnnotationB ...
- spring中BeanPostProcessor之一:InstantiationAwareBeanPostProcessor(01)
在spring中beanPostProcessor绝对是开天辟地的产物,给了程序员很多自主权,beanPostProcessor即常说的bean后置处理器. 一.概览 先来说下Instantiatio ...
- Spring中BeanPostProcessor
Spring中BeanPostProcessor 前言: 本文旨在介绍Spring动态配置数据源的方式,即对一个DataSource的配置诸如jdbcUrl,user,password,driverC ...
- spring中BeanPostProcessor之二:CommonAnnotationBeanPostProcessor(01)
在上篇博客中分享了InstantiationAwareBeanPostProcessor接口中的四个方法,分别对其进行了详细的介绍,在文末留下了一个问题,那就是postProcessPropertie ...
- spring(三):spring中BeanPostProcessor的使用
spring中实现BeanPostProcessor的后置处理器 ApplicationContextAwareProcessor 进入该实现类内部 可以看到:该类帮我们组建IOC容器,判断我们的be ...
- spring中BeanPostProcessor之一:InstantiationAwareBeanPostProcessor(03)
前面介绍了InstantiationAwareBeanPostProcessor后置处理器的postProcessBeforeInstantiation和postProcessAfterInstant ...
- spring中BeanPostProcessor之一:InstantiationAwareBeanPostProcessor(02)
在上篇博客中写道了bean后置处理器InstantiationAwareBeanPostProcessor,只介绍了其中一个方法的作用及用法,现在来看postProcessBeforeInstanti ...
- Spring中的BeanPostProcessor
一.何谓BeanProcessor BeanPostProcessor是SpringFramework里非常重要的核心接口之一,我先贴出一段源代码: /* * Copyright 2002-2015 ...
- 通过BeanPostProcessor理解Spring中Bean的生命周期
通过BeanPostProcessor理解Spring中Bean的生命周期及AOP原理 Spring源码解析(十一)Spring扩展接口InstantiationAwareBeanPostProces ...
随机推荐
- 不同规模的企业对CRM的需求是否相同?
CRM客户管理系统在我们的认知中往往是中大型企业的选择.如今,越来越多中小规模企业开始使用CRM系统.CRM的功能随着发展变得越来越实用,可以满足不同行业不同业务规模的企业的需求.同时,CRM功能类型 ...
- 重新整理 .net core 实践篇————依赖注入应用[二]
前言 这里介绍一下.net core的依赖注入框架,其中其代码原理在我的另一个整理<<重新整理 1400篇>>中已经写了,故而专门整理应用这一块. 以下只是个人整理,如有问题, ...
- [bug] org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputException: Input length = 2
原因 SpringBoot启动加载yml配置文件出现编码格式错误 参考 https://www.pianshen.com/article/2431144034/
- property - 必应词典 美['prɑpərti]英['prɒpə(r)ti] n.属性;财产;财产权;【戏】道具
英语 (已检测) 自动检测 阿拉伯语 自动检测 爱尔兰语 自动检测 爱沙尼亚语 自动检测 保加利亚语 自动检测 冰岛语 自动检测 波兰语 自动检测 波斯尼亚语(拉丁语) 自动检测 波斯语 自动检测 丹 ...
- mysql基础之数据库备份和恢复实操
一.基于二进制文件的恢复*** 1.算好要恢复数据的时间段,重定向输入到bin.sql文件中 [root@ren7 mysql]# mysqlbinlog --start-datetime=" ...
- 第8章 Shell函数的知识与实践
shell 函数常见的语法格式 function 函数名(){ return n } 简化1 function 函数名{ ... } 简化2 函数名(){ ... } ...
- 『动善时』JMeter基础 — 31、JMeter中BeanShell断言详解
目录 1.BeanShell简介 2.Beanshell的内置变量和方法 3.BeanShell断言界面详解 4.BeanShell断言的使用 (1)测试计划内包含的元件 (2)登陆接口请求界面内容 ...
- [LeetCode] 231. 2 的幂
位运算 231. 2 的幂 ``` class Solution { public boolean isPowerOfTwo(int n) { int cnt = 0; while (n>0) ...
- Ascend Pytorch算子功能验证
Ascend Pytorch算子功能验证 编写测试用例 以add算子为例,测试脚本文件命名为:add_testcase.py.以下示例仅为一个简单的用例实现,具体算子的实现,需要根据算子定义进行完整的 ...
- MindSpore Lite整体架构介绍
MindSpore Lite整体架构介绍 MindSpore Lite框架的总体架构如下所示: 前端(Frontend): 负责模型生成,用户可以通过模型构建接口构建模型,将第三方模型和MindSpo ...