前言

使用 Java 作为第一开发语言的朋友们,相信大家或多或少的都使用过 Spring 这个开发框架,可以说 Spring 框架真是我们 Java 程序员的春天,在 Spring 中 Bean 是其中最重要的概念之一,是学习其它高级知识的基础,Bean 说白了其实就是一个被 Spring 框架管理的对象,今天我们来看看 Bean 在 Spring 中是如何被造出来的。

1. Bean 要如何定义

假如你有如下这样的一个 Programmer 类,这个程序员类有三个属性: 姓名(name)、年龄(age)、是否有女朋友(hasGirlFriend)(P.S. 正常情况下 hasGirlFriend 属性应该都是 false),还有一个显示个人资料的方法 showMaterial。

/**
* @Author: mghio
* @Date: 2020-10-05
* @Description: Programmer.
*/
public class Programmer { private String name; private Integer age; private Boolean hasGirlFriend; public void showMaterial() {
System.out.println("name: " + name + ", age: " + age + ", hasGirlFriend: " + hasGirlFriend);
}
}

现在请你思考一下,如果让你来设计该如何在一个 Spring 容器中描述这样的一个 Programmer 对象呢?

无非就是需要如下这些信息:

1.1 类名

首先类名肯定是需要的,这样到时候才能通过类名加载到这个类。

1.2 实例别名

当我们在一个容器中如果一个类有多个实例或者不想通过一个类名来描述一个实例时,这时通过设置一个别名就可以很方便的描述该实例了。

1.3 构造函数

我们知道 Java 中创建一个类的实例首先就会调用该类的构造函数,当有多个构造函数时,需要明确的描述要使用哪个构造函数来创建对象,比如通过传入不同的参数类型来选择不同的构造函数。

1.4 类的属性设置

当我们没有在构造函数中传入属性,比如上面的 Programmer 可以直接通过无参构造函数就可以创建出来了,后面如果需要设置实例的属性则需要调用其设置属性的方式来进行设置,所以属性方法也是必要的。

1.5 初始化方法

有时候我们需要在一个实例化完成之后做一些我们自定义的业务逻辑,比如想让上面例子中的 Programmer 在实例化完成之后就显示个人资料(调用 showMaterial() 方法),这种场景使用初始化方法就很合适了。

1.6 销毁方法

说到销毁,大家可能都会想到和资源有关,比如一个共识就是大家一般都把资源释放类的工作放在 finally 代码块中确保资源可以得到释放,同样当一个 Bean 之后连接使用了某些资源时,当销毁后想要对这些资源进行释放,这时候就可以通过其 销毁方法 来释放资源。

1.7 作用域

有些 Bean 可能需要在整个容器中只有一个,也就是单例,而有些可能要求每一次请求对应的 Bean 都不一样,这时可以通过一个 作用域 的概念,来区分不同要求的 Bean,当容器发现这个类是 单例 的,就会复用已存在的 Bean,否则才重新创建。

当然这里只是列举一些个人觉得比较重要的属性,还有其它的一些属性需要增加。在 Spring 框架中 Bean 的定义是通过一个 BeanDefinition 类来描述的。

在没有使用 SpringBoot 之前我们都是通过 XML 配置然后 Spring 来解析生成 Bean 的,同时我们也可以通过代码方式使用 BeanDefinitionBuilder 生成 Bean,具体代码如下所示:

/**
* @Author: mghio
* @Date: 2020-10-05
* @Description:
*/
public class ProgrammerTest { public static void main(String[] args) {
new Programmer().showMaterial(); BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Programmer.class);
beanDefinitionBuilder.addPropertyValue("name", "mghio");
beanDefinitionBuilder.addPropertyValue("age", 18);
beanDefinitionBuilder.addPropertyValue("hasGirlFriend", false); DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("programmer", beanDefinitionBuilder.getBeanDefinition()); Programmer programmer = (Programmer) beanFactory.getBean("programmer");
programmer.showMaterial();
} }

运行结果如下:

在使用 XML 方式时一般是通过调用 ClassPathXmlApplicationContext 来注册 Bean 的,其构造函数可以传入具体的 XMl配置文件的路径,可以是一个或者多个,甚至还可以是通配符。在构造函数内部就会调用熟悉的 refresh 方法了。

深入 refresh 方法可以发现,在该方法中调用了 obtainFreshBeanFactory 方法来获取生成的 Bean,这个方法实际上是调用了抽象实现类 AbstractRefreshableApplicationContext 的 refreshBeanFactory 方法,该方法首先会先判断此时是否还有 beanFactory ,如果有的话会先销毁 beanFactory,然后再重新创建一个 BeanFactory(实际上是 DefaultListableBeanFactory 类型),最后会调用 loadBeanDefinitions 加载我们定义的 XMl 配置,方法使用的是 XmlBeanDefinitionReader 来读取的 XMl 配置,下面一起来深入的了解一下 Spring 生成 Bean 的过程。

2. 创建 Bean 的过程

首先我们看看 BeanFactory 类图,如下所示:

Bean 的整体创建流程如下所示:

3. 总结

本文简要的讲述了 Spring 创建 Bean 的主要流程,还有许多细节的地方需要深入研读源码才能了解,在这里先给自己一个小目标,后续会自己实现一个简易版本的 Spring(IOC、AOP),预知后事如何,请看下篇博文。。。

