源码系列1 - 从 Bean 开始说起

什么是 Spring Bean ?

简单来说,就是被 IoC 容器所管理的对象。 这些 Bean 是根据我们提供给容器配置的元数据。

Bean 的创建方式

xml 方式

在 SpringBoot 作为通用框架的大环境下,xml 方式注册 Bean 基本上不怎么使用了,所以一下只是简单提及。


    

注解方式

注解通常作为 SpringBoot 的使用姿势,我们通常是使用 @Controller、@Service、@Mapper、@Compoment等注解。

当我们使用注解修饰时,Spring 会在启动过程中自动加载,生产单例/原型 Bean,实例如下:

@Compoment
public class Test {
    ...
}

JavaConfig

顾名思义,这种方式主要是使用 @Configuration 注解来声明配置类,然后在配置类中通过 @Bean 的方式声明 Bean,实例如下:

public Test {
    ...
}

@Configuration
public class config {

@Bean
public Test getTest() {
    ...
    return new Test(); 
}

}

值得注意的是,该配置类也会被 Spring 视为一个Bean

工厂类

我们可以利用 FactoryBean 生成一个单例 Bean。示例如下:

public class Test {
    ...
}

public class TestFactoryBean implements FactoryBean {

@Override
public Test getObject() throws Exception {
    return new Test();
}

@Override
public Class<!--?--> getObjectType() {
    return Test.class;
}

}

利用 Spring 容器

除了以上注册Bean的容器之外,ApplicationContext 实现也允许我们手动创建现有的对象。

  • 使用AnnotationConfigApplicationContext.register()方法
  • 使用DefaultListableBeanFactory.registerSingleton(..) 或者 registerBeanDefinition(..) 方法等等 当然,该方法具有强烈的耦合性,如果新建 Bean 过于复杂,或者存在循环依赖问题,不太推荐使用

使用方法

根据 Bean 的注册方法,我们也可以大概明白 Spring 有哪些使用方法。

注解方式

可以使用 @Autowired 或者 @Resource 注解添加到成员变量上,便可由容器自动注入。

构造方法/ Setter 方法

我们可以利用构造方法和 Setter 方法手动注入到属性中。

利用 Spring 容器

除了以上两种方式以外,Spring 实现也允许我们手动获取现有的对象。 比如 ApplicationContext下的 getBean() 方法。

Bean 的前世

当一个快递到达菜鸟驿站,工作人员会先将快递记录下来,分配一个取货码,然后我们就可以根据取货码去获取快递啦。 而 Spring 也不例外,当一个 Bean 被注册进容器后,他会使用一个取货码记录这个 Bean 的相关信息,以方便后续依赖注入/动态代理。

这个“取货码”的名字就是 BeanDefinition。 通常他会记录以下信息:

  • bean的类信息
  • Bean 属性信息,用于说明Bean在容器中的行为方式(scope,lazyInit等)
  • 依赖性信息(dependsOn)
  • 新创建对象中设置的其他配置设置,比如 池的大小,自动注入模型(autowireCandidate)等
  • Bean 的创建、销毁初始化等。

他的类图如下所示:

当然,我们并不需要关注太多,只需要注意一下几个类就行。

  • GenericBeanDefinition -> xml 定义
  • ScannedGenericBeanDefintion -> @Compoment 以及派生注解定义
  • AnnotatedGenericBeanDefintion -> @Bean 定义的方法
  • RootBeanDefintion -> 在 Spring Factory 初始化 Bean 的前阶段,会根据扫描生成的 BeanDefiniction 合并生成。

参考资料

Spring Framework


这是一个从 https://juejin.cn/post/7368701816442617907 下的原始话题分离的讨论话题