@Autowired注解源码解析

我们先来写一个简单的demo方便debug调试。

public class QualifierDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext();
        applicationContext.register(QualifierDemo.class);
        applicationContext.refresh();

        applicationContext.close();
    }

    @Autowired
    private User user;


    @Bean
    public User user(){
        return createUser("user1");
    }

    private static User createUser(String name){
        User user=new User();
        user.setName(name);
        return user;
    }
}

首先我们来关注这个方法AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition,这个类实现了BeanPostProcessor的子接口,所以bean在实例化的时候会执行到这个方法。

    @Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,Class<?> beanType,String beanName) {
	    //获取加了@Autowired的元信息数据
		InjectionMetadata metadata = findAutowiringMetadata(beanName,beanType,null);
		//将beanDefinition里Autowired相关信息添加到checkedElements里面,后面会用到。
		metadata.checkConfigMembers(beanDefinition);
	}

我们可以看到上面这个方法到入参里有个beanDefinition,这个beanDefinition正是QualifierDemo的实例,然后通过findAutowiringMetadata方法会去找关于Autowired的元信息。
这个方法执行完后,会执行AutowiredAnnotationBeanPostProcessor#postProcessProperties方法。

@Override
	public PropertyValues postProcessProperties(PropertyValues pvs,Object bean,String beanName) {
	    //获取一些元信息
		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;
	}

这里面关键的方法就是inject方法,他的代码如下:

public void inject(Object target,@Nullable String beanName,@Nullable PropertyValues pvs) throws Throwable {
        //取之前存入的checkedElements
		Collection<InjectedElement> checkedElements = this.checkedElements;
		//没有的话就取injectedElements,也是之前存入的
		Collection<InjectedElement> elementsToIterate =
				(checkedElements != null ? checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
		    //遍历@Autowired注解标记了的元信息数据集合,我们的示例中只有一个@Autowired  User
			for (InjectedElement element : elementsToIterate) {
				if (logger.isTraceEnabled()) {
					logger.trace("Processing injected element of bean '" + beanName + "': " + element);
				}
				//element正是我们示例代码里的User的一些描述
				element.inject(target,pvs);
			}
		}
	}

element的结构图如下:


可以看出,这个类型就是我们的User。接着往下看element#inject方法。

        @Override
		protected void inject(Object bean,@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 {
				    //根据元信息描述去进行bean查找
					value = beanFactory.resolveDependency(desc,autowiredBeanNames,typeConverter);
				}
				catch (BeansException ex) {
					throw new UnsatisfiedDependencyException(null,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;
					}
				}
			}
			//将查找到的bean通过反射set到对象中及示例中的 @Autowired private User user;
			if (value != null) {
			    //反射操作给private属性需要的操作。
				ReflectionUtils.makeAccessible(field);
				field.set(bean,value);
			}
		}
	}

通过反射将查找到到bean注入到@Autowired注解到变量上。

另外,源码中分析要经过的两个方法postProcessMergedBeanDefinition和postProcessProperties,他们是因为实现了spring的接口,所以会被调用到。下面我们写个例子证实它。

@Configuration
public class BeanPostConfig implements MergedBeanDefinitionPostProcessor,InstantiationAwareBeanPostProcessor {
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,String beanName) {
        System.out.println("postProcessMergedBeanDefinition:"+beanName);
    }


    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs,String beanName) {
        System.out.println("postProcessProperties:"+beanName);
        return pvs;
    }
}

打印结果如下:

postProcessMergedBeanDefinition:qualifierDemo
postProcessMergedBeanDefinition:user
postProcessProperties:user
postProcessProperties:qualifierDemo

事实证明实现了接口后,两个方法都被执行了,并且会将postProcessMergedBeanDefinition方法执行完之后才开始调用postProcessProperties方法。

原文地址:https://www.cnblogs.com/javammc

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要介绍了spring的事务传播属性REQUIRED_NESTED的原理介绍,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。传统事务中回滚点的使...
今天小编给大家分享的是一文解析spring中事务的传播机制,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获...
这篇文章主要介绍了SpringCloudAlibaba和SpringCloud有什么区别,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。Spring Cloud Netfli...
本篇文章和大家了解一下SpringCloud整合XXL-Job的几个步骤。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。第一步:整合pom文件,在S...
本篇文章和大家了解一下Spring延迟初始化会遇到什么问题。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。List 坑列表 = new ArrayList(2);...
这篇文章主要介绍了怎么使用Spring提供的不同缓存注解实现缓存的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇...
本篇内容主要讲解“Spring中的@Autowired和@Resource注解怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学...
今天小编给大家分享一下SpringSecurity怎么定义多个过滤器链的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家
这篇文章主要介绍“Spring的@Conditional注解怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Spring的@Con...
这篇文章主要介绍了SpringCloudGateway的熔断限流怎么配置的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringCloud&nb...
今天小编给大家分享一下怎么使用Spring解决循环依赖问题的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考
这篇文章主要介绍“Spring事务及传播机制的原理及应用方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Sp...
这篇“SpringCloudAlibaba框架实例应用分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价
本篇内容主要讲解“SpringBoot中怎么使用SpringMVC”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习...
这篇文章主要介绍“SpringMVC适配器模式作用范围是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“SpringMVC
这篇“导入SpringCloud依赖失败如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家...
这篇文章主要讲解了“SpringMVC核心DispatcherServlet处理流程是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来
今天小编给大家分享一下SpringMVCHttpMessageConverter消息转换器怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以...
这篇文章主要介绍“Spring框架实现依赖注入的原理是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Spring框架...
本篇内容介绍了“Spring单元测试控制Bean注入的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下