写点什么

0 源码基础学习 Spring 源码系列(一)——Bean 注入流程

  • 2023-02-13
    北京
  • 本文字数:17754 字

    阅读完需:约 58 分钟

0源码基础学习Spring源码系列(一)——Bean注入流程

作者:京东科技 韩国凯

通过本文,读者可以 0 源码基础的初步学习 spring 源码,并能够举一反三从此进入源码世界的大米!


由于是第一次阅读源码,文章之中难免存在一些问题,还望包涵指正!

一、 @Autowired 与 @Resource 的区别

用一句话总结两者的区别就是: @Autowired 会先通过类型注入,即 byType,当存在有多个类型时会通过名称注入。@Resource 则相反,会先通过名称注入,即 byName,当名称不存在或有多个名称时会通过类型注入。


那么通过名称注入与通过类型注入有什么区别呢?


//创建接口interface StuService{    String getName();}
@Service//Stu2实现接口并注册beanclass Stu2 implements StuService{ @Override public String getName() { return "stu2"; }}
@Service//Stu3实现接口并注册beanclass Stu3 implements StuService{ @Override public String getName() { return "stu3"; }}
复制代码

1.1 @Autowired

那么此时如果我们对 StuService注入, @Autowired 可以选择注入的类型就有两个,分别是 Stu2与 Stu3


需要注意的是,类型有很多种选择:


  1. 当注册 bean 与获取 bean 为同一个类时,类型只有这个类本身。


例如,我们有获取 session 的工具类,需要将其注入到 spring 之中,


@Componentclass SessionUtil{    public String getSession(){        return "session";    }}
复制代码


只有一个类,直接注册 bean,使用时可以任意选择


@AutowiredSessionUtil sessionUtil;
复制代码


此时 @Autowired 只有一个注册类型,直接注入。


  1. 当注册 bean 有多个时,类型为所有注册的 bean,实现方式有:实现接口、继承、通过其他方式,例如 xml 配置注册 bean。


例如上述 StuService有多个实现类,每个实现类都注册了 bean,因此 @Autowired 可以选择的类型就有两个。


@AutowiredStuService stu;
复制代码


根据上述的 @Autowired 逻辑,此时有多个类型,那么会根据 bean name 查找,(即类名首字母小写的),发现 stu没有对应的实现类,


此时会报错:


Field stu in com.example.demo.spring.Stu1 required a single bean, but 2 were found:


只需要将 stu 替换成 stu2或 stu3即可完成注入。


继承和其他方式同时有多个 bean 注入时同理。


因此,@Autowired 中类型的定义可以归结为:当注册 bean 有多个时,类型为所有注册的 bean,实现方式有:实现接口、继承、通过其他方式,例如 xml 配置注册 bean 或者 @Bean 注册。

1.2 @Resource

  1. 当只有一个 bean 时,可以直接注册


@AutowiredSessionUtil sessionUtil;
复制代码


  1. 当有多个 bean 注册时,如果未指定名称,则 bean name 为类名首字母小写,指定了 bean 名称则注册名称为该名称。


例如上文中 Stu1 Stu2都未指定 bean 名称,因此两者的 bean 名称分别为 stu1 stu2


当使用 @Bean 在方法上注册 bean,此时名称为方法名称。


@Bean()public Student getStudent(){    Student student = new Student();    student.setName("bob");    student.setId(26);    return student;}
复制代码


此时该 bean 名称为 getStudent


同样,我们也可以注册 bean 时自定义 bean 名称


@Bean("stu1")public Student getStudent(){    Student student = new Student();    student.setName("bob");    student.setId(26);    return student;}
@Service("stu2")class Stu2 implements StuService{ @Override public String getName() { return "stu2"; }}
@Component("stu3")class Stu3 implements StuService{ @Override public String getName() { return "stu3"; }}
复制代码


在引用时指定 bean:


@Resource(name = "stu2")private StuService stu1;
复制代码

1.3 @Autowired

当我们使用 @Resource 时,会根据名称也就是 stu2去查询,此时 bean 名称只有一个,查到返回


@Resourceprivate Stu3 stu2;
复制代码


但是在执行时却发现报错:


Bean named 'stu2' is expected to be of type 'com.example.demo.spring.Stu3' but was actually of type 'com.example.demo.spring.Stu2'
复制代码


