手写Spring2(实现 Bean 的定义、注册、获取)
创始人
2024-03-25 05:11:04
0

文章目录

  • 前言
  • 本章目标
  • 一、实现
    • 1、项目结构
    • 2、BeanFactory-bean工厂
    • 3、BeanDefinition -bean定义
    • 4、单例注册接口定义和实现-SingletonBeanRegistry 、DefaultSingletonBeanRegistry
    • 5、AbstractBeanFactory-抽象bean工厂类(定义模板方法)
    • 6、AbstractAutowireCapableBeanFactory-实例化Bean
    • 7、DefaultListableBeanFactory-bean工厂核心实现类
  • 五、测试
    • 1、准备的测试类
    • 2、测试用例
    • 3、测试结果
  • 总结


前言

继续完善 Spring Bean 容器框架的功能开发


本章目标

1、bean的创建交给容器

2、getBean采用模板方法设计模式,指定调用过程和标准定义,控制了后续的实现者不用关心调用逻辑,按照统一方式执行

3、容器框架的类结构优化,方便后续功能的扩展


一、实现

1、项目结构

├─src
│  ├─main
│  │  ├─java
│  │  │  └─cn
│  │  │      └─ljc
│  │  │          └─springframework
│  │  │              └─beans
│  │  │                  │  BeansException.java
│  │  │                  │
│  │  │                  └─factory
│  │  │                      │  BeanFactory.java
│  │  │                      │
│  │  │                      ├─config
│  │  │                      │      BeanDefinition.java
│  │  │                      │      SingletonBeanRegistry.java
│  │  │                      │
│  │  │                      └─support
│  │  │                              AbstractAutowireCapableBeanFactory.java
│  │  │                              AbstractBeanFactory.java
│  │  │                              BeanDefinitionRegistry.java
│  │  │                              DefaultListableBeanFactory.java
│  │  │                              DefaultSingletonBeanRegistry.java
│  │  │
│  │  └─resources
│  └─test
│      └─java
│          └─springframework
│              └─test
│                  │  ApiTest.java
│                  │
│                  └─bean
│                          UserService.java

在这里插入图片描述

2、BeanFactory-bean工厂

/*** @desc Bean工厂* @Author: ljc* @Date: 2022/11/28 10:36*/
public interface BeanFactory {Object getBean(String name) throws BeansException;}

上一章的BeanFactory 是一个类,这里把他抽象了,变成一个接口,方便扩展


3、BeanDefinition -bean定义

/*** @desc Bean定义* @Author: ljc* @Date: 2022/11/28 10:35*/
public class BeanDefinition {private Class beanClass;public BeanDefinition(Class beanClass) {this.beanClass = beanClass;}public Class getBeanClass() {return beanClass;}public void setBeanClass(Class beanClass) {this.beanClass = beanClass;}
}

上一章Object beanClass 改为Class beanClass,bean的实例化操作可以放到容器中去处理


4、单例注册接口定义和实现-SingletonBeanRegistry 、DefaultSingletonBeanRegistry

单例注册bean的接口

/*** @desc 单例注册接口定义* @Author: ljc* @Date: 2022/11/30 17:27*/
public interface SingletonBeanRegistry {Object getSingleton(String beanName);}

提供了一个获取单例bean的接口


单例注册bean的实现

/*** @desc 单例注册接口的实现类* @Author: ljc* @Date: 2022/11/30 17:28*/
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {/*** @desc: 单例池* @author: ljc* @date: 2022/12/7 10:57* @param:* @return:**/private Map singletonObjects = new HashMap<>();/*** @desc: 获取单例bean* @author: ljc* @date: 2022/12/7 10:57* @param: [beanName]* @return: java.lang.Object**/@Overridepublic Object getSingleton(String beanName) {return singletonObjects.get(beanName);}/*** @desc: 入单例池* @author: ljc* @date: 2022/12/7 10:56* @param: [beanName, singletonObject]* @return: void**/protected void addSingleton(String beanName,Object singletonObject){singletonObjects.put(beanName,singletonObject);}
}

实现了获取单例bean的接口,并且定义了一个对象单例池,以及提供了添加对象到单例池的保护方法

保证单一职责,只负责处理单例Bean的处理


5、AbstractBeanFactory-抽象bean工厂类(定义模板方法)

/*** @desc 抽象bean工厂类* @Author: ljc* @Date: 2022/12/7 11:10*/
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {@Overridepublic 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;}

