Spring 源码(九)@Autowired注解实现原理(Spring Bean的自动装配)

@Autowired注解的实现过程,其实就是Spring Bean的自动装配过程。通过看@Autowired源码注释部分我们可以看到@Autowired的实现是通过AutowiredAnnotationBeanPostProcessor后置处理器中实现的。

AutowiredAnnotationBeanPostProcessor 类图

  • PriorityOrdered:确认 AutowiredAnnotationBeanPostProcessor 后置处理器的执行优先级
  • BeanFactoryAware:使得AutowiredAnnotationBeanPostProcessor 可以直接通过BeanFactory获取容器中的Bean
  • BeanPostProcessor:在 Bean 初始化前后执行的后置处理器
  • InstantiationAwareBeanPostProcessor:在 Bean 实例化前后和Bean设置属性值时执行的后置处理器
  • SmartInstantiationAwareBeanPostProcessor:智能实例化Bean的后处理器,如预测Bean的类型和确认Bean的构造函数等。
  • MergedBeanDefinitionPostProcessor:合并Bean的定义信息。

在分析自动装配前我们先来介绍一下上面的这些后置处理器。

后置处理器介绍

BeanPostProcessor

BeanPostProcessor有两个方法,postProcessBeforeInitializationpostProcessAfterInitialization。它们分别在任何bean初始化回调之前或之后执行(例如InitializingBean的afterPropertiesSet方法或自定义init-method方法之前或者之后), 在这个时候该bean的属性值已经填充完成了,并且我们返回的bean实例可能已经是原始实例的包装类型了。例如返回一个FactoryBean

InstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor继承自BeanPostProcessor接口。主要多提供了以下三个方法。

postProcessBeforeInstantiation

该方法是在Bean实例化目标对象之前调用,返回的Bean对象可以代理目标,从而有效的阻止了目标Bean的默认实例化。

1protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { 2 Object bean = null; 3 if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { 4 // Make sure bean class is actually resolved at this point. 5 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { 6 Class<?> targetType = determineTargetType(beanName, mbd); 7 if (targetType != null) { 8 bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); 9 if (bean != null) { 10 // 如果此方法返回一个非null对象,则Bean创建过程将被短路。 11 // 唯一应用的进一步处理是来自已配置BeanPostProcessors的postProcessAfterInitialization回调 12 bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); 13 } 14 } 15 } 16 mbd.beforeInstantiationResolved = (bean != null); 17 } 18 return bean; 19} 20 21protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) { 22 for (BeanPostProcessor bp : getBeanPostProcessors()) { 23 if (bp instanceof InstantiationAwareBeanPostProcessor) { 24 InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; 25 // 执行Bean实例化目标对象之前的后置处理方法 26 Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); 27 if (result != null) { 28 return result; 29 } 30 } 31 } 32 return null; 33}

跟进源码我们可以看出,如果此方法返回一个非null对象,则Bean创建过程将被短路。唯一应用的进一步处理是来自已配置BeanPostProcessors的postProcessAfterInitialization回调。

postProcessAfterInstantiation

该方法执行在通过构造函数或工厂方法在实例化bean之后但在发生Spring属性填充(通过显式属性或自动装配)之前执行操作。这是在Spring的自动装配开始之前对给定的bean实例执行自定义字段注入的理想回调。如果该方法返回false,那么它会阻断后续InstantiationAwareBeanPostProcessor后置处理器的执行,并且会阻止后续属性填充的执行逻辑。

postProcessPropertyValues

在工厂将给定属性值应用于给定bean之前,对它们进行后处理。允许检查是否满足所有依赖关系,例如基于bean属性设置器上的“ Required”注解。还允许替换要应用的属性值,通常是通过基于原始PropertyValues创建新的MutablePropertyValues实例,添加或删除特定值来实现。

SmartInstantiationAwareBeanPostProcessor

智能实例化Bean的后处理器,主要提供了三个方法。

predictBeanType

预测从此处理器的postProcessBeforeInstantiation回调最终返回的bean的类型。

determineCandidateConstructors

确定使用实例化Bean的构造函数。

getEarlyBeanReference

获取提早暴露的Bean的引用,提早暴露的Bean就是只完成了实例化,还未完成属性赋值和初始化的Bean。

MergedBeanDefinitionPostProcessor

postProcessMergedBeanDefinition

合并Bean的定义信息的后处理方法,该方法是在Bean的实例化之后设置值之前调用。

自动装配的实现

找到需要自动装配的元素

AutowiredAnnotationBeanPostProcessor后置处理器主要负责对添加了@Autowired和@Value注解的元素实现自动装配。所以找到需要自动装配的元素,其实就是对@Autowired和@Value注解的解析。

AutowiredAnnotationBeanPostProcessor后置处理器,找出需要自动装配的元素是在MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition这个方法中实现的,调用链路如下:

1doWith:445, AutowiredAnnotationBeanPostProcessor$2 (org.springframework.beans.factory.annotation) 2doWithLocalFields:657, ReflectionUtils (org.springframework.util) 3buildAutowiringMetadata:433, AutowiredAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation) 4findAutowiringMetadata:412, AutowiredAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation) 5postProcessMergedBeanDefinition:235, AutowiredAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation) 6applyMergedBeanDefinitionPostProcessors:1000, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) 7doCreateBean:523, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) 8createBean:483, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) 9getObject:312, AbstractBeanFactory$1 (org.springframework.beans.factory.support) 10getSingleton:230, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support) 11doGetBean:308, AbstractBeanFactory (org.springframework.beans.factory.support) 12getBean:197, AbstractBeanFactory (org.springframework.beans.factory.support) 13preInstantiateSingletons:761, DefaultListableBeanFactory (org.springframework.beans.factory.support) 14finishBeanFactoryInitialization:867, AbstractApplicationContext (org.springframework.context.support) 15refresh:543, AbstractApplicationContext (org.springframework.context.support) 16<init>:84, AnnotationConfigApplicationContext (org.springframework.context.annotation)