这是因为只根据了 bean 名称去查询,却没有根据 bean 类型,查到的是Stu2类型的 bean,但是期望的却是Stu3,因此会发生类型不匹配。

二、SpringIOC 的 Bean 注入流程

spring 的注册流程主要包含两个部分:


  1. 容器的启动阶段及预热工作

  2. Bean 的注入流程


先了解一下几个概念:

2.1 概念介绍

2.1.1 配置元数据

存在于磁盘上的项目中用于描述一个 bean 的数据,可以是 xml、properties、yaml 等静态文件,也可以是各种注解描述的对应信息,例如 @Service、@Component 描述的一个 bean 的信息。


<bean id="role" class="com.wbg.springxmlbean.entity.Role">    <property name="id" value="1"/>    <property name="roleName" value="高级工程师"/>    <property name="note" value="重要人员"/></bean>
复制代码


以上就是一个由 xml 定义的配置元数据。

2.1.2 BeanDefinition 与 BeanDefinitionReader

在 spring 中,无论是那种配置元数据,最终都会转换为BeanDefinition,由 BeanDefinition 描述要生成并被引用的对象,可以理解为 BeanDefinition 就是 bean 的生成模板,或者是 bean 的说明书,按照 BeanDefinition 生成 bean。


而将配置元数据转换为BeanDefinition的工作就是由BeanDefinitionReader完成的,对于不同的的配置元数据有不同的 Reader 完成对应的工作,例如有XmlBeanDefinitionReader读取 xml 配置信息,PropertiesBeanDefinitionReader读取 properties 配置信息,AnnotatedBeanDefinitionReader读取注解的配置信息。


BeanDefinitionReader 的作用就是将磁盘上的文件信息或注解信息转化为内存中用于描述 bean 的 BeanDefinition。

2.1.3 BeanFactoryPostProcessor

BeanFactoryPostProcessor 是容器启动阶段 Spring 提供的一个扩展点,主要负责对注册到 BeanDefinitionRegistry 中的一个个的 BeanDefinition 进行一定程度上的修改与替换。例如我们的配置元信息中有些可能会修改的配置信息散落到各处,不够灵活,修改相应配置的时候比较麻烦,这时我们可以使用占位符的方式来配置。例如配置 Jdbc 的 DataSource 连接的时候可以这样配置:


<bean id="dataSource"      class="org.apache.commons.dbcp.BasicDataSource"      destroy-method="close">      <property name="maxIdle" value="${jdbc.maxIdle}"></property>      <property name="maxActive" value="${jdbc.maxActive}"></property>      <property name="maxWait" value="${jdbc.maxWait}"></property>      <property name="minIdle" value="${jdbc.minIdle}"></property>        <property name="driverClassName"          value="${jdbc.driverClassName}">      </property>      <property name="url" value="${jdbc.url}"></property>        <property name="username" value="${jdbc.username}"></property>      <property name="password" value="${jdbc.password}"></property>  </bean> 
复制代码


BeanFactoryPostProcessor 就会对注册到 BeanDefinitionRegistry 中的 BeanDefinition 做最后的修改,替换 $占位符为配置文件中的真实的数据。

2.1.4 BeanDefinitionRegistry

一个存储 BeanDefinition 的地方,存储方式为 KV 值,key 为 beanName,value 为 BeanDefinition。

2.1.5 容器启动阶段

容器的启动阶段相对比较简单,首先会将存在于各处的磁盘上的配置元信息由各自的 Reader 读取到内存之中,转换成BeanDefinition,然后注册到BeanDefinationRegistry之中,最后由BeanFactoryPostProcessor进行修改与替换。


2.1.6 BeanFactory 与 FactoryBean

BeanFactory 与 FactoryBean 的名字很像,但是确实两个不同的东西。


根据命名规则来看,BeanFactory 是一个 Factory,也就是一个存放 bean 的工厂,在创建 bean 完成后放到其中,使用是从其中获取。


而 FactoryBean 则是一个 bean,只不过与不同的的 bean 不同的是他不仅可以创建本身类型的 bean,也可以类似于 Factory 一样创建一层有包装的新的 bean。这个 Bean 可以返回一个新的类型的 bean,在返回之前也可以对其进行加工。


@Componentclass FactoryBeanDemo implements FactoryBean<Student>{
@Override public Student getObject() { return new Student(); }
@Override public Class<?> getObjectType() { return Student.class; }}
复制代码


