第03章:实现含构造函数的类实例化策略
约 686 字大约 2 分钟
本文内容
1. 设计
在第02章的设计中,虽然扩充了 Bean 容器的功能,将类的实例化交给了容器来处理,但是并 没有考虑到带有有参构造器的类的实例化,因此这章我们来进行改造,使其具备获取有参 Bean 的能力。
具体的,在 BeanFactory 中添加 Object getBean(String name, Object... args)
接口,即可在获取 Bean 的时候把构造函数的入参信息传递进去,从而能实例化有参数的 Bean 对象。
另外,我们使用两种方式来创建含有构造函数的 Bean 对象,分别是基于 JDK 的方法 DeclaredConstructor()
和基于 Cglib 的 enhancer.create()
方法。
2. 实现
得利于之前的设计,现在我们只需要添加一个 实例化策略模块,供实例化对象的时候使用即可。
目录结构更新如下:
类图如下:
- InstantiationStrategy:实例化策略接口,提供一个实例化方法
instantiate()
,入参包括 BeanDefinition、beanName、Class 的构造器、参数; - 提供两个 InstantiationStrategy 的实现类
SimpleInstantiationStrategy
和CglibSubclassingInstantiationStrategy
,分别是基于 JDK 和基于 Cglib 的方式来实例化对象; - 在 AbstractBeanFactory 类中,使用 重载 机制,新增一个带有入参的
getBean()
方法。由于重载的方法有 2 个,都需要进行获取 Bean,所以抽取一个doGetBean()
方法做具体的流程,供它们调用; - 在 AbstractAutowireCapableBeanFactory 类中,新增
createBeanInstance()
方法,用于 具体创建 Bean 实例:- 先通过
Class.getDeclaredConstructors()
获取 该 Class 的所有构造器; - 遍历所有构造器,将构造器的参数个数和类型与入参的参数做对比,选出需要的构造器;
- 将 选出的构造器作为参数传递给实例化策略中的方法,进行具体的实例化。
- 先通过
3. 测试
先给测试 bean 的 UserService 添加一个遍历 String name
,提供有参无参构造方法。
测试方法:
@Test
public void test_BeanFactory() {
// 1. 初始化 BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//beanFactory.setInstantiationStrategy(new SimpleInstantiationStrategy());
// 2. 注册 bean
BeanDefinition beanDefinition = new BeanDefinition(UserService.class);
beanFactory.registerBeanDefinition("userService", beanDefinition);
// 3. 带有参数的获取 bean
UserService userService = (UserService) beanFactory.getBean("userService", "AruNi");
userService.queryUserInfo();
// 输出:查询用户信息:AruNi
}
4. 流程
整体流程如下: