@Autowired注解的实现原理
创始人
2024-03-30 21:22:47
0

        @Autowired注解可以被标注在构造函数、属性、setter方法或配置方法上,用于实现依赖自动注入。

这里对@Autowired注解底层进行源码分析

参考:https://blog.csdn.net/One_L_Star/article/details/114829247

        @Autowired注解的作用是由AutowiredAnnotationBeanPostProcessor实现的,查看该类的源码会发现它实现了MergedBeanDefinitionPostProcessor接口,进而实现了接口中的postProcessMergedBeanDefinition方法,@Autowired注解正是通过这个方法实现注入类型的预解析,将需要依赖注入的属性信息封装到InjectionMetadata类中,InjectionMetadata类中包含了哪些需要注入的元素及元素要注入到哪个目标类中,在Spring容器启动的过程中初始化单例bean的时候通过populateBean方法实现对属性的注入。

   

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) {if (beanType != null) {InjectionMetadata metadata = this.findAutowiringMetadata(beanName, beanType, (PropertyValues)null);metadata.checkConfigMembers(beanDefinition);}
}public class InjectionMetadata {private static final Log logger = LogFactory.getLog(InjectionMetadata.class);private final Class targetClass;private final Collection injectedElements;private volatile Set checkedElements;

        

 Spring对autowire注解的实现逻辑位于类:AutowiredAnnotationBeanPostProcessor#postProcessProperties之中,——>findAutowiringMetadata——>buildAutowiringMetadata,核心代码就在buildAutowiringMetadata方法里面

private InjectionMetadata buildAutowiringMetadata(Class clazz) {if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {return InjectionMetadata.EMPTY;} else {List elements = new ArrayList();// 需要处理的目标类Class targetClass = clazz;do {List currElements = new ArrayList();// 通过反射获取该类所有的字段,并遍历每一个字段,并通过方法findAutowiredAnnotation遍历每一个字段的所用注解,并如果用autowired修饰了,则返回auotowired相关属性ReflectionUtils.doWithLocalFields(targetClass, (field) -> {MergedAnnotation ann = this.findAutowiredAnnotation(field);if (ann != null) {// 校验autowired注解是否用在了static方法上if (Modifier.isStatic(field.getModifiers())) {if (this.logger.isInfoEnabled()) {this.logger.info("Autowired annotation is not supported on static fields: " + field);}return;}// 判断是否指定了requiredboolean required = this.determineRequiredStatus(ann);currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement(field, required));}});// 和上面一样的逻辑,但是是通过反射处理类的methodReflectionUtils.doWithLocalMethods(targetClass, (method) -> {Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);if (BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {MergedAnnotation ann = this.findAutowiredAnnotation(bridgedMethod);if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {if (Modifier.isStatic(method.getModifiers())) {if (this.logger.isInfoEnabled()) {this.logger.info("Autowired annotation is not supported on static methods: " + method);}return;}if (method.getParameterCount() == 0 && this.logger.isInfoEnabled()) {this.logger.info("Autowired annotation should only be used on methods with parameters: " + method);}boolean required = this.determineRequiredStatus(ann);PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement(method, required, pd));}}});// 用@Autowired修饰的注解可能不止一个,因此都加在currElements这个容器里面,一起处理elements.addAll(0, currElements);targetClass = targetClass.getSuperclass();} while(targetClass != null && targetClass != Object.class);return InjectionMetadata.forElements(elements, clazz);}
}
  • 获取需要处理的目标类
  • 通过doWithLocalFields方法传入目标类参数,通过反射获取该类所有的字段,并遍历每一个字段,并通过方法findAutowiredAnnotation遍历每一个字段的所用注解,并如果用autowired修饰了,则返回auotowired相关属性
  • 判断autowired注解是否用在了static方法上
  • 如有多个@Autowired修饰的注解,都加在currElements这个容器里面,一起处理

最后返回包含所有带有autowire注解修饰的一个InjectionMetadata集合,如下

  • targetClass:要处理的目标类
  • elements:上述方法获取到的所以elements集合
public InjectionMetadata(Class targetClass, Collection elements) {this.targetClass = targetClass;this.injectedElements = elements;
}

        

        有了目标类,与所有需要注入的元素集合之后,我们就可以实现autowired的依赖注入逻辑了,实现的方法如下:

public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {if (!this.validatedBeanNames.contains(beanName)) {if (!this.shouldSkip(this.beanFactory, beanName)) {List invalidProperties = new ArrayList();PropertyDescriptor[] var6 = pds;int var7 = pds.length;for(int var8 = 0; var8 < var7; ++var8) {PropertyDescriptor pd = var6[var8];if (this.isRequiredProperty(pd) && !pvs.contains(pd.getName())) {invalidProperties.add(pd.getName());}}if (!invalidProperties.isEmpty()) {throw new BeanInitializationException(this.buildExceptionMessage(invalidProperties, beanName));}}this.validatedBeanNames.add(beanName);}return pvs;
}

 调用InjectionMetadata中定义的inject方法:

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Collection checkedElements = this.checkedElements;Collection elementsToIterate = checkedElements != null ? checkedElements : this.injectedElements;if (!((Collection)elementsToIterate).isEmpty()) {Iterator var6 = ((Collection)elementsToIterate).iterator();while(var6.hasNext()) {InjectionMetadata.InjectedElement element = (InjectionMetadata.InjectedElement)var6.next();element.inject(target, beanName, pvs);}}
}

进行遍历,然后调用inject方法,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);field.set(target, this.getResourceToInject(target, requestingBeanName));} else {if (this.checkPropertySkipping(pvs)) {return;}try {Method method = (Method)this.member;ReflectionUtils.makeAccessible(method);// 注入的bean的名字,这个方法的功能就是根据这个bean的名字去拿到它method.invoke(target, this.getResourceToInject(target, requestingBeanName));} catch (InvocationTargetException var5) {throw var5.getTargetException();}}
}
  • 使用了反射技术,分成字段和方法去处理的。
  • makeAccessible这样的可以称之为暴力破解的方法,通过反射技术对对象进行实例化和赋值
  • getResourceToInject方法的参数就是要注入的bean的名字,这个方法的功能就是根据这个bean的名字去拿到它

@AutoWired自动注入过程图:

 

相关内容

热门资讯

货币政策工具加力支持 □ 本报记者 詹 超 【场景】 昆山开发区,苏州清陶动力科技有限公司车间的固态电池生产线嗡嗡作响,金...
我国继续实施更加积极的财政政策 经济日报北京12月28日讯(记者曾金华)记者从全国财政工作会议获悉,今年财政工作取得新成效,为推动完...
吴中区“三强化”促进法律服务业... 苏州市吴中区锚定“升级服务产业、优化营商环境、赋能高质量发展”核心目标,以政策为引领、平台为支撑、人...
央行:稳妥有序完善房地产信贷基... |2025年12月29日 星期一| NO.1 央行:稳妥有序完善房地产信贷基础性制度 12月26日,...
大金重工[002487]关于诉... 本版导读 2025-12-29 2025-12-29 2025-12-29 2025...
国务院国资委:完善国有资产管理... 国务院国资委党委书记、主任张玉卓在学习时报刊发文章《坚定不移做强做优做大国有企业和国有资本》。其中提...
“惠民政策落不到村”,紧抓!(... 本报记者 郑洋洋 “重点研究周武村党组织软弱涣散的问题,大家直奔主题,谈谈看法。”山西长治市潞城区店...
财政政策如何继续“更加积极” 记者从27日至28日举行的全国财政工作会议获悉:2026年要继续实施更加积极的财政政策,扩大财政支出...
落户政策居然考虑放开! 怎么,我能落户北京了? 大家好,我是孙少睡,这是我的第467篇楼市评论。 很多人的第一反应肯定是有没...
股市必读:ST泉为股东因涉嫌违... 截至2025年12月26日收盘,ST泉为(300716)报收于9.96元,下跌0.8%,换手率0.9...