创建一个 FactoryBean 只需要实现其接口,并实现其中的两个方法。当我们获取 FactoryBean 时,会返回其中 getObject()方法返回的对象。而如果想要获取 FactoryBean 本身,只需要在 bean name 前加一个"&"符号即可。


@Resource()private Object factoryBeanDemo;
@GetMapping("/getStu")private String getBean(){ System.out.println(factoryBeanDemo.getClass()); return stu2.getName();}
复制代码


//输出结果class com.example.demo.domain.Student
复制代码


可以看到获取到的是 Student 类型。


class com.example.demo.spring.FactoryBeanDemo
复制代码


将获取 bean 名称假“&”符号:


@Resource(name = "&factoryBeanDemo")private Object factoryBeanDemo;
复制代码


class com.example.demo.spring.FactoryBeanDemo
复制代码


可以看到获取到的对象变成了 FactoryBeanDemo 本身。

2.2 Bean 注入流程

在容器启动阶段,已经完成了 bean 的注册。如果该对象是配置成懒加载的方式,那么直到我们向 Spring 要依赖对象实例之前,其都是以 BeanDefinitionRegistry 中的一个个的 BeanDefinition 的形式存在,也就是 Spring 只有在我们第一次依赖对象的时候才开启相应对象的实例化阶段。而如果我们不是选择懒加载的方式,容器启动阶段完成之后,其中有一个步骤 finishBeanFactoryInitialization(),在这一步将立即启动 Bean 实例化阶段,通过隐式的调用所有依赖对象的 getBean 方法来实例化所有配置的 Bean,完成类的加载。


doGetBean():获取并返回 bean


doGetBean()的主要流程有两个:


  • 尝试从缓存中获取 bean,如果获取到直接返回。

  • 如果没有获取到则尝试加载 bean。


protected <T> T doGetBean(      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)      throws BeansException {
String beanName = transformedBeanName(name); Object beanInstance;
// Eagerly check singleton cache for manually registered singletons. // 1、查询缓存中是否存在,存在的话直接返回 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); } } // 根据缓存中的bean获取实例,主要是检测如果是FactoryBean类型,则获取其内部的getObject()的bean。(需要先了解FactoryBean的作用) beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null); }
//2、不存在则创建bean else { // Fail if we're already creating this bean instance: // We're assumably within a circular reference. if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }
// Check if bean definition exists in this factory. // 2.1 尝试从父类的Factory加载bean BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup, args); } else if (requiredType != null) { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } }
if (!typeCheckOnly) { markBeanAsCreated(beanName); }
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate") .tag("beanName", name); try { if (requiredType != null) { beanCreation.tag("beanType", requiredType::toString); } /* * 2.2 获取RootBeanDefinition:首先会根据beanName获取BeanDefinition,然后将BeanDefinition转换为RootBeanDefinition * BeanDefinition 接口的实现类有很多,通过不同方式注册到 BeanDefinitionRegistry 中的 BeanDefinition 的类型可能都不太相同。 最终,在通过 BeanDefinition 来创建 bean 的实例时,通常都会调用 getMergedBeanDefinition 来获取到一个 RootBeanDefinition。 所以,RootBeanDefinition 本质上是 Spring 运行时统一的 BeanDefinition 视图。 * */ RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on. // 2.3 初始化依赖的bean String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } registerDependentBean(dep, beanName); try { getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } }
// Create bean instance. // 2.4 创建实例 if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { //返回真正的bean return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } }
return adaptBeanInstance(name, beanInstance, requiredType);}
复制代码

2.2.1 mbd = getMergedLocalBeanDefinition(beanName)获取 BeanDefinition

RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);


BeanDefinition 接口的实现类有很多,通过不同方式注册到 BeanDefinitionRegistry 中的 BeanDefinition 的类型可能都不太相同。

最终,在通过 BeanDefinition 来创建 bean 的实例时,通常都会调用 getMergedBeanDefinition 来获取到一个 RootBeanDefinition。所以,RootBeanDefinition 本质上是 Spring 运行时统一的 BeanDefinition 视图。


此处就是将各种 BeanDefinition 统一转换为 spring 能识别的 RootBeanDefinition。

2.2.2 getSingleton(String beanName, ObjectFactory<?> singletonFactory) 获取创建好的对象

