前言
使用 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
),预知后事如何,请看下篇博文。。。