从零实现一个简单的Spring Bean容器的代码案例
作者:Cosolar 发布时间:2022-07-24 11:42:16
Spring是一个非常流行的Java Web开发框架,它提供了强大的依赖注入、面向切面编程、声明式事务管理等功能,为开发者提供了高效、快速地构建 Web 应用程序的工具。
最近在学习Spring这个框架源码时,我明白我们不仅需要掌握其基本使用方法,还应该深入了解其内部实现原理。本博文将会带领大家一步一步地实现一个简单的 Spring Bean 容器,涉及到容器接口和实现、Bean的定义和注册、Bean的依赖注入、Bean的生命周期管理等多个方面,旨在帮助读者更加深入地理解Spring内部的运行机制。
如果你想更加深入地了解Spring框架的内部原理,或者想从零开始手动实现一个简单的Spring Bean容器的话,欢迎以后一起学习探讨,共同进步!
在这篇文章中,放松心情,提高兴趣,咱们将一步一步地构建一个简单的Spring Bean容器,包括如下内容:
容器接口和实现
Bean 的定义和注册
Bean 的依赖注入
Bean 的生命周期管理
1. 容器接口和实现
我们先定义一个容器接口 BeanFactory
,包含三个方法:获取 Bean、注册 Bean、是否包含 Bean。
public interface BeanFactory {
Object getBean(String name);
void registerBean(String name, Object bean);
boolean containsBean(String name);
}
然后,我们可以编写一个简单的实现 SimpleBeanFactory
。这个实现采用了一个 Map<String, Object>
来存储 Bean,其中键为 Bean 名称,值为 Bean 实例。
public class SimpleBeanFactory implements BeanFactory {
private final Map<String, Object> beans = new HashMap<>();
@Override
public Object getBean(String name) {
return beans.get(name);
}
@Override
public void registerBean(String name, Object bean) {
beans.put(name, bean);
}
@Override
public boolean containsBean(String name) {
return beans.containsKey(name);
}
}
2. Bean 的定义和注册
在 Spring 中,Bean 是通过 XML 或注解来定义的。但是我们这里为了简化,还是采用常规的方式来定义和注册 Bean。
我们定义一个 BeanDefinition
类,用于保存 Bean 的定义信息。其中包含了 Bean 的名称、类型、构造函数参数、属性等。
public class BeanDefinition {
private final Class<?> type;
private final Object[] constructorArgs;
private final Map<String, Object> properties = new HashMap<>();
public BeanDefinition(Class<?> type, Object[] constructorArgs) {
this.type = type;
this.constructorArgs = constructorArgs;
}
public void setProperty(String name, Object value) {
properties.put(name, value);
}
public Class<?> getType() {
return type;
}
public Object[] getConstructorArgs() {
return constructorArgs;
}
public Map<String, Object> getProperties() {
return properties;
}
}
我们可以编写一个简单的类 BeanDefinitionReader
,用于从配置文件中读取 Bean 定义信息,并将其转换成 BeanDefinition
对象。
public class BeanDefinitionReader {
private final ResourceLoader resourceLoader;
public BeanDefinitionReader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public List<BeanDefinition> readBeanDefinitions(String location) throws Exception {
InputStream inputStream = resourceLoader.getResource(location).getInputStream();
Properties props = new Properties();
props.load(inputStream);
List<BeanDefinition> result = new ArrayList<>();
for (Map.Entry<Object, Object> entry : props.entrySet()) {
String name = (String) entry.getKey();
String[] args = ((String) entry.getValue()).split(",");
Class<?> type = Class.forName(args[0]);
Object[] constructorArgs = new Object[args.length - 1];
for (int i = 1; i < args.length; i++) {
constructorArgs[i - 1] = args[i];
}
BeanDefinition beanDefinition = new BeanDefinition(type, constructorArgs);
result.add(beanDefinition);
}
return result;
}
}
我们可以在配置文件中定义 Bean,比如:
userService=com.example.UserService,dao
表示我们要创建一个名为 userService
的 Bean,类型为 com.example.UserService
,构造函数参数为一个类型为 dao
的字符串。这个字符串可以用来表示依赖的其他 Bean。
然后,我们可以编写一个简单的类 BeanDefinitionRegistry
,用于管理所有的 BeanDefinition,并提供一些注册方法。
public interface BeanDefinitionRegistry {
void registerBeanDefinition(String name, BeanDefinition beanDefinition);
BeanDefinition getBeanDefinition(String name);
}
3. Bean 的依赖注入
在 Spring 中,Bean 的依赖注入主要通过构造函数或属性进行注入。这里我们先实现属性注入。
我们可以编写一个简单的类 BeanFactoryPostProcessor
,用于在 Bean 实例化之前,对 Bean 的定义信息进行修改。在这个方法中,我们可以将依赖的其他 Bean 注入到当前 Bean 的属性中。
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(DefaultListableBeanFactory beanFactory);
}
public class DefaultListableBeanFactory implements BeanFactory {
private final Map<String, BeanDefinition> beanDefinitions = new HashMap<>();
private final Map<String, Object> beans = new HashMap<>();
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
// TODO: addBeanPostProcessor
}
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {
beanFactoryPostProcessor.postProcessBeanFactory(this);
}
public void preInstantiateSingletons() {
// TODO: preInstantiateSingletons
}
@Override
public Object getBean(String name) throws Exception {
// TODO: getBean
}
@Override
public void registerBean(String name, Object bean) {
beans.put(name, bean);
}
@Override
public boolean containsBean(String name) {
return beans.containsKey(name);
}
}
public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor {
private final BeanFactory beanFactory;
public AutowiredAnnotationBeanPostProcessor(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
// TODO: postProcessBeforeInitialization
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
// TODO: postProcessAfterInitialization
}
}
4. Bean 的生命周期管理
在 Spring 中,Bean 的生命周期是由容器来管理的。在创建某个 Bean 之前,容器会先调用它的 postProcessBeforeInitialization
方法对其进行修改,而在销毁它时,容器会调用其 destroy
方法。
我们可以在 BeanDefinition
类中添加一些方法,用于实现 Bean 的生命周期管理,比如 initMethod
和 destroyMethod
。
public class BeanDefinition {
private final Class<?> type;
private final Object[] constructorArgs;
private final Map<String, Object> properties = new HashMap<>();
private String initMethod;
private String destroyMethod;
public void setInitMethod(String initMethod) {
this.initMethod = initMethod;
}
public void setDestroyMethod(String destroyMethod) {
this.destroyMethod = destroyMethod;
}
public Class<?> getType() {
return type;
}
public Object[] getConstructorArgs() {
return constructorArgs;
}
public Map<String, Object> getProperties() {
return properties;
}
public void init(Object bean) throws Exception {
if (initMethod != null) {
Method method = bean.getClass().getMethod(initMethod);
method.invoke(bean);
}
}
public void destroy(Object bean) throws Exception {
if (destroyMethod != null) {
Method method = bean.getClass().getMethod(destroyMethod);
method.invoke(bean);
}
}
}
然后,我们可以在 DefaultListableBeanFactory
类中添加一些方法,用于实现 Bean 的生命周期管理。
public class DefaultListableBeanFactory implements BeanFactory, BeanDefinitionRegistry {
private final Map<String, BeanDefinition> beanDefinitions = new HashMap<>();
private final Map<String, Object> beans = new HashMap<>();
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
// TODO: addBeanPostProcessor
}
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {
beanFactoryPostProcessor.postProcessBeanFactory(this);
}
public void preInstantiateSingletons() throws Exception {
for (Map.Entry<String, BeanDefinition> entry : beanDefinitions.entrySet()) {
String beanName = entry.getKey();
BeanDefinition beanDefinition = entry.getValue();
if (!beanDefinition.getType().isInterface()) {
Object bean = createBean(beanName, beanDefinition);
registerBean(beanName, bean);
beanDefinition.init(bean);
}
}
}
@Override
public Object getBean(String name) throws Exception {
// TODO: getBean
}
@Override
public void registerBean(String name, BeanDefinition beanDefinition) {
beanDefinitions.put(name, beanDefinition);
}
@Override
public BeanDefinition getBeanDefinition(String name) {
return beanDefinitions.get(name);
}
@Override
public boolean containsBean(String name) {
return beans.containsKey(name);
}
private Object createBean(String name, BeanDefinition beanDefinition) throws Exception {
Class<?> beanClass = beanDefinition.getType();
Object[] constructorArgs = beanDefinition.getConstructorArgs();
if (constructorArgs == null) {
return beanClass.newInstance();
}
List<Object> objects = new ArrayList<>();
for (Object arg : constructorArgs) {
if (arg instanceof String) {
objects.add(getBean((String) arg));
} else {
objects.add(arg);
}
}
Constructor<?> constructor = beanClass.getConstructor(constructorArgs.getClass());
return constructor.newInstance(objects.toArray());
}
}
5. 总结
通过以上的步骤,我们可以简单地实现了一个 Spring Bean 容器。虽然这个容器不具备 Spring 的完整的功能和特性,但是对于初学者或者想深入了解 Spring 内部原理的开发者而言,本文提供了一个简易的参考实现。
在实现过程中,我们涉及了容器接口和实现、Bean 的定义和注册、Bean 的依赖注入、Bean 的生命周期管理等多个方面。通过不断地切分和优化问题,我们逐步向着完整的 Spring 功能逼近,也更加深入地了解了 Spring 内部的运行机制。
当然,在实际使用 Spring 框架时,我们可以直接使用 Spring 自带的 Bean 容器,通过 XML 或者注解来配置和管理 Bean。但是通过手动实现一个简单的 Bean 容器,我们可以更加深入地理解 Spring 内部的运行机制,这对于我们日后开发、维护和扩展 Spring 应用程序都具有重要意义。
来源:https://juejin.cn/post/7239309010569101371


猜你喜欢
- 前言消息推送功能可以说移动APP不可缺少的功能之一,一般简单的推送我们可以使用第三方推送的SDK,比如极光推送、信鸽推送等,但是对于消息聊天
- 一 前言学习微服务要从基础的架构学起,首先你要有个微服务的概念才能学习对吧!!如果你都不知道啥是微服务,就一头扎进去学习,你自己也觉得自己也
- log4j MDC实现日志追踪MDC 中包含的可以被同一线程中执行的代码所访问内容。当前线程的子线程会继承其父线程中的 MDC 的内容。记录
- 本文实例讲述了Android编程使用WebView实现与Javascript交互的方法。分享给大家供大家参考,具体如下:Android中可以
- 本文实例讲述了android中Bitmap用法。分享给大家供大家参考。具体如下:在Android SDK中可以支持的图片格式如下:png ,
- CyclicBarrier 接着讲多线程下的其他组件,第一个要讲的就
- 宏定义与预处理命令预处理阶段:处理宏定义与预处理命令;编译期:检查代码,分析语法、语义等,最后生成.o或.obj文件;链接期:链接所有的.o
- 在java中,static是一个修饰符,用于修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能;被static关键
- 递归生成一个如图的菜单,编写两个类数据模型Menu、和创建树形的MenuTree。通过以下过程实现:1.首先从菜单数据中获取所有根节点。2.
- 异步方法很好的解决了这些问题,异步执行某个方法,程序立即开辟一个新线程去运行你的方法,主线程包括界面就不会死掉了。异步如何开始,好理解,现在
- 这个导出网站功能指通过前台javascript触发进入ashx函数中,实现将服务器中某个文件夹(包含其子文件夹和文件)通通复制到服务器中另一
- StringUtils.isBlank()的使用在校验一个String类型的变量是否为空时,可以使用StringUtils.isBlank方
- RandomAccessFileRandomAccessFile 是随机访问文件(包括读/写)的类。它支持对文件随机访问的读取和写入,即我们
- 代码注释是架起程序设计者与程序阅读者之间的通信桥梁,最大限度的提高团队开发合作效率。也是程序代码可维护性的重要环节之一。所以我们不是为写注释
- java.lang.Error: Unresolved compilation problems:出现该问题的原因主要是编译等级跟jdk不一
- Recyclerview现在基本已经替代Listview了,RecyclerView也越来越好用了 当我们有实现条目的拖拽排序和
- 在html中大家都知道布局是什么意思了,简单来说就是将页面划分模块,比如html中的div、table等。那么Android中也是这样的。A
- 在上一章中,有个问题可能大家都没有注意,Acitivity 在使用startActivityForResult后,可以给另一个的Acitiv
- 一,设计多图片打包下载逻辑:1,如果是要拉取腾讯云等资源服务器的图片,2,我们先把远程图片拉取到本地的临时文件夹,3,然后压缩临时文件夹,4
- 本文实例为大家分享了java验证码生成的具体代码,供大家参考,具体内容如下简单验证码java实现--servlet类生成 验证码img,并写