sharedInstance = getSingleton(beanName, () -> {   try {      //返回真正的bean      return createBean(beanName, mbd, args);   }   catch (BeansException ex) {      // Explicitly remove instance from singleton cache: It might have been put there      // eagerly by the creation process, to allow for circular reference resolution.      // Also remove any beans that received a temporary reference to the bean.      destroySingleton(beanName);      throw ex;   }});
复制代码


getSingleton()方法中获取创建好的对象


//获取singletonFactory返回的结果singletonObject = singletonFactory.getObject();
复制代码


getSingleton()方法中最主要的一次调用也就是从singletonFactory中获取对象,而获取对象的结果就是上面代码中传入的匿名工厂返回的结果,也就是 createBean(beanName, mbd, args)

2.2.3 createBean(beanName, mbd, args) 创建 bean

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)      throws BeanCreationException {
if (logger.isTraceEnabled()) { logger.trace("Creating instance of bean '" + beanName + "'"); } RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and // clone the bean definition in case of a dynamically resolved Class // which cannot be stored in the shared merged bean definition. // 1.解析bean class Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); }
// Prepare method overrides. // 2.准备覆盖的方法 try { mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", ex); }
try { // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. // 3.尝试返回代理创建的Bean,这个作用就是查找bean中所有实现前置和后置处理器的接口,有没有手工创建然后返回的,代替了spring的创建bean的流程 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } } catch (Throwable ex) { throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", ex); }
try { //4.真正创建bean Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { // A previously detected exception with proper bean creation context already, // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry. throw ex; } catch (Throwable ex) { throw new BeanCreationException( mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex); }}
复制代码


创建 bean 主要有以下几步:


  1. 解析 bean 的 class 文件,为后面的根据 class 文件通过反射创建对象做准备。

  2. 预处理 bean 的 Override 属性,预处理的方式也比较简单,就是在方法 prepareMethodOverride 中判断一下,如果 lookup-method 标签或者 replaced-method 标签中配置了 bean 中需要覆盖的方法,就将 MethodOverride 中的 overload 属性值设置为 false。

  3. 尝试通过反射获取被代理的 bean。

  4. 真正创建 bean 的过程

2.2.4 Object beanInstance = doCreateBean(beanName, mbdToUse, args) 开始创建 bean

以上流程都是获取 bean 前的流程或获取 bean 的准备,doCreateBean 是真正的创建并填充 bean 的流程(去掉了一些不重要的代码)。


protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)      throws BeanCreationException {
// Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { //1.通过反射创建实例化对象,并将其放入wraaper中。wraaper可以理解为bean的包装对象,里面是bean实例的,还有一些其他bean的属性方便使用 instanceWrapper = createBeanInstance(beanName, mbd, args); } Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; }
// Allow post-processors to modify the merged bean definition. //2.允许后处理处理器修改合并后的bean定义,这里只是解析这些@Autowired @Value @Resource @PostConstruct等这些注解,并没有发生实际属性注入的动作 synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } mbd.postProcessed = true; } }
// Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. //3.是否需要提前曝光,用来解决循环依赖时使用 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); }
// Initialize the bean instance. Object exposedObject = bean; //4.将实例化完成成的bean填充属性 populateBean(beanName, mbd, instanceWrapper); //5.调用初始化方法,例如 init-method exposedObject = initializeBean(beanName, exposedObject, mbd); //6.循环依赖检查 if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } } } }
// Register bean as disposable. //7.注册bean try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); }
return exposedObject;}
复制代码


从上述流程中可以看到,我们创建一个 bean 主要有以下几个流程:


  1. 首先通过 class 根据反射创建对象,此时该对象的所有的属性都为空,可以理解为我们 new 出的空属性对象。

  2. 解析 @Autowired @Value @Resource @PostConstruct 这些注解,但并没有发生属性注入的行为。

  3. 是否需要提前曝光,用来解决循环依赖时使用,主要作用是如果需要代理会返回代理对象,如果不需要代理,返回前面创建的对象

  4. 将第一步实例化完成的空属性对象填充属性,其中如果该 bean 依赖了其他 bean,也会在此步骤将依赖的 bean 装配,如果 bean 已经被创建,则直接属性注入,如果不存在,则创建 bean,创建方式跟本 bean 相同,可以理解为递归。

  5. 将实例化完成的 bean 对象初始化,主要查看 bean 是否实现了一些前置或后置或初始化的方法,如果是的话就执行。

  6. 循环依赖检查。

  7. 根据 scope 注册 bean。


可以看到,经过以上的几个步骤,我们就获取到了一个实例 bean。


其中最重要的三个方法:


  1. 实例化 bean

  2. 装配属性

  3. 初始化 bean

2.2.5 总结

总结来说,创建 bean 的流程就是先根据反射获取对象,然后填充对象的属性,初始化,最后将 bean 注册。


2.3 创建 bean 流程深入理解

上文我们只粗略的讲解了创建 bean 的过程,并没有深入的查看源码是如何实现的,例如通过反射获取对象是怎么获取的,填充属性是如何填充的,下文将详细阐述 2.2.5 过程中在源码层面是如何构建的。

2.3.1 instanceWrapper = createBeanInstance(beanName, mbd, args) 获取实例化对象

该方法通过反射获取实例化的空属性对象。


protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {   // Make sure bean class is actually resolved at this point.   //1.1解析class   Class<?> beanClass = resolveBeanClass(mbd, beanName);
//1.2确认public权限 if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName()); }
//2.如果存在 Supplier 回调,则调用 obtainFromSupplier() 进行初始化,因为反射获取对象的效率比较低 Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); }
if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); }
// Shortcut when re-creating the same bean... boolean resolved = false; boolean autowireNecessary = false; if (args == null) { synchronized (mbd.constructorArgumentLock) { /* * 3.如果args为空且方法已经被resolved,则会直接选择对应的构造方法 * mbd.resolvedConstructorOrFactoryMethod的赋值在下方【1】【2】的代码中赋值 * */ if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { if (autowireNecessary) { return autowireConstructor(beanName, mbd, null, null); } else { return instantiateBean(beanName, mbd); } }
// Candidate constructors for autowiring? //4.自动装配的构造方法 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); }
// Preferred constructors for default construction? //5.是否有首选构造方法 ctors = mbd.getPreferredConstructors(); if (ctors != null) { return autowireConstructor(beanName, mbd, ctors, null); }
// No special handling: simply use no-arg constructor. //6.通过默认的无参构造函数 return instantiateBean(beanName, mbd);}
复制代码


  1. 首先解析 class 文件与确认 public 权限。

  2. 如果存在 Supplier 回调,则调用 obtainFromSupplier() 进行初始化,因为反射获取对象的效率比较低。

  3. 如果 args 为空且使用那个构造函数已经被确定了,则进行标记,后续直接选择使用那种构造方法。

  4. 如果 args 不为空或没有被解析过,则选择使用那种构造方法来构造实例化的对象:


Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);


Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName);


选择 AutowiredAnnotationBeanPostProcessor 实现类:


其中重要的代码已贴出:


//1.遍历所有的构造方法for (Constructor<?> candidate : rawCandidates) {   if (!candidate.isSynthetic()) {      nonSyntheticConstructors++;   }   else if (primaryConstructor != null) {      continue;   }   //2.查看当前构造方法是否有@Autowired注解   MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);   if (ann == null) {      Class<?> userClass = ClassUtils.getUserClass(beanClass);      if (userClass != beanClass) {         try {            Constructor<?> superCtor =                  userClass.getDeclaredConstructor(candidate.getParameterTypes());            ann = findAutowiredAnnotation(superCtor);         }         catch (NoSuchMethodException ex) {            // Simply proceed, no equivalent superclass constructor found...         }      }   }   //3.如果有@Autowired注解   if (ann != null) {      //4.如果已经有一个@Autowired注解,则说明存在多个@Autowired注解,则抛出异常      if (requiredConstructor != null) {         throw new BeanCreationException(beanName,               "Invalid autowire-marked constructor: " + candidate +               ". Found constructor with 'required' Autowired annotation already: " +               requiredConstructor);      }      boolean required = determineRequiredStatus(ann);      if (required) {         if (!candidates.isEmpty()) {            throw new BeanCreationException(beanName,                  "Invalid autowire-marked constructors: " + candidates +                  ". Found constructor with 'required' Autowired annotation: " +                  candidate);         }         requiredConstructor = candidate;      }      candidates.add(candidate);   }   //5无参构造函数   else if (candidate.getParameterCount() == 0) {      //将其设置为默认构造函数      defaultConstructor = candidate;   }}//对上面的处理过程进行判断//6.1先检查是否有@Autowired注解if (!candidates.isEmpty()) {   // Add default constructor to list of optional constructors, as fallback.   if (requiredConstructor == null) {      if (defaultConstructor != null) {         candidates.add(defaultConstructor);      }      else if (candidates.size() == 1 && logger.isInfoEnabled()) {         logger.info("Inconsistent constructor declaration on bean with name '" + beanName +               "': single autowire-marked constructor flagged as optional - " +               "this constructor is effectively required since there is no " +               "default constructor to fall back to: " + candidates.get(0));      }   }  //返回@Autowired注解的构造方法   candidateConstructors = candidates.toArray(new Constructor<?>[0]);}//6.2如果只有一个有参构造函数,则返回该有参函数else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {   candidateConstructors = new Constructor<?>[] {rawCandidates[0]};}//6.3对于非Kotlin类只会返回null,所以这里不会进入else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&      defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {   candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};}else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {   candidateConstructors = new Constructor<?>[] {primaryConstructor};}else {   //6.4对于不能识别的场景会进入到这里,例如有多个构造函数但是并没有指定@Autowired注解或者没有构造函数(java会帮我们生成一个无参的构造函数),返回null   candidateConstructors = new Constructor<?>[0];}
复制代码


2-5 步会对所有的构造函数进行检查,并在检查完进行标记,并会在第 6 步对标记的结果进行返回,按照 ifelse 判断顺序主要分为以下几种情况:


  • 如果有 @Autowired 注解的方法则返回该构造方法

  • 如果只有一个有参构造函数则会返回该有参构造函数

  • 对于不能识别的场景会进入到这里,例如有多个构造函数但是并没有指定 @Autowired 注解或者没有构造函数(java 会帮我们生成一个无参的构造函数)会返回 null


在获取到需要的构造函数后,会进行标记,下次不用再次解析可以直接选用那个构造函数,即上文的第 4 步


  1. 是否有首选的构造函数

  2. 如果都没有的话,通过默认的无参构造函数创建对象。


我们查看代码发现,无论第 4 步返回什么结果,最终会执行以下两个方法:


autowireConstructor()与instantiateBean()


两者都会调用


instantiate()方法


最终都会执行以下这个方法


BeanUtils.instantiateClass(constructorToUse)


也就是如下的代码


for (int i = 0 ; i < args.length; i++) {   if (args[i] == null) {      Class<?> parameterType = parameterTypes[i];      argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);   }   else {      argsWithDefaultValues[i] = args[i];   }}return ctor.newInstance(argsWithDefaultValues);
复制代码