Spring 是如何造出一个 Bean 的的更多相关文章

  1. spring 在容器中一个bean依赖另一个bean 需要通过ref方式注入进去 通过构造器 或property

    spring  在容器中一个bean依赖另一个bean 需要通过ref方式注入进去 通过构造器 或property

  2. 在spring中如何生成一个bean (一个对象,比如jedis的连接池对象)【我】

    在spring中,要想生成一个单例对象(比如jedis的连接池对象) 方法1: 在 spring中用 bean 标签生成(反正就是让spring生成并管理单例的对象) 方法2: 把要生成的单例对象类, ...

  3. Spring的几种注入bean的方式

    在Spring容器中为一个bean配置依赖注入有三种方式: · 使用属性的setter方法注入  这是最常用的方式: · 使用构造器注入: · 使用Filed注入(用于注解方式).   使用属性的se ...

  4. 《Spring实战》系列之Bean的装配-Days02

    2.1 回顾 对于我第一天在bean的装配中写的,是一些基本的语法或者是Spring本身的一些规定,但是我没有对此进行深究.接下来就让我们仔细的讨论一下细节问题.和传统的类的定义和方法的调用做一些比较 ...

  5. 【spring set注入 注入集合】 使用set注入的方式注入List集合和Map集合/将一个bean注入另一个Bean

    Dao层代码: package com.it.dao; public interface SayHell { public void sayHello(); } Dao的Impl实现层: packag ...

  6. Spring学习笔记--声明一个简单的Bean

    spring依赖的maven dependencyhttp://mvnrepository.com/artifact/org.springframework 在pom.xml中添加如下依赖: < ...

  7. 品Spring:真没想到,三十步才能完成一个bean实例的创建

    在容器启动快完成时,会把所有的单例bean进行实例化,也可以叫做预先实例化. 这样做的好处之一是,可以及早地发现问题,及早的抛出异常,及早地解决掉. 本文就来看下整个的实例化过程.其实还是比较繁琐的. ...

  8. spring中如何向一个单例bean中注入非单例bean

    看到这个题目相信很多小伙伴都是懵懵的,平时我们的做法大都是下面的操作 @Component public class People{ @Autowired private Man man; } 这里如 ...

  9. Spring boot 将配置文件属性注入到一个bean中

    现在要做的就是将如下配置文件中的内容注入到一个bean 名为Properties中. Redis.properties配置文件中的内容如下: Properties java bean中代码如下,注意注 ...

  10. Spring IoC源码解析——Bean的创建和初始化

    Spring介绍 Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和AOP的容器框架,主要是针对JavaBean的生命周期进行管理的轻量级容器 ...

随机推荐

  1. KingbaseES V8R6 fillfactor 对于表的影响

    前言 fillfactor 表的填充因子是一个介于 10 和 100 之间的百分数.100是默认值.如果指定了较小的填充因子,INSERT操作仅按照填充因子指定的百分率填充表页.每个页上的剩余空间将用 ...

  2. 浅谈 KingbaseES 和 SQLServer 中的 instead of 触发器

    本文基于Kingbase和SqlServer的INSTEAD OF 触发器主要功能特点进行对比浅析,同时针对SqlServer 的INSTEAD OF 触发器提出了多种kingbase环境的等价代码方 ...

  3. archlinux修改btrfs文件系统大小出现ERROR: unable to retrieve fs info

    提权sudo就可以了 例: sudo btrfs filesystem resize max /

  4. C++设计模式 - 观察者模式(Observer)

    组件协作模式: 现代软件专业分工之后的第一个结果是"框架与应用程序的划分","组件协作"模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用 ...

  5. postman测试接口时的参数对应接口的两种情况

    第一种通过json字符串的情况去进行测试,最终将json字符串转成对应的对象 代码里面一定要加上@RequestBody注解,即使是一个字符串也需要加这个注解 第二种通过key-value的形式去加入 ...

  6. #贪心,构造#AT2266 [AGC008D] K-th K

    题目 给你一个长度为 \(N\) 的整数序列 \(X\),请判断是否存在一个满足下列条件的整数序列 \(a\),如果存在,请构造一种方案 条件如下: \(a\) 的长度为 \(N^2\),并且满足数字 ...

  7. ArkUI中的线程和看门狗机制

    一.前言 本文主要分析ArkUI中涉及的线程和看门狗机制. 二.ArkUI中的线程 应用Ability首次创建界面的流程大致如下: 说明: • AceContainer是一个容器类,由前端.任务执行器 ...

  8. C 语言中布尔值的用法和案例解析

    C语言中的布尔值 在编程中,您经常需要一种只能有两个值的数据类型,例如: 是/否 开/关 真/假 为此,C语言有一个 bool 数据类型,称为布尔值. 布尔变量 在C语言中,bool 类型不是内置数据 ...

  9. Python 条件和 if 语句

    Python支持来自数学的通常逻辑条件: 等于:a == b 不等于:a != b 小于:a < b 小于或等于:a <= b 大于:a > b 大于或等于:a >= b 这些 ...

  10. 【Learning eBPF-3】一个 eBPF 程序的深入剖析

    从这一章开始,我们先放下 BCC 框架,来看仅通过 C 语言如何实现一个 eBPF.如此一来,你会更加理解 BCC 所做的底层工作. 在这一章中,我们会讨论一个 eBPF 程序被执行的完整流程,如下图 ...