04.实例化Bean


title: 04.实例化Bean
tag: 笔记 手写SSM IOC

读取信息后根据信息去创建Bean。

分析

在注册了所有的BeanDefination之后,我们就可以进行Bean的实例创建了。

在学习Spring的过程中我们学习到,通常依赖注入的方式有三种:

  • 构造方法注入
  • Setter方法注入
  • 字段注入(不推荐)

除了以上三种之外,我们还有一种方式:

  • FactoryMethod工厂方法注入。
@Configuration
public class AppConfig {
    @Bean
    Hello hello(@Autowired JdbcTemplate jdbcTemplate) {
        return new Hello(jdbcTemplate);
    }
}

我们可以根据实例化Bean和注入Bean的时机来将这四种种注入分为两种

  • Bean的创建与注入是一体的,我们无法拆分。
    • 构造方法注入
    • 工厂方法注入

这种方式我们通过调用方法来实例化Bean,在Bean被实例化时,同时也被初始化了。

  • Bean的创建与注入可以分开
    • Setter方法注入
    • 属性注入

这种方式我们可以在Bean实例化后再通过反射调用方法或者字段来完成注入。

循环依赖

然后我们可以分析循环依赖问题,循环依赖问题就是A、B互相依赖,或者A依赖B,B依赖C,C依赖A,形成了一个闭环。

循环依赖也可以分为两种:

  1. 属性必须通过构造方法初始化
class A {
    final B b;
    A(B b) { this.b = b; }
}

class B {
    final A a;
    B(A a) { this.a = a; }
}

这种方式在Java中是不能通过编译器编译的。因此我们把这样的依赖称为强依赖,之前构造方法注入和工厂方法注入的依赖就属于此类,这样的循环依赖我们只能报错。

  1. 属性不必在初始化阶段赋值
class A {
    B b;
}

class B {
    A a;
}

这样的依赖我们称为弱依赖,之前的Setter方法和注入属性注入就属于此类。

这样的循环依赖我们可以先实例化Bean,再注入依赖。

// 第一步,实例化:
A a = new A();
B b = new B();
// 第二步,注入:
a.b = b;
b.a = a;

因此,对于IoC容器来说,创建Bean的过程分两步:

  1. 创建Bean的实例,此时必须注入强依赖
  2. 对Bean实例进行Setter方法注入和字段注入

第一步如果遇到循环依赖则直接报错,第二步则不需要关心有没有循环依赖。

实例化Bean

有了上面的基础后,我们就可以开始进行Bean的实例化了。

因为实例化阶段是在获取BeanDefiniation之后,因此我们的入口类如下设计:

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    super();
    this.reader = new AnnotatedBeanDefinitionReader(this);
    register(componentClasses);//注册BeanDefiniation并读取配置文件
    createBean();//实例化Bean
    .....
}

这样我们可以在后面需要扩展时只需要在下面继续调用方法即可,并且方便用户使用,只需要传入一个注解配置类即可启动容器。

现在我们只需要实现这个createBean()方法的逻辑即可。

逻辑实现

我们在这个阶段需要检测循环依赖,我们可以定义一个Set<String>跟踪当前正在创建的所有Bean的名称,并在创建Bean的方法开始使用下面的代码检测循环依赖:

if (!this.creatingBeanNames.add(def.getName())) {
        // 检测到重复创建Bean导致的循环依赖:
        throw new UnsatisfiedDependencyException();
    }

由于@Configuration标识的Bean实际上是工厂,它们必须先实例化,才能实例化其他普通Bean,所以我们先把@Configuration标识的Bean创建出来,再创建普通Bean:

protected void createBean(){
    createConfigurationBean();
    createCommonBean();
}

private void createConfigurationBean(){
        beans.values()
                .stream()
                .filter(this::isConfigurationDefinition)
                .sorted()
                .forEach(this::createBeanAsEarlySingleton);

    }

private void createCommonBean(){
        List<BeanDefinition> beanDefinitions = beans.values()
                .stream()
                .filter(beanDefinition -> beanDefinition.getInstance() == null)
                .toList();
        beanDefinitions.forEach(beanDefinition -> {
            if(beanDefinition.getInstance() == null) createBeanAsEarlySingleton(beanDefinition);
        });
    }

接下来需要实现的就是createBeanAsEarlySingleton了:

/**
 * 向BeanDefinition中插入实例化后的对象
 * @param definition Bean定义信息
 */