其中最重要的一句:


return ctor.newInstance(argsWithDefaultValues);


可以发现,也就是这里通过反射的方式创建了一个空属性对象,并一层层返回,直到后面的属性装配等过程,可以说这里就是 bean 加载过程的源头。

2.3.2 applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName) 解析各种注解

该方法主要解析该 bean 所相关的注解,例如属性有 @Resource,bean 中 @PostConstruct 注解都会被解析。


for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {   processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);}
复制代码


processor 主要有两个实现类:


  1. AutowiredAnnotationBeanPostProcessor 处理 @Autowired 和 @Value 注解 bean 定义信息

  2. CommonAnnotationBeanPostProcessor 处理 @Resource、@PostConstruct、@PreDestroy 注解的 bean 定义信息


这里需要注意的是,该方法只是会解析并不会真正的进行注入,因为学习意义不大,并不在赘述。

2.3.3 populateBean(beanName, mbd, instanceWrapper) 对实例化完成的 bean 进行属性注入

//遍历所有的属性for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {   //对属性进行装填   PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);   if (pvsToUse == null) {      if (filteredPds == null) {         filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);      }      pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);      if (pvsToUse == null) {         return;      }   }   pvs = pvsToUse;}
复制代码


其中 bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName)有几个实现方法,比较重要的是:


  1. AutowiredAnnotationBeanPostProcessor,主要装配属性是 @Autowired 与 @Value 的属性

  2. CommonAnnotationBeanPostProcessor,主要装配属性是 @Resource 的属性


