本文用问答形式引导读者思考,以求理解spring ioc容器的设计思想
目录
-
IOC分析
- IOC是什么?
- 带来什么好处?
- 做什么工作?
- 是否是工厂模式的实例?
-
IOC设计实现
- IOC容器的工作?
- bean是什么?
- 它应该具备什么行为、功能?
- 这个getBean()方法是否需要参数?需要几个参数?什么类型的参数?
- getBean()方法返回值应该是什么类型?
- 设计bean工厂接口
- 如何告诉他创建Bean?
- 定义一个bean定义注册接口
- 接口中要定义什么方法?
- 注册的bean定义用什么区分?
- 创建什么Bean?
- bean定义的用途是什么?
- 获得类实例的方式有哪些?
- Bean工厂创建bean时需要知道哪些信息?
- 单例还是多例?
- bean定义应该提供哪些方法?
- 对象交由IOC容器管理后生命周期还有什么事情要做?
- Bean工厂实现
- 要具有什么功能?实现什么接口?
- 创建的bean用什么存放?
- getBean()方法要做什么?
- bean定义信息如何存放?
- bean定义是否可以重名?重名怎么办?
- 扩展默认工厂
- IOC容器的工作?
-
画完整UML类图
-
编写代码
-
测试
-
总结
IOC分析
1. IOC是什么?
IOC:inversion of control 控制反转,也称依赖倒置反转。
反转:依赖对象的获得权被反转了,由自己创建,变为从IOC容器获取,和自动注入。
2. 带来什么好处?
- 代码简洁,不需要自己new很多类了。
- 面向接口编程,使用者与具体类解耦,易扩展、替换实现者。
- 可作为基础模块,供支撑其他高级功能
3. 做什么工作?
负责创建、管理类实例,向使用者提供实例。
4. 是否是工厂模式的实例?
是的。IOC容器负责创建bean实例,也称为bean工厂。
IOC设计实现
1. IOC容器的工作?
- bean是什么?
组件,就是类的实例对象。
- IOC容器应该具备什么行为、功能?
负责创建、管理bean。他是一个bean工厂,负责对外提供bean实例,getBean()方法。
- 这个getBean()方法是否需要参数?需要几个参数?什么类型的参数?
根据类的名称获取相应的bean是最简单的,也符合简单工厂设计,所以只用一个String参数即可。
- getBean()方法返回值应该是什么类型?
返回的bean实例可能是所有的类型,所以应该是返回Object。
2.设计bean工厂接口
目前只需要提供一个getBean()的方法。
public interface BeanFactory {
public Object getBean(String beanName) throws Exception;
}
-
如何告诉它创建bean?
- 定义一个注册接口
- bean定义注册接口应该定义什么方法?
注册bean定义、获取bean定义、是否已包含bean定义。 - 注册的bean定义应该如何区分?
每个注册的bean定义有唯一的名称。 - 类图
-
创建什么bean?
- bean定义的用途是什么?
告诉bean工厂该如何创建某bean。 - 获得类实例的方式有哪些?
new 构造方法
- bean定义的用途是什么?
Student stu = new Student();
工厂方法
public class StudentFactory{
public static Student getStudent(){
return new Student();
}
}
静态工厂方法
public class StudentFactory{
public Student getStudent(){
return new Student();
}
}
3. bean工厂创建bean时需要知道哪些信息?
构造方法需要知道,类的全路径名(无参构造方法)。
静态工厂方法需要知道,工厂类名和方法名。
工厂方法需要知道,工厂bean名(可通过bean工厂获取工厂bean)和方法名。
4. 单例还是多例?
两种情况都有。
5. bean定义应该提供哪些方法?
- 获取bean的类名 getBeanClass():Class 有可能是bean的类名或工厂bean的类名
- 获取工厂方法名 getFactoryMethodName(): String
- 获取工厂bean名 getFactoryBeanName():String
- 是否单例等方法 getScope():String 、isSingleton():boolean、isPrototype():boolean
6. 对象交由IOC容器管理后生命周期还有什么事情要做?
可能要对bean实例化后进行初始化方法、销毁前进行的销毁方法
故应定义getInitMethodName() 、getDestroyMethodName.
5. beanFactory实现
- 要实现什么功能?实现什么接口?
实现bean工厂和bean定义注册接口
- 创建的bean用什么存放,以便获取?
map
- getBean()要做哪些事?
创建bean实例,进行初始化等方法。
- bean定义信息用什么存放?
map
- bean定义是否可以重名,重名怎么办?
可以先简单设计为不可重名,重名即抛出异常。
- 扩展默认bean工厂
可以提前将单例bean初始化。
完整uml类图
编写代码
详见附件完整项目。
测试
- 测试无参构造器创建bean
public class PreBuildBeanFactoryTest {
static PreBuildBeanFactory bf = new PreBuildBeanFactory();
@Test
public void testConstrutor() throws Exception {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(ABean.class);
bd.setInitMethodName("init");
bd.setDestroyName("destroy");
bf.registry("abean", bd);
bf.preInstantiateSingletons();
ABean abean = (ABean)bf.getBean("abean");
abean.doSomthing();
}
- 测试静态工厂方法创建bean
@Test
public void testStaticFactoryMethod() throws Exception {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(ABeanFactory.class);
bd.setFactoryMethodName("getABean");
bf.registry("abean", bd);
bf.preInstantiateSingletons();
ABean abean = (ABean)bf.getBean("abean");
abean.doSomthing();
}
- 测试工厂方法创建bean
@Test
public void testFactoryMethod() throws Exception {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setFactoryMethodName("getABean2");
bd.setFactoryBeanName("aBeanFactory");
bf.registry("abean", bd);
bd = new GenericBeanDefinition();
bd.setBeanClass(ABeanFactory.class);
bf.registry("aBeanFactory", bd);
bf.preInstantiateSingletons();
ABean abean = (ABean)bf.getBean("abean");
abean.doSomthing();
}
总结
本文是参考spring设计架构进行简化的方式来设计beanFactory,简化版的IOC容器,实现bean定义注册及获取功能,后续会继续实现DI、AOP等功能。