@Override
protected Object createBeanAsEarlySingleton(BeanDefinition definition) {
    logger.atDebug().log("Try create bean '{}' as early singleton: {}",
            definition.getName(), definition.getBeanClass().getName());
    //循环依赖报错
    if(!creatingBeanNames.add(definition.getName())){
        throw new UnsatisfiedDependencyException(
                String.format("Circular dependency detected when create bean '%s'", definition.getName()));
    }
    Executable createFun = definition.getFactoryName() == null ?
            definition.getConstructor() : definition.getFactoryMethod();
    assert createFun != null;
    Parameter[] parameters = createFun.getParameters();//拿到参数
    Annotation[][] annotations = createFun.getParameterAnnotations();//拿到参数的注解
    Object[] args = new Object[parameters.length];//为参数注入值
    for(int i = 0; i < args.length; i++){
        Parameter curParameter = parameters[i];
        Annotation[] curParameterAnnotations = annotations[i];
        Value value = ClassUtils.getAnnotation(curParameterAnnotations, Value.class);
        Autowired autowired = ClassUtils.getAnnotation(curParameterAnnotations, Autowired.class);
        // @Configuration类型的Bean是工厂,不允许使用@Autowired创建:
        final boolean isConfiguration = isConfigurationDefinition(definition);
        if (isConfiguration && autowired != null) {
            throw new BeanCreationException(
                    String.format("Cannot specify @Autowired when create @Configuration bean '%s': %s."
                            , definition.getName(), definition.getBeanClass().getName()));
        }

        // 参数需要@Value或@Autowired两者之一:
        if (value != null && autowired != null) {
            throw new BeanCreationException(
                    String.format("Cannot specify both @Autowired and @Value when create bean '%s': %s."
                            , definition.getName(), definition.getBeanClass().getName()));
        }
        if (value == null && autowired == null) {
            throw new BeanCreationException(
                    String.format("Must specify @Autowired or @Value when create bean '%s': %s.",
                            definition.getName(), definition.getBeanClass().getName()));
        }
        final Class<?> type = curParameter.getType();
        if(value != null){
            args[i] = propertyResolver.getProperty(value.value(),type);
        }else{
            String dependencyName = autowired.name();
            boolean required = autowired.value();
            BeanDefinition dependencyDefinition = dependencyName.isEmpty() ?
                    findBeanDefinition(type) : findBeanDefinition(dependencyName, type);
            if(required && dependencyDefinition == null){
                throw new BeanCreationException(String.format("Missing autowired bean with type '%s' when create bean '%s': %s.", type.getName(),
                        definition.getName(), definition.getBeanClass().getName()));
            }
            if(dependencyDefinition != null){
                Object dependencyInstance = dependencyDefinition.getInstance();
                if(dependencyInstance == null){
                    dependencyInstance = createBeanAsEarlySingleton(dependencyDefinition);
                }
                args[i] = dependencyInstance;
            }else{
                args[i] =null;
            }
        }
    }
    Object instance = null;
    if(definition.getFactoryName() == null){
        try {
            instance = definition.getConstructor().newInstance(args);
        } catch (Exception e) {
            throw new BeanCreationException(String.format("Exception when create bean '%s': %s",
                    definition.getName(), definition.getBeanClass().getName()), e);
        }
    }else{
        Object bean = getBean(definition.getFactoryName());
        try {
            instance = definition.getFactoryMethod().invoke(bean,args);
        }catch (Exception e){
            throw new BeanCreationException(String.format("Exception when create bean '%s': %s",
                    definition.getName(), definition.getBeanClass().getName()), e);
        }
    }
    definition.setInstance(instance);
    return instance;
}

上面的代码虽然很长,但主要逻辑就是:

  1. 检测循环依赖
  2. 通过构造函数的参数列表获取到对应注入的值,如果有依赖Bean则递归拿到依赖。
  3. 拿到注入的值之后调用工厂方法或者构造方法拿到实例。

注意:

这里的递归调用:

public Object createBeanAsEarlySingleton(BeanDefinition def) {
    ...
    Object[] args = new Object[parameters.length];
    for (int i = 0; i < parameters.length; i++) {
        ...
        // 获取依赖Bean的实例:
        Object autowiredBeanInstance = dependsOnDef.getInstance();
        if (autowiredBeanInstance == null && !isConfiguration) {
            // 当前依赖Bean尚未初始化,递归调用初始化该依赖Bean:
            autowiredBeanInstance = createBeanAsEarlySingleton(dependsOnDef);
        }
        ...
    }
    ...
}

依赖注入过程

假设如下的Bean依赖:

@Component
class A {
    // 依赖B,C:
    A(@Autowired B, @Autowired C) {}
}

@Component
class B {
    // 依赖C:
    B(@Autowired C) {}
}

@Component
class C {
    // 无依赖:
    C() {}
}

如果按照A、B、C的顺序创建Bean实例,那么系统流程如下:

  1. 准备创建A;
  2. 检测到依赖B:未就绪;
    1. 准备创建B:
    2. 检测到依赖C:未就绪;
      1. 准备创建C;
      2. 完成创建C;
    3. 完成创建B;
  3. 检测到依赖C,已就绪;
  4. 完成创建A。

如果按照B、C、A的顺序创建Bean实例,那么系统流程如下:

  1. 准备创建B;
  2. 检测到依赖C:未就绪;
    1. 准备创建C;
    2. 完成创建C;
  3. 完成创建B;
  4. 准备创建A;
  5. 检测到依赖B,已就绪;
  6. 检测到依赖C,已就绪;
  7. 完成创建A。

可见无论以什么顺序创建,C总是最先被实例化,A总是最后被实例化

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值