1. 创建简单的Bean容器
1.1 Spring的Bean容器是什么?
自从我们用上了Spring ,我们再也不用new 对象了,创建对象实例的任务都交给了Spring容器。很显然Spring容器是一个承载对象的容器,它用来保存各式各样的Bean、管理Bean的配置和生命周期。
如果一个Bean对象交给Spring容器管理,那么这个Bean对象就应该以类似零件的方式被拆解后存放到Bean的定义中,这样相当于一种把对象解耦的操作,可以让Spring更加容易的管理。其实一个Bean被定义存放后,再由Spring进行统一装配,这个过程包括Bean的初始化、属性填充等,最终我们就可以完整的使用一个Bean实例化后的对象了。
那么我们接下来就可以动手实践一下怎么定义一个Spring容器,实现三个功能:定义Bean对象、存放Bean对象、获取Bean对象。
1.2 设计Bean容器
其实Java中的容器有很多,List、Set、Map都可以称作容器,或者说容器是存放数据的一种数据结构。但是很显然Spring容器需要用到的是HashMap。
说白了这个Bean容器就是一个HashMap,Bean的名字就是它的hashMap的key,Bean的对象信息就是HashMap的值。那么我们该如何定义Bean对象嘞?
其实我们查阅Spring源码会经常看到BeanDefinition这个类,这个类有很多属性来描述Bean对象:
-
beanClass:表示一个bean的类型,比如UserService.class、OrderService.class,Spring在创建Bean的过程中会根据此属性来实例化得到对象。 -
scope:表示一个bean的作用域,比如:scope等于singleton,该bean就是一个单例Bean; scope等于prototype,该bean就是一个原型Bean。 -
isLazy:表示一个bean是不是需要懒加载,原型bean的isLazy属性不起作用,懒加载的单例bean,会在第一次getBean的时候生成该bean,非懒加载的单例bean,则会在Spring启动过程中直接生成好。 -
dependsOn:表示一个bean在创建之前所依赖的其他bean,在一个bean创建之前,它所依赖的这些bean得先全部创建好。 -
primary:表示一个bean是主bean,在Spring中一个类型可以有多个bean对象,在进行依赖注入时,如果根据类型找到了多个bean,此时会判断这些bean中是否存在一个主bean,如果存在,则直接将这个bean注入给属性。 -
initMethodName:表示一个bean的初始化方法,一个bean的生命周期过程中有一个步骤叫初始化,Spring会在这个步骤中去调用bean的初始化方法,初始化逻辑由程序员自己控制,表示程序员可以自定义逻辑对bean进行加工。
具体可以看看这篇文章:https://blog.csdn.net/mashaokang1314/article/details/108054547?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1-108054547-blog-102633067.pc_relevant_multi_platform_featuressortv2dupreplace&spm=1001.2101.3001.4242.2&utm_relevant_index=4
Bean对象定义完了,就是注册和获取了,Bean的注册和获取其实就是对Spring容器做增加和查询操作。
1.3 实现Bean容器
我们的实现并不是完全遵循Spring官方实现,而是自己做的简易实现。主要实现了两个类:BeanFactory
和BeanDefinition。
public class BeanDefinition {
private Object bean;
public BeanDefinition(Object bean) {
this.bean = bean;
}
public Object getBean() {
return bean;
}
}
目前的 Bean 定义中,只有一个 Object 用于存放 Bean 对象。如果感兴趣可以参
考 Spring 源码中这个类的信息,名称都是一样的。不过在后面陆续的实现中会逐步完善 BeanDefinition 相关属性的填充,例如:SCOPE_SINGLETON、SCOPE_PROTOTYPE、ROLE_APPLICATION、
ROLE_SUPPORT、ROLE_INFRASTRUCTURE 以及 Bean Class 信息。
public class BeanFactory {
private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
public Object getBean(String name){
return beanDefinitionMap.get(name);
}
public void registerBeanDefinition(String name, BeanDefinition beanDefinition){
beanDefinitionMap.put(name, beanDefinition);
}
}
目前的 BeanFactory 仍然是非常简化的实现,但这种简化的实现内容也是整个 Spring 容器中关于 Bean 使用的最终体现结果,只不过实现过程只展示出基本的 核心原理。在后续的补充实现中,这个会不断变得庞大
2. 实现Bean的定义、注册、获取
之前我们依照Spring容器的概念,实现了一个精简的BeanFactory,但是它存在很多问题,先讲两个:
-
我们需要将Bean的创建交给容器,而不是在调动的时候传递一个实例好的Bean过去。这就需要我们保证Spring容器在注册Bean时只注册一个类信息,而不会直接把实例化信息注册到Spring容器中。 -
此外我们还要考虑单例对象,在单例对象的二次获取时Spring容器是可以从内存中拿到它的
那么接下来我们就按照这两个需求来写一下代码实现它。
其实这里的核心实现类也就是真正的BeanFactory要做的就两件事:注册BeanDefinition、获取BeanDefinition,创建Bean、获取Bean.
由于我们不希望将实例信息放入Bean容器,而是希望将类信息放入容器,那么BeanDefinition类就要改动了,我们要将它的属性类型改为Class。
public class BeanDefinition {
private Class beanClass;
public BeanDefinition(Class beanClass) {
this.beanClass = beanClass;
}
public Class getBean() {
return this.beanClass;
}
public void setBeanClass(Class beanClass){
this.beanClass = beanClass;
}
}
第一个接口当然是BeanDefinition的注册接口:
public interface BeanDefinitionRegistry {
/**
* 向注册表中注册 BeanDefinition
*
* @param beanName
* @param beanDefinition
*/
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
}
当然BeanFactory也要改造成一个接口,未来会有各种各样的实现类去实现它,这里我们抽出一个最通用的方法getBean
public interface BeanFactory {
Object getBean(String name) throws BeansException;
}
此外我们还有新建一个单例Bean的注册接口SingletonBeanRegistry。
public interface SingletonBeanRegistry {
Object getSingleton(String beanName);
}
既然我们有了单例注册表这个接口,那么就需要写一个类来实现单例注册和获取:
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
private final Map<String, Object> singletonObjects = new HashMap<>();
@Override
public Object getSingleton(String beanName) {
return singletonObjects.get(beanName);
}
protected void addSingleton(String beanName, Object singletonObject) {
singletonObjects.put(beanName, singletonObject);
}
}
「这个 Bean 工厂接口由抽象类 AbstractBeanFactory 实现。这样使用模板模式的设计方式,可以统一收口通用核 心方法的调用逻辑和标准定义,也就很好的控制了后续的实现者不用关心调用逻 辑,按照统一方式执行。那么类的继承者只需要关心具体方法的逻辑实现即可。」
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
@Override
public Object getBean(String name) throws BeansException {
Object bean = getSingleton(name);
if (bean != null) {
return bean;
}
BeanDefinition beanDefinition = getBeanDefinition(name);
return createBean(name, beanDefinition);
}
protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException;
}
那么在继承抽象类 AbstractBeanFactory 后的 「AbstractAutowireCapableBeanFactory」 就可以实现相应的抽象方法了,因为 「AbstractAutowireCapableBeanFactory」 本身也是一个抽象类,所以它只会实现属于自己的抽象方法,其他抽象方法由继承 「AbstractAutowireCapableBeanFactory」 的类实现。这里就体现了类实现过程中的各司其职,你只需要关心属于你的内容,不是你的内容,不要参与。这里的AbstractAutowireCapableBeanFactory实现了createBean,getBeanDefinition不是它所关心的。
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory{
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException {
Object bean;
try {
bean = beanDefinition.getBeanClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new BeansException("Instantiation of bean failed", e);
}
addSingleton(beanName, bean);
return bean;
}
}
最后的DefaultListableBeanFactory才是最终的核心实现类,它还需要继承AbstractAutowireCapableBeanFactory抽象类实现BeanDefinitionRegistry接口,完成两件事情那就是getBeanDefinition和registerBeanDefinition,我们用一个Map<String, BeanDefinition> beanDefinitionMap 来存储他们。
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry{
private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
@Override
protected BeanDefinition getBeanDefinition(String beanName) throws BeansException {
return this.beanDefinitionMap.get(beanName);
}
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
this.beanDefinitionMap.put(beanName, beanDefinition);
}
}
3. 总结
这里的AbstractBeanFactory充分体现了模板模式的设计方式
-
AbstractBeanFactory 首先继承了 DefaultSingletonBeanRegistry,也就具备了使用单例注册类方法。 -
接下来很重要的一点是关于接口 BeanFactory 的实现,在方法 getBean 的实现过程中可以看到,主要是对单例 Bean 对象的获取以及在获取不到时需要拿到Bean的定义做相应 Bean 实例化操作。那么getBean 并没有自身的去实现这些方法,而是只定义了调用过程以及提供了抽象方法,由实现此抽象类的其他类做相应实现。 -
后续继承抽象类 AbstractBeanFactory 的类有两个,包括:AbstractAutowireCapableBeanFactory、DefaultListableBeanFactory,这两个类分别做了相应的实现处理。
BeanDefinitionRegistry接口定义了beanDefinition的注册,AbstractBeanFactory抽象类定义了beanDefinition的获取,都集中在 DefaultListableBeanFactory 中的 beanDefinitionMap 里,套路真的很深。
原文始发于微信公众号(Java之禅):Bean的定义、注册、获取
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/161323.html