回顾step1
step1我们实现了一个非常单纯的Bean容器—BeanFactory,里面提供方法registerBeanDefinition(),getBean(),并且维护一个ConcurrentHashMap的实例,用于存储Bean对象
这个容器提供的Bean的注册、获取功能,但对用户而言,用户却需要自行创建、自行注册、同时自行提取;这与我们最初的设想:将创建对象的控制权从用户手中夺回,因此我们应该让容器自行创建对象才是,那么如何实现呢?
掌控对象控制权
我们知道将创建对象和业务功能解耦,可以使用工厂设计模式或者抽象工厂,但是由于对象的类型不确定,我们不可能在未知对象类型的情况下new出对象,所以说用户必须告诉我们的工厂我们该实例化哪个类型?用户不能自己创建,又必须告诉工厂创建什么,大家想到了什么?对,就是反射!通过反射获取Class对象就可以创建实例对象,用户只要告诉我么类型的全类名就可以了;所以现在用户和容器的关系应该是下面这样的:
而原来容器维护的是实例对象,现在维护的应该是Class对象,这样容器就能真正掌握对象的创建权力,这样什么时候需要对象,容器就可以为其创建,或者单例对象
所以我们的BeanDefinition看起来应该是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class BeanDefinition{
private Class beanClass;
public BeanDefinition(){}
public BeanDefinition(Class beanClass){
this.beanClass = beanClass;
}
public void setBeanClass(Class beanClass){
this.beanClass = beanClass;
}
public Class getBeanClass(Class beanClass){
return this.beanClass
}
}
拆分容器
在step1中我们总结过Spring Ioc容器的主要工作,包括Bean定义、Bean注册、Bean初始化、依赖注入;而现在这些功能都被耦合在同一个BeanFactory类中,这样不便于后期扩展,为了提供更好的可扩展性,我们应该将其分解,一个类做一件事;经分析我们发现,容器的真正起作用时是当我们需要从中获取Bean对象的时候,那么容器需要能够自己创建Bean对象,并且暂存起来,那么我们看下BeanFactory的继承链是如何的:
然后我们在以getBean为目标,看看它是如何执行的:
可见因为getBean的需要,诞生了getBeanDefinition和createBean方法,并且我们发现这次的容器增加了单例对象缓存,使得不是每次getBean都重新创建对象,AbstractBeanFactory确定了getBean()的执行框架,使得该容器会默认返回对象的单例,同样单例缓存功能也实现在另一个类DefaultSingletonRegistry中,这样每个功能之间保持独立,类与类之间实现解耦,整个框架更容易扩展
完整的类图
为什么无论是BeanDefinition容器还是singletonObject容器都要用final修饰呢?
因为这样让属性更安全,因为被final修饰后,容器就很难被替换,也就是说属性只能初始化一次;
当前容器存在的问题
先看一段代码,这段代码测试单例缓存是否成功:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class DefaultSingletonBeanRegistryTest {
@Test
public void testGetSingleton() {
// 我的bean容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 创建我的BeanDefinition
BeanDefinition beanDefinition = new BeanDefinition(UserService.class);
//BeanDefinition注册进容器
beanFactory.registerBeanDefinition("userService", beanDefinition);
//获取Bean对象
UserService userService = (UserService)beanFactory.getBean("userService");
//再次获取Bean对象
Object anotherUserService = beanFactory.getBean("userService");
// 判断两者是否为同一对象
System.out.println(userService == anotherUserService);
}
}
问题:
1.很明显,相较于step1我们的容器确实能够自己创建对象,并且还能进行单例缓存,但是对于用户来说,依然需要手动注册Definition,也就是说还是要由程序主动管理对象的生成 2.每次取出Bean需要用户显式进行强转,有没有如泛型那样容器帮我们自动强转的方法 3.容器创建Bean,使用反射的newInstance()方法,而它的底层实际上调用的是无参构造函数,所以如果面对这样的一个类:
1
2
3
4
5
6
7
8
9
10
11
public class UserService {
private String name;
public UserService(String name) {
this.name = name;
}
public void queryUserInfo(){
System.out.println("查询用户信息");
}
}
就会报错,因为它压根就没有无参构造函数
那么如何解决这些问题呢?Spring-step3继续