Spring @Autowired 注解原理

Spring @Autowired 注解原理

1.@Autowired 使用

@ComponentScan("org.example.bean")
public class AnnoContextDemo {@Autowiredprivate User user;public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AnnoContextDemo.class);User user1 = context.getBean(AnnoContextDemo.class).user;System.out.println("user1 = " + user1);}}

被扫描的组件配置类

@Configuration
public class BeanConfig {@Beanpublic User user(){return new User(21,"张三");}}

输出结果

user1 = User{age=21, name='张三'}

2.依赖自动注入原理

定位@Autowired所在包 org.springframework.beans.factory.annotation.Autowired

找到同包下 AutowiredAnnotationBeanPostProcessor

image-20230717202302872

AutowiredAnnotationBeanPostProcessor 的类继承图如下

image-20230717202419423

AutowiredAnnotationBeanPostProcessor实现了InstantiationAwareBeanPostProcessor与

MergedBeanDefinitionPostProcessor两个BeanPostProcessor后置处理器接口

  1. MergedBeanDefinitionPostProcessor 此接口主要有两个方法 抽象方法 postProcessMergedBeanDefinition 默认方法 resetBeanDefinition

  2. InstantiationAwareBeanPostProcessor 此接口 抽象方法 postProcessBeforeInstantiation ,postProcessAfterInstantiation ,默认方法 postProcessProperties ,默认过时方法 postProcessPropertyValues

想搞清楚@Autowried注入原理,先得知道这些接口对应方法执行的先后顺序 跟踪ApplicationContext.refresh方法,调用链路如下

ApplicationContext.refresh() -> AbstractApplicationContext.finishBeanFactoryInitialization() -> ConfigurableListableBeanFactory.preInstantiateSingletons() - > AbstractBeanFactory.getBean() -> AbstractBeanFactory.doGetBean() -> AbstractBeanFactory.getSingleton() -> AbstractBeanFactory.createBean()

实例化前

-> resolveBeforeInstantiation() 执行 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()前置方法 如果返回不为null,将执行 InstantiationAwareBeanPostProcessor.postProcessAfterInitialization()后置方法。

创建bean实例阶段

-> doCreateBean() -> createBeanInstance 反射创建bean实例

-> applyMergedBeanDefinitionPostProcessors() 执行 MergedBeanDefinitionPostProcessor.MergedBeanDefinitionPostProcessor方法 合并bean定义信息

属性注入阶段

-> populateBean() -> 执行 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation 后置处理方法 -> 执行InstantiationAwareBeanPostProcessor.postProcessProperties -> InstantiationAwareBeanPostProcessor.postProcessPropertyValues -> applyPropertyValues 执行属性注入

初始化阶段

-> initializeBean() -> BeanPostProcessor.postProcessBeforeInitialization() 执行前置方法 -> invokeInitMethods() 反射调用初始化方法 -> BeanPostProcessor.postProcessAfterInitialization 执行后置方法

收尾注册bean

->registerDisposableBeanIfNecessary() 注册bean

通过上面追踪refresh()方法我们可知,spring容器将先调用 AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition方法,然后执行 postProcessProperties 方法

3. postProcessMergedBeanDefinition 查找需要自动注入的字段或方法

	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);metadata.checkConfigMembers(beanDefinition);}

进入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);}//查找类的字段,方法,是否有需要自动注入对象的元素,封装InjectionMetadatametadata = buildAutowiringMetadata(clazz);//放入缓存中,供后面调用取出this.injectionMetadataCache.put(cacheKey, metadata);}}}return metadata;}

进入 buildAutowiringMetadata 方法