新增了2个抽象方法,getBeanDefinition和createBean;

AbstractBeanFactory 继承于DefaultSingletonBeanRegistry,获得了单例注册bean的能力,并且实现了bean工厂的getBean方法

在getBean里面只定义了调用过程(模板模式),并没有自己去实现,让实现此抽象的类去完成。

PS:
这样使用模板模式 (opens new window)的设计方式,可以统一收口通用核心方法的调用逻辑和标准定义,也就很好的控制了后续的实现者不用关心调用逻辑,按照统一方式执行。那么类的继承者只需要关心具体方法的逻辑实现即可


6、AbstractAutowireCapableBeanFactory-实例化Bean

/*** @desc 实例化Bean类* @Author: ljc* @Date: 2022/12/7 13:06*/
public abstract class  AbstractAutowireCapableBeanFactory extends AbstractBeanFactory{@Overrideprotected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException {Object bean = null;try {bean = beanDefinition.getBeanClass().newInstance();} catch (InstantiationException | IllegalAccessException e) {throw new BeansException("Instantiation of bean failed", e);}addSingleton(beanName,bean);return bean;}
}

AbstractAutowireCapableBeanFactory 本身也是一个抽象类

它只会实现属于自己的抽象方法,其他抽象方法由继承AbstractAutowireCapableBeanFactory 的类实现。

这里会有一个问题,如果是带参数的构造方法如何处理?(在源码里,其实是有一个寻找构造方法的判断处理)


7、DefaultListableBeanFactory-bean工厂核心实现类

/*** @desc bena工厂核心实现类* @Author: ljc* @Date: 2022/12/7 13:33*/
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry{// bean定义的缓存private final Map beanDefinitionMap = new HashMap<>();@Overrideprotected BeanDefinition getBeanDefinition(String beanName) throws BeansException {BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);if(beanDefinition ==null) throw new BeansException("No bean named " + beanName + " is defined");return beanDefinition;}@Overridepublic void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeansException {beanDefinitionMap.put(beanName, beanDefinition);}
}

继承于AbstractAutowireCapableBeanFactory ,拥有了创建bean、获取bean的能力

并且实现了BeanDefinitionRegistry接口的,内部实现了egisterBeanDefinition(实现了Bean定义


五、测试

1、准备的测试类

/*** @desc 用户服务类* @Author: ljc* @Date: 2022/11/28 10:56*/
public class UserService {public void queryUserInfo(){System.out.println("查询用户信息");}}

2、测试用例

/*** @desc 测试* @Author: ljc* @Date: 2022/11/28 10:57*/
public class ApiTest {@Testpublic void test_BeanFactory() {// 1.初始化 BeanFactoryDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// 2.注册 beanBeanDefinition beanDefinition = new BeanDefinition(UserService.class);beanFactory.registerBeanDefinition("userService", beanDefinition);// 3.第一次获取 beanUserService userService = (UserService) beanFactory.getBean("userService");userService.queryUserInfo();// 4.第二次获取 bean from SingletonUserService userService_singleton = (UserService) beanFactory.getBean("userService");userService_singleton.queryUserInfo();System.out.println(userService);System.out.println(userService_singleton);}}

测试案例主要包含了 初始化bean工厂、注册bean、获取bean。

上一章的测试用例,可以看到是通过new userService()来定义bean,现在是把UserService的class传给bean定义。

调用2次获取bean,主要是用于测试第二次获取时,是否从缓存里获取,按上述代码,结果是肯定的!

3、测试结果

查询用户信息
查询用户信息
springframework.test.bean.UserService@504bae78
springframework.test.bean.UserService@504bae78Process finished with exit code 0

可以看到打印的对象是同一个


总结

可以看到本章节,增加了很多类和接口,为什么要设计成这样?

基于接口、抽象编程,便于扩展

松耦合,让每个类只承担自己职责的那部分,尽可能保证单一职责

相关内容

热门资讯

【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
修复 爱普生 EPSON L4... L4151 L4153 L4156 L4158 L4163 L4165 L4166 L4168 L4...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
【前端】‘??‘与‘||‘有什... 0 问题 经常写const data = res.data.a ?? ''或者const d...
ChatGPT 怎么用最新详细... ChatGPT 以其强大的信息整合和对话能力惊艳了全球,在自然语言处理上面表现出了惊人...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...