目标
在上一章节 《小试牛刀,实现一个简单的Bean容器》 我们初步依照 Spring Bean 容器的概念,实现了一个粗糙版本的代码实现。那么本章节我们需要结合已实现的 Spring Bean 容器进行功能完善,实现 Bean 容器关于 Bean 对象的注册和获取。
这一次我们把 Bean 的创建交给容器,而不是我们在调用时候传递一个实例化好的 Bean 对象,另外还需要考虑单例对象,在对象的二次获取时是可以从内存中获取对象的。此外不仅要实现功能还需要完善基础容器框架的类结构体,否则将来就很难扩容进去其他的功能了。
设计
鉴于本章节的案例目标,我们需要将 Spring Bean 容器完善起来,首先非常重要的一点是在 Bean 注册的时候只注册一个类信息,而不会直接把实例化信息注册到 Spring 容器中。那么就需要修改 BeanDefinition 中的属性 Object 为 Class,接下来在需要做的就是在获取 Bean 对象时需要处理 Bean 对象的实例化操作以及判断当前单例对象在容器中是否已经缓存起来了。
- 首先我们需要定义 BeanFactory 这样一个 Bean 工厂,提供 Bean 的获取方法 getBean(String name),之后这个 Bean 工厂接口由抽象类 AbstractBeanFactory 实现。这样使用 模板模式的设计方式,可以统一收口通用核心方法的调用逻辑和标准定义,也就很好的控制了后续的实现者不用关心调用逻辑,按照统一方式执行。那么类的继承者只需要关心具体方法的逻辑实现即可。
- 那么在继承抽象类 AbstractBeanFactory 后的 AbstractAutowireCapableBeanFactory 就可以实现相应的抽象方法了,因为 AbstractAutowireCapableBeanFactory 本身也是一个 抽象类,所以它只会实现属于自己的抽象方法,其他抽象方法由继承 AbstractAutowireCapableBeanFactory 的类实现。这里就体现了类实现过程中的各司其职,你只需要关心属于你的内容,不是你的内容,不要参与。
- 另外这里还有块非常重要的知识点,就是关于单例 SingletonBeanRegistry 的接口定义实现,而 DefaultSingletonBeanRegistry 对接口实现后,会被抽象类 AbstractBeanFactory 继承。现在 AbstractBeanFactory 就是一个非常完整且强大的抽象类了,也能非常好的体现出它对模板模式的抽象定义。
实现
工程结构
从类关系图来看,其实已经具备了一定的设计复杂性,这些复杂的类关系设计在各个接口定义和实现以及在抽象类继承中都有所体现,例如:
- BeanFactory 的定义由 AbstractBeanFactory 抽象类实现接口的 getBean 方法
- 而 AbstractBeanFactory 又继承了实现了 SingletonBeanRegistry 的DefaultSingletonBeanRegistry 类。这样 AbstractBeanFactory 抽象类就具备了单例 Bean 的注册功能。
- AbstractBeanFactory 中又定义了两个抽象方法:getBeanDefinition(String beanName)、createBean(String beanName, BeanDefinition beanDefinition) ,而这两个抽象方法分别由 DefaultListableBeanFactory、AbstractAutowireCapableBeanFactory 实现。
- 最终 DefaultListableBeanFactory 还会继承抽象类 AbstractAutowireCapableBeanFactory 也就可以调用抽象类中的 createBean 方法了。
综上这一部分的类关系和实现过程还是会有一些复杂的,因为所有的实现都以 职责划分、共性分离以及调用关系定义 为标准搭建的类关系。
BeanFactory工厂
package com;
/**
* Bean工厂
*/
public interface BeanFactory {
Object getBean(String name) throws Exception;
}
BeanDefinition 定义
package com;
/**
* BeanDefinition定义
*/
public class BeanDefinition {
private Class beanClass;
public BeanDefinition(Class beanClass) {
this.beanClass = beanClass;
}
public Class getBeanClass() {
return beanClass;
}
}
- 在 Bean 定义类中已经把上一章节中的 Object bean 替换为 Class,这样就可以把 Bean 的实例化操作放到容器中处理了。如果你有仔细阅读过上一章并做了相应的测试,那么你会发现 Bean 的实例化操作是放在初始化调用阶段传递给 BeanDefinition 构造函数的。
向注册表中注册BeanDefinition
package com;
public interface BeanDefinitionRegistry {
void registerBeanDefinition(String beanName,BeanDefinition beanDefinition);
}
单例注册接口定义和实现
package com;
/**
* 单例注册接口定义和实现
*/
public interface SingletonBeanRegistry {
Object getSingleton(String beanName);
}
- 这个类比较简单主要是定义了一个获取单例对象的接口。
package com;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
private Map<String,Object> singletonObjects = new ConcurrentHashMap<>(256);
@Override
public Object getSingleton(String beanName) {
return singletonObjects.get(beanName);
}
public void addSingleton(String beanName,Object singletonObject){
singletonObjects.put(beanName,singletonObject);
}
}
- 在 DefaultSingletonBeanRegistry 中主要实现 getSingleton 方法,同时实现了一个受保护的 addSingleton 方法,这个方法可以被继承此类的其他类调用。包括:AbstractBeanFactory 以及继承的 DefaultListableBeanFactory 调用。
抽象类定义模板方法(AbstractBeanFactory)
package com;
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
@Override
public Object getBean(String name) throws Exception {
Object bean = getSingleton(name);
if(bean != null){
return bean;
}
BeanDefinition beanDefinition = getBeanDefinition(name);
return createBean(name,beanDefinition);
}
protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws Exception;
protected abstract BeanDefinition getBeanDefinition(String beanName) throws Exception;
}
- AbstractBeanFactory 首先继承了 DefaultSingletonBeanRegistry,也就具备了使用单例注册类方法。
- 接下来很重要的一点是关于接口 BeanFactory 的实现,在方法 getBean 的实现过程中可以看到,主要是对单例 Bean 对象的获取以及在获取不到时需要拿到 Bean 的定义做相应 Bean 实例化操作。那么 getBean 并没有自身的去实现这些方法,而是只定义了调用过程以及提供了抽象方法,由实现此抽象类的其他类做相应实现。
- 后续继承抽象类 AbstractBeanFactory 的类有两个,包括:AbstractAutowireCapableBeanFactory、DefaultListableBeanFactory,这两个类分别做了相应的实现处理,接着往下看。
实例化Bean类(AbstractAutowireCapableBeanFactory)
package com;
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
@Override
protected Object createBean(String name, BeanDefinition beanDefinition) throws Exception {
Object bean = null;
try {
bean = beanDefinition.getBeanClass().newInstance();
}catch (Exception e){
throw new RuntimeException("Instantiation of bean failed");
}
addSingleton(name,bean);
return bean;
}
}
- 在 AbstractAutowireCapableBeanFactory 类中实现了 Bean 的实例化操作 newInstance,其实这块会埋下一个坑,有构造函数入参的对象怎么处理?可以提前思考
- 在处理完 Bean 对象的实例化后,直接调用 addSingleton 方法存放到单例对象的缓存中去。
核心类实现(DefaultListableBeanFactory)
package com;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry {
private Map<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
beanDefinitionMap.put(beanName,beanDefinition);
}
@Override
protected BeanDefinition getBeanDefinition(String beanName) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if(beanDefinition == null){
throw new RuntimeException("No bean named '" + beanName + "' is defined");
}
return beanDefinition;
}
}
- DefaultListableBeanFactory 在 Spring 源码中也是一个非常核心的类,在我们目前的实现中也是逐步贴近于源码,与源码类名保持一致。
- DefaultListableBeanFactory 继承了 AbstractAutowireCapableBeanFactory 类,也就具备了接口 BeanFactory 和 AbstractBeanFactory 等一连串的功能实现。所以有时候你会看到一些类的强转,调用某些方法,也是因为你强转的类实现接口或继承了某些类。
- 除此之外这个类还实现了接口 BeanDefinitionRegistry 中的 registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 方法,当然你还会看到一个 getBeanDefinition 的实现,这个方法我们文中提到过它是抽象类 AbstractBeanFactory 中定义的抽象方法。现在注册Bean定义与获取Bean定义就可以同时使用了,是不感觉这个套路还蛮深的。接口定义了注册,抽象类定义了获取,都集中在 DefaultListableBeanFactory 中的 beanDefinitionMap 里。
测试
package com;
public class UserService {
public void queryUserInfo(){
System.out.println("查询用户信息");
}
}
package com;
import org.junit.Test;
public class UTest
{
@Test
public void test_BeanFactory() throws Exception {
//1.初始化 BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//2.注冊 Bean
BeanDefinition beanDefinition = new BeanDefinition(UserService.class);
beanFactory.registerBeanDefinition("userService",beanDefinition);
//3.获取 Bean
UserService userService = (UserService)beanFactory.getBean("userService");
userService.queryUserInfo();
UserService userService1 = (UserService)beanFactory.getBean("userService");
userService1.queryUserInfo();
System.out.println("是否同一个对象:"+(userService==userService1));
}
}
是同一个对象说明缓存起作用了。