程序员社区

Spring 框架源码解读4


title: Spring 框架源码解读4
date: 2020/04/16 13:56


本节内容 & 思考题

Spring 创建对象的几种方式?

1、空参构造(@Component)

<bean id="apple" class="cn.x5456.Apple" />

2、静态工厂方法(了解)

<bean id="apple" class="cn.x5456.Apple" factory-method="createApple" />
public Apple createApple() {
    return new Apple();
}

3、实例工厂(@Bean)

<bean name="appleFactory" class="cn.x5456.AppleFactory" />

<bean id="apple" factory-bean="appleFactory" factory-method="createApple" />

本节将会介绍第一种和第三种配置的实现方式(不会介绍注解实现)

注:本教程暂不考虑有参构造(包括自动注入的有参构造),因为其实都是差不多的。


装饰者模式:BeanWrapper

策略模式:实例化对象的方式

新增工厂方法创建对象

1、BD 新增字段

// 工厂类注册到容器中的 beanName
private String factoryBean;

// 工厂方法名
private String factoryMethod;

2、修改 ABF

/**
 * 根据 bd 创建对象
 * <p>
 * 1)创建bean 日后需要对有参构造进行扩展
 * 2)注入属性  日后新增
 * 3)执行初始化操作
 * 4)注册销毁的处理
 */
private Object createBean(BeanDefinition beanDefinition) {

    // 1、创建 bean
    Object bean = this.createBeanInstance(beanDefinition);

    // 2、注入属性 todo

    // 3、执行初始化操作(在 Spring 中是直接调用的该类中的 initializeBean 方法,为了让他面向对象一点,我给他抽出一个类)
    InitializeBeanAdapter initializeBeanAdapter = new InitializeBeanAdapter(bean, beanDefinition);
    initializeBeanAdapter.afterPropertiesSet();

    // 4、注册销毁的处理
    if (this.check(beanDefinition, bean)) {
        registry.registerDisposableBean(beanDefinition.getName(), new DisposableBeanAdapter(bean, beanDefinition));
    }

    return bean;
}

/**
    * 分两种情况
    * <p>
    * 1. 工厂方法(无参版)
    * 2. 空参构造
    */
private Object createBeanInstance(BeanDefinition beanDefinition) {
    if (ObjectUtil.isNotNull(beanDefinition.getFactoryBean())) {
        // 从容器中找到工厂对象
        Object bean = this.getBean(beanDefinition.getFactoryBean());
        if (ObjectUtil.isNull(bean)) {
            throw new RuntimeException("工厂 bean 不存在!");
        }
        return ReflectUtil.invoke(bean, beanDefinition.getFactoryMethod());
    }

    return ReflectUtil.newInstance(beanDefinition.getClassName());
}

3、测试

public class TestJsonBF {
    public static void main(String[] args) {
        ListableBeanFactory bf = new JsonBeanFactoryImpl("/Users/x5456/IdeaProjects/Summer/src/test/resources/apple.json");
        Apple apple = bf.getBean("apple", Apple.class);
        System.out.println(apple);
    }
}

apple.json

[
  {
    "name": "appleFactory",
    "className": "cn.x5456.summer.AppleFactory"
  },
  {
    "name": "apple",
    "factoryBean": "appleFactory",
    "factoryMethod": "createApple"
  }
]

public class AppleFactory {

    public Apple createApple() {
        Apple apple = new Apple();
        apple.setName("黄元帅");
        return apple;
    }
}

思考:配置文件中把 factory 放到 bean 的后面会不会报错吗?

不会,因为 BF 先把所有的 BD 读到 BDMap 中,然后 AP 再一个一个 get,不管先后顺序,总能获取到对象;这也是 BF 懒加载的好处。

Spring 0.9

Spring 0.9 只有根据构造创建的,所以没有参考 0.9 版本

Spring 5.0

创建 Bean 部分代码

// AbstractAutowireCapableBeanFactory.java

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // Make sure bean class is actually resolved at this point.
    Class<?> beanClass = resolveBeanClass(mbd, beanName);

    // 判断一个类的访问权限, Spring默认情况下对于非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());
    }

    // 不重要,跳过
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }


    // 这里是处理工厂方法的,比如你的类里面设置了一个工厂方法返回一个对象,比如:
    //  @Bean
    //  public static Object query() {
    //    return new Ant();
    //  }
    //  xml配置如下:
    //  <bean id="user" class="com.ant.context.service.UserService" factory-method="query">
    //
    //  </bean>
    //  那么这个query方法就会在这里处理,这里spring就会给你构建一个新的对象Ant,然后放到实例容器中去
    if (mbd.getFactoryMethodName() != null)  {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }


    // 重新创建同一个bean时的快捷方式(Shortcut)...
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                // 如果已经解析了构造方法的参数,则直接把这个属性设置为true
                // 则后面的if判断方法则会直接进入,而不会去执行后续的方法
                resolved = true;
                // 如果已经解析了构造方法参数, 则必须要通过一个带参构造方法来实例
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }

    // 判断是否已经解析过了构造函数
    if (resolved) {
        if (autowireNecessary) {
            // 通过构造方法自动装配的方式构造 bean 对象
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            // 通过默认的无参构造方法进行
            return instantiateBean(beanName, mbd);
        }
    }

    // 这个方法比较重要,spring通过判断我们的bean对象的构造方法的数量和结构,
    // 来判断我们在实例化对象的时候,到底要使用哪个构造函数去对我们的bean进行实例化
    // 如果我们的bean只有一个默认的无参构造方法,则会返回null
    // Candidate constructors for autowiring?
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
        // 如果我们的bean自己有一个特殊的构造方法,则会执行这个方法,这个方法比较复杂,也比较重要
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // 如果bean只有一个默认的无参构造方法,则使用下面的方法去实例化我们的bean对象
    // No special handling: simply use no-arg constructor.
    return instantiateBean(beanName, mbd);
}

1)工厂方法方式

Spring 框架源码解读4插图
Spring 框架源码解读4插图1
  1. 从工厂类中找到用户配置的那个方法
  2. 找到那个方法需要依赖注入的参数
  3. 如果没找到工厂方法则抛出异常,检查返回值是不是 void
  4. 和下面一样,选个策略创建对象
Spring 框架源码解读4插图2
有参版本
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="appleFactory" class="com.dist.ars.aop.AppleFactory" />

    <bean id="apple" factory-bean="appleFactory" factory-method="createApple">
        <constructor-arg ref="seed" />
    </bean>

    <bean name="seed" class="com.dist.ars.aop.Seed" />
</beans>

2)空参构造方式

Spring 框架源码解读4插图3
Spring 框架源码解读4插图4
Spring 框架源码解读4插图5
Spring 框架源码解读4插图6

这就是创建对象的流程,再往下就是 DI 了,也是使用 BeanWrapper 的目的。

赞(0) 打赏
未经允许不得转载:IDEA激活码 » Spring 框架源码解读4

一个分享Java & Python知识的社区