两者最终都会进入如下方法:


//判断要注入的是属性还是方法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();   }}
复制代码


理解起来比较简单,判断是方法注入还是属性注入,在注入时注入的对象为:


getResourceToInject(target, requestingBeanName)


找到ResourceElement的实现方法中getResource()方法:


返回了 autowireResource(this.resourceFactory, element, requestingBeanName)


if (factory instanceof AutowireCapableBeanFactory) {   AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;   DependencyDescriptor descriptor = element.getDependencyDescriptor();   if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {      autowiredBeanNames = new LinkedHashSet<>();      resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);      if (resource == null) {         throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");      }   }   else {      resource = beanFactory.resolveBeanByName(name, descriptor);      autowiredBeanNames = Collections.singleton(name);   }}else {   resource = factory.getBean(name, element.lookupType);   autowiredBeanNames = Collections.singleton(name);}
复制代码


在这个方法中,无论是 if 还是 else,最终都会调用


getBean(name, element.lookupType)
复制代码


也就是我们 bean 注入的入口,这个过程很像递归,在我们创建 bean 时,如果发现我们有依赖的其他 bean,那么就会去创建依赖的 bean,如果依赖的 bean 还有其依赖的属性则又会去创建被依赖的属性,只到最终全部创建完成,返回一开始想要创建的 bean。

2.3.4 exposedObject = initializeBean(beanName, exposedObject, mbd)初始化 bean

在该方法中,会对已经填充过属性的 bean 进行初始化:


Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {   //对bean的前置处理,其中@PostConstruct就在此步骤中   wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}
try { //调用初始化方法如果bean实现了InitializingBean接口,则先执行InitializingBean接口的afterPropertiesSet方法,然后执行xml或注解设置的init-method方法。 invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) { //对bean进行后置处理,对象的代理发生在此步骤中 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}
复制代码


在初始化 bean 的时候,主要分为三个部分,分别是applyBeanPostProcessorsBeforeInitialization、invokeInitMethods、applyBeanPostProcessorsAfterInitialization,分别对应于初始化的前置处理、自定义 init 方法、后置处理。


applyBeanPostProcessorsBeforeInitialization、applyBeanPostProcessorsAfterInitialization两个方法的大概逻辑就是获取获取所有实现其接口的类,然后执行其中被覆盖的方法。


常用的注解执行顺序如下:


  1. @PostConstruct 注解修饰的方法

  2. InitializingBean 接口的 afterPropertiesSet()方法

  3. init-method 指定的方法

  4. @PreDestroy 注解修饰的方法

  5. DisposableBean 接口的 destroy()方法

  6. destory-method 指定的方法


并且在代码中可以看到,前置处理与后置处理都可以改变 bean。


在容器启动阶段我们讲到 BeanFactoryPostProcessor,这里我们讲到 BeanPostProcessor,那么 BeanFactoryPostProcessor 和 BeanPostProcessor 有什么区别呢?

BeanFactoryPostProcessor 存在于容器启动阶段,而 BeanPostProcessor 存在于对象实例化阶段,BeanFactoryPostProcessor 关注对象被创建之前那些配置的修改,而 BeanPostProcessor 阶段关注对象已经被创建之后的功能增强,替换等操作,这样就很容易区分了。

BeanPostProcessor 与 BeanFactoryPostProcessor 都是 Spring 在 Bean 生产过程中强有力的扩展点。Spring 中著名的 AOP(面向切面编程),其实就是依赖 BeanPostProcessor 对 Bean 对象功能增强的。


BeanFactoryPostProcessor 主要用于解决实例化之前,对实例的属性进行拓展,而 BeanPostProcessor 是在实例化之后对对象做的拓展。

2.4 总结

用简单的话描述一下,创建一个 bean 的过程大概包括三部分:


  1. 通过反射实例化 bean

  2. 属性装配以及填充

  3. 初始化,包括 init-method、以及其前后三个步骤。其中 AOP 增强就是发生在初始化之后的applyBeanPostProcessorsAfterInitialization的步骤中。


通过以上的步骤,就可以获得我们可以正常使用的一个 bean。

发布于: 刚刚阅读数: 4
用户头像

拥抱技术,与开发者携手创造未来! 2018-11-20 加入

我们将持续为人工智能、大数据、云计算、物联网等相关领域的开发者,提供技术干货、行业技术内容、技术落地实践等文章内容。京东云开发者社区官方网站【https://developer.jdcloud.com/】,欢迎大家来玩

评论

发布
暂无评论
0源码基础学习Spring源码系列(一)——Bean注入流程_spring_京东科技开发者_InfoQ写作社区