从链路上我们可以看到,找到需要自动装配的元素是在findAutowiringMetadata方法中实现的,该方法会去调用buildAutowiringMetadata方法构建元数据信息。如果注解被加载属性上将会被封装成AutowiredFieldElement对象;如果注解加在方法上,那么元素会被封装成AutowiredMethodElement对象。这里两个对象的inject方法将最后完成属性值的注入,主要区别就是使用反射注入值的方式不一样。源码如下:

1private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) { 2 LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>(); 3 Class<?> targetClass = clazz; 4 5 do { 6 // 存放我们找到的元数据信息 7 final LinkedList<InjectionMetadata.InjectedElement> currElements = 8 new LinkedList<InjectionMetadata.InjectedElement>(); 9 10 // 通过反射找出对应Class对象的所有Field 11 ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() { 12 @Override 13 public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { 14 // 通过反射找到该字段上所有的注解信息,并判断是否有@Autowired和@Value注解,如果有就将该字段封成AutowiredFieldElement对象 15 AnnotationAttributes ann = findAutowiredAnnotation(field); 16 if (ann != null) { 17 if (Modifier.isStatic(field.getModifiers())) { 18 if (logger.isWarnEnabled()) { 19 logger.warn("Autowired annotation is not supported on static fields: " + field); 20 } 21 return; 22 } 23 boolean required = determineRequiredStatus(ann);24 // 将该字段封成AutowiredFieldElement对象,并放到缓存中 25 currElements.add(new AutowiredFieldElement(field, required)); 26 } 27 } 28 }); 29 30 // 通过反射找出对应Class对象的所有Method 31 ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() { 32 @Override 33 public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { 34 Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); 35 if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) { 36 return; 37 } 38 // 通过反射找到该字段上所有的注解信息,并判断是否有@Autowired和@Value注解,如果有就将该字段封成AutowiredMethodElement对象 39 AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod); 40 if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { 41 if (Modifier.isStatic(method.getModifiers())) { 42 if (logger.isWarnEnabled()) { 43 logger.warn("Autowired annotation is not supported on static methods: " + method); 44 } 45 return; 46 } 47 if (method.getParameterTypes().length == 0) { 48 if (logger.isWarnEnabled()) { 49 logger.warn("Autowired annotation should only be used on methods with parameters: " + 50 method); 51 } 52 } 53 boolean required = determineRequiredStatus(ann); 54 PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); 55 // 将该字段封成AutowiredMethodElement对象 56 currElements.add(new AutowiredMethodElement(method, required, pd)); 57 } 58 } 59 }); 60 61 elements.addAll(0, currElements); 62 targetClass = targetClass.getSuperclass(); 63 } 64 // 循环处理父类需要自动装配的元素 65 while (targetClass != null && targetClass != Object.class); 66 // 将需要自动装配的元素封装成InjectionMetadata对象,最后合并到Bean定义中 67 return new InjectionMetadata(clazz, elements); 68}

寻找需要自动装配过程:

  1. 根据Class对象,通过反射获取所有的Field和```Method````对象
  2. 通过反射获取FieldMethod上的注解,并判断是否有@Autowired和@Value注解
  3. 将注解了@Autowired和@Value的FieldMethod封装成AutowiredFieldElementAutowiredMethodElement对象,等待下一步的自动装配。
  4. 循环处理父类需要自动装配的元素
  5. 将需要自动装配的元素封装成InjectionMetadata对象,最后合并到Bean定义的externallyManagedConfigMembers属性中

注入属性值

AutowiredAnnotationBeanPostProcessor后置处理器注入属性值是在postProcessPropertyValues方法中实现的。源码如下:

1public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable { 2 // 获取需要自动装配的元数据信息(这里实在缓存中取) 3 Collection<InjectedElement> elementsToIterate = 4 (this.checkedElements != null ? this.checkedElements : this.injectedElements); 5 if (!elementsToIterate.isEmpty()) { 6 boolean debug = logger.isDebugEnabled(); 7 for (InjectedElement element : elementsToIterate) { 8 if (debug) { 9 logger.debug("Processing injected element of bean '" + beanName + "': " + element); 10 } 11 // 调用AutowiredFieldElement或AutowiredMethodElement对象的inject方法注入属性值 12 element.inject(target, beanName, pvs); 13 } 14 } 15}

AutowiredFieldElement#inject

1@Override 2protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { 3 Field field = (Field) this.member; 4 Object value; 5 if (this.cached) { 6 value = resolvedCachedArgument(beanName, this.cachedFieldValue); 7 } 8 else { 9 DependencyDescriptor desc = new DependencyDescriptor(field, this.required); 10 desc.setContainingClass(bean.getClass()); 11 Set<String> autowiredBeanNames = new LinkedHashSet<String>(1); 12 TypeConverter typeConverter = beanFactory.getTypeConverter(); 13 try { 14 // 在容器中获取需要装配的Bean 15 value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); 16 } 17 ... 18 } 19 if (value != null) { 20 // 通过反射设置属性值 21 ReflectionUtils.makeAccessible(field); 22 field.set(bean, value); 23 } 24}

AutowiredMethodElement#inject

1@Override 2protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { 3 if (checkPropertySkipping(pvs)) { 4 return; 5 } 6 Method method = (Method) this.member; 7 Object[] arguments; 8 if (this.cached) { 9 // Shortcut for avoiding synchronization... 10 arguments = resolveCachedArguments(beanName); 11 } 12 else { 13 Class<?>[] paramTypes = method.getParameterTypes(); 14 arguments = new Object[paramTypes.length]; 15 DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length]; 16 Set<String> autowiredBeans = new LinkedHashSet<String>(paramTypes.length); 17 TypeConverter typeConverter = beanFactory.getTypeConverter(); 18 for (int i = 0; i < arguments.length; i++) { 19 MethodParameter methodParam = new MethodParameter(method, i); 20 DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required); 21 currDesc.setContainingClass(bean.getClass()); 22 descriptors[i] = currDesc; 23 try { 24 // 在容器中获取需要装配的Bean 25 Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter); 26 if (arg == null && !this.required) { 27 arguments = null; 28 break; 29 } 30 arguments[i] = arg; 31 } 32 catch (BeansException ex) { 33 throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex); 34 } 35 } 36 ... 37 } 38 if (arguments != null) { 39 try { 40 // 通过反射调用方法设置元素值 41 ReflectionUtils.makeAccessible(method); 42 method.invoke(bean, arguments); 43 } 44 ... 45 } 46}

从这里的源码我们可以看出AutowiredFieldElementAutowiredMethodElement完成自动装配都是先去容器中找对应的Bean,然后通过反射将获取到的Bean设置到目标对象中,来完成Bean的自动装配。

总结

我们可以看出Spring Bean的自动装配过程就是:

  1. 根据Class对象,通过反射获取所有的FieldMethod信息
  2. 通反射获取FieldMethod的注解信息,并根据注解类型,判断是否需要自动装配
  3. 将需要自动装配的元素,封装成AutowiredFieldElementAutowiredMethodElement对象
  4. 调用AutowiredFieldElementAutowiredMethodElementinject方法,唤起后续步骤
  5. 通过调用容器的getBean()方法找到需要注入的源数据Bean
  6. 通过反射将找到的源数据Bean注入到目标Bean中

在自动装配过程中还涉及循环依赖的问题,有兴趣的可以看下这篇文章Spring 源码(八)循环依赖

注意:注解注入将在XML注入之前执行;因此,对于通过这两种方法注入的属性,XML注入将覆盖注解注入。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )