从零实现一个简单的Spring Bean容器的代码案例

 更新时间:2023年06月01日 08:34:05   作者:Cosolar  
Spring是一个非常流行的Java Web开发框架,它提供了强大的依赖注入、面向切面编程、声明式事务管理等功能,为开发者提供了高效、快速地构建Web应用程序的工具,在这篇文章中,咱们将一步一步地构建一个简单的SpringBean容器,需要的朋友可以参考下

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 的生命周期管理,比如 initMethoddestroyMethod

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 应用程序都具有重要意义。

以上就是从零实现一个简单的SpringBean容器的代码案例的详细内容,更多关于实现Spring Bean容器的资料请关注脚本之家其它相关文章!

相关文章

  • JAVA中NIO的技术原理及SpringBoot代码实例详解

    JAVA中NIO的技术原理及SpringBoot代码实例详解

    Java NIO(Non-blocking I/O)是Java1.4引入的非阻塞I/O API,通过Channel、Buffer和Selector实现高效、低延迟的异步文件传输,适用于高并发服务器端场景,本文给大家介绍JAVA中NIO的技术原理及SpringBoot代码实例,感兴趣的朋友一起看看吧
    2025-10-10
  • 关于springcloud集成nacos遇到的问题

    关于springcloud集成nacos遇到的问题

    这篇文章主要介绍了关于springcloud集成nacos遇到的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • 10中java常见字符串操作实例

    10中java常见字符串操作实例

    给大家分享10中java常见字符串操作方法以及相关实例代码,对此有需要的读者们可以学习参考下。
    2019-07-07
  • maven配置阿里云仓库的实现方法

    maven配置阿里云仓库的实现方法

    本文主要介绍了maven配置阿里云仓库的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • Eolink上传文件到Java后台进行处理的示例代码

    Eolink上传文件到Java后台进行处理的示例代码

    这篇文章主要介绍了Eolink上传文件到Java后台进行处理,这里是上传的excel表格数据并转换为java集合对象、然后进行业务逻辑处理判断最后保存到数据库 ,需要的朋友可以参考下
    2022-12-12
  • SpringBoot完整实现滑块拼图验证+轨迹验证+Redis分布式方案

    SpringBoot完整实现滑块拼图验证+轨迹验证+Redis分布式方案

    滑块拼图验证是一种行为验证技术,通过要求用户将拼图块拖动到正确位置来区分人类用户和自动化程序,本文介绍SpringBoot完整实现滑块拼图验证+轨迹验证+Redis分布式方案,感兴趣的朋友跟随小编一起看看吧
    2026-03-03
  • Java实现导出合并Excel单元格

    Java实现导出合并Excel单元格

    随着数据的不断增长,很多时候需要将数据导出到Excel中进行分析、处理和展示。本文将介绍如何使用Java实现Excel导出,并且可以合并单元格,需要的可以参考一下
    2023-04-04
  • java 排序算法之冒泡排序

    java 排序算法之冒泡排序

    这篇文章主要介绍了java 排序算法之冒泡排序,文中运用大量的代码讲解相关知识,非常详细,感兴趣的小伙伴可以参考一下
    2021-09-09
  • Java参数校验详解之使用@Valid注解和自定义注解进行参数验证

    Java参数校验详解之使用@Valid注解和自定义注解进行参数验证

    在后端开发中,参数校验是非常普遍的,下面这篇文章主要给大家介绍了关于Java参数校验详解之使用@Valid注解和自定义注解进行参数验证的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-06-06
  • Java编写掷骰子游戏

    Java编写掷骰子游戏

    这篇文章主要介绍了Java编写掷骰子游戏,需要的朋友可以参考下
    2015-11-11

最新评论