private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {//判断当前类是否有使用autowiredAnnotationTypes容器中的注解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<>();//反射遍历类中所有字段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);//封装InjectionMetadatacurrElements.add(new AutowiredFieldElement(field, required));}});//反射遍历类中所有方法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);//封装InjectionMetadatacurrElements.add(new AutowiredMethodElement(method, required, pd));}});elements.addAll(0, currElements);targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);return InjectionMetadata.forElements(elements, clazz);}

this.autowiredAnnotationTypes 为set集合,容器内为需要自动注入的注解类

private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
	public AutowiredAnnotationBeanPostProcessor() {## 1.@Autowiredthis.autowiredAnnotationTypes.add(Autowired.class);## 2.@Valuethis.autowiredAnnotationTypes.add(Value.class);try {## 3.@javax.inject.Inject  JSR-330规范中定义的一个注解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.}}

4.postProcessProperties 需要自动注入的元素从容器中获取bean后注入

	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;}

进入 metadata.inject() 方法

	public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Collection<InjectedElement> checkedElements = this.checkedElements;Collection<InjectedElement> elementsToIterate =(checkedElements != null ? checkedElements : this.injectedElements);if (!elementsToIterate.isEmpty()) {//遍历需要注入的元素for (InjectedElement element : elementsToIterate) {//不同类型调用各自inject方法element.inject(target, beanName, pvs);}}}

字段处理逻辑

通过 resolveFieldValue 方法,找到需要依赖的bean(单个或集合),通过 Filed.set方法注入

		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Field field = (Field) this.member;Object value;if (this.cached) {try {value = resolvedCachedArgument(beanName, this.cachedFieldValue);}catch (NoSuchBeanDefinitionException ex) {// Unexpected removal of target bean for cached argument -> re-resolvevalue = resolveFieldValue(field, bean, beanName);}}else {//查找依赖的beanvalue = resolveFieldValue(field, bean, beanName);}if (value != null) {ReflectionUtils.makeAccessible(field);//反射设置值field.set(bean, value);}}
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);try {Object shortcut = descriptor.resolveShortcut(this);if (shortcut != null) {return shortcut;}Class<?> type = descriptor.getDependencyType();Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);if (value != null) {if (value instanceof String) {String strVal = resolveEmbeddedValue((String) value);BeanDefinition bd = (beanName != null && containsBean(beanName) ?getMergedBeanDefinition(beanName) : null);value = evaluateBeanDefinitionString(strVal, bd);}TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());try {return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());}catch (UnsupportedOperationException ex) {// A custom TypeConverter which does not support TypeDescriptor resolution...return (descriptor.getField() != null ?converter.convertIfNecessary(value, type, descriptor.getField()) :converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));}}Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);if (multipleBeans != null) {return multipleBeans;}//字段非集合类型时bean时查找方法Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);if (matchingBeans.isEmpty()) {if (isRequired(descriptor)) {raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);}return null;}String autowiredBeanName;Object instanceCandidate;if (matchingBeans.size() > 1) {autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);if (autowiredBeanName == null) {if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);}else {// In case of an optional Collection/Map, silently ignore a non-unique case:// possibly it was meant to be an empty collection of multiple regular beans// (before 4.3 in particular when we didn't even look for collection beans).return null;}}instanceCandidate = matchingBeans.get(autowiredBeanName);}else {// We have exactly one match.Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();autowiredBeanName = entry.getKey();instanceCandidate = entry.getValue();}if (autowiredBeanNames != null) {autowiredBeanNames.add(autowiredBeanName);}if (instanceCandidate instanceof Class) {instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);}Object result = instanceCandidate;if (result instanceof NullBean) {if (isRequired(descriptor)) {raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);}result = null;}if (!ClassUtils.isAssignableValue(type, result)) {throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());}return result;}finally {ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);}}

findAutowireCandidates() 会调用 BeanFactoryUtils.beanNamesForTypeIncludingAncestors

底层通过类似双亲委派模型,找出所有的bean

	public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lbf, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {Assert.notNull(lbf, "ListableBeanFactory must not be null");String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);if (lbf instanceof HierarchicalBeanFactory) {HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {String[] parentResult = beanNamesForTypeIncludingAncestors((ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);result = mergeNamesWithParent(result, parentResult, hbf);}}return result;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/27399.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Sentinel流量规则模块(新增)

系统并发能力有限&#xff0c;比如系统A的QPS支持1个请求&#xff0c;如果太多请求过来&#xff0c;那么系统A就应该进行流量控制了&#xff0c;比如其他请求直接拒绝 新增流控规则介绍:新增流控规则窗口 1.资源名&#xff1a;默认请求路径。 2.针对来源&#xff1a;Se…

四维轻云地理空间数据在线协作管理平台为测绘行业用户解决了这些难题

测绘作为一个基础性行业&#xff0c;从大比例的地形图到铁路网、公路网的分布&#xff0c;再到互联网地图&#xff0c;测绘的身影随处可见。随着科技的不断发展与进步&#xff0c;无人机也成为测绘行业的一部分。通过无人机测绘技术能够获取高精度的影像数据并生成三维模型和点…

自监督语义分割面模型——Masked Autoencoders Are Scalable Vision Learners(MAE)论文阅读

1、摘要 This paper shows that masked autoencoders (MAE) are scalable self-supervised learners for computer vision. Our MAE approach is simple: we mask random patches of the input image and reconstruct the missing pixels. It is based on two core designs. F…

【动手学深度学习】pytorch-参数管理

pytorch-参数管理 概述 我们的目标是找到使损失函数最小化的模型参数值。 经过训练后&#xff0c;我们将需要使用这些参数来做出未来的预测。 此外&#xff0c;有时我们希望提取参数&#xff0c;以便在其他环境中复用它们&#xff0c; 将模型保存下来&#xff0c;以便它可以在…

Spark(26):Spark通讯架构

目录 0. 相关文章链接 1. Spark通信架构概述 2. Spark 通讯架构解析 0. 相关文章链接 Spark文章汇总 1. Spark通信架构概述 Spark 中通信框架的发展&#xff1a; Spark 早期版本中采用 Akka 作为内部通信部件。Spark1.3 中引入 Netty 通信框架&#xff0c;为了解决 Shuf…

今天实习第三天,vue(vue-cli部分,webpack部分,vue-router部分,elementUI部分)

01.创建第一个vue-cli。这里用的是node.js。早上的时候&#xff0c;就需要把node.js安装上去 02.node.js安装 第一步.去官网下载node.js https://nodejs.org/en 第二步.运行官网下载的node.js的msi文件&#xff08;记住所有的node.js文件的安装包都是msi文件的形式&#xff0…

qt和vue交互

1、首先在vue项目中引入qwebchannel /******************************************************************************** Copyright (C) 2016 The Qt Company Ltd.** Copyright (C) 2016 Klarlvdalens Datakonsult AB, a KDAB Group company, infokdab.com, author Milian …

APP加固:助力移动应用安全合规

近日&#xff0c;工业和信息化部发布了2023年第2批侵害用户权益行为的App&#xff08;SDK&#xff09;名单&#xff0c;55款App因涉及强制、频繁、过度索取权限等问题而被通报。这一举措进一步凸显了合规对于APP发展的重要性。 根据工业和信息化部的通报&#xff0c;被通报的这…

Vue3统计数值(Statistic)

可自定义设置以下属性&#xff1a; 数值的标题&#xff08;title&#xff09;&#xff0c;类型&#xff1a;string | slot&#xff0c;默认&#xff1a;‘’数值的内容&#xff08;value&#xff09;&#xff0c;类型&#xff1a;string | number&#xff0c;默认&#xff1a;…

【程序人生】如何在工作中保持稳定的情绪?

前言 在工作中保持稳定的情绪是现代生活中一个备受关注的话题。随着职场压力和工作挑战的增加&#xff0c;我们常常发现自己情绪波动不定&#xff0c;甚至受到负面情绪的困扰。然而&#xff0c;保持稳定的情绪对于我们的工作效率、人际关系和整体幸福感都至关重要。 无论你是…

Delete `␍`eslint(prettier/prettier)报错的终极解决方案

1.背景 在进行代码仓库clone打开后&#xff0c;vscode报错全屏的 Delete ␍eslint(prettier/prettier)问题 原因是因为&#xff1a; 罪魁祸首是git的一个配置属性&#xff1a; 由于历史原因&#xff0c;windows下和linux下的文本文件的换行符不一致。* Windows在换行的时候&…

Spring 框架——事件驱动模型

目录 1.概述2.三种角色2.1.事件角色2.2.事件监听者角色2.3.事件发布者角色 3.示例 1.概述 &#xff08;1&#xff09;Spring 事件驱动模型是 Spring 框架中的一种编程模型&#xff0c;也被称为发布/订阅模型&#xff0c;通过使用观察者模式和事件机制&#xff0c;实现了组件之…