写点什么

如何从零实现一个简单的 Spring Bean 容器

作者:Java你猿哥
  • 2023-06-05
    湖南
  • 本文字数:5327 字

    阅读完需:约 17 分钟

Spring 是一个非常流行的 Java Web 开发框架,它提供了强大的依赖注入、面向切面编程、声明式事务管理等功能,为开发者提供了高效、快速地构建 Web 应用程序的工具。

最近在学习 Spring 这个框架源码时,我明白我们不仅需要掌握其基本使用方法,还应该深入了解其内部实现原理。本博文将会带领大家一步一步地实现一个简单的 Spring Bean 容器,涉及到容器接口和实现、Bean 的定义和注册、Bean 的依赖注入、Bean 的生命周期管理等多个方面,旨在帮助读者更加深入地理解 Spring 内部的运行机制。

如果你想更加深入地了解 Spring 框架的内部原理,或者想从零开始手动实现一个简单的 Spring Bean 容器的话,欢迎以后一起学习探讨,共同进步!

在这篇文章中,放松心情,提高兴趣,咱们将一步一步地构建一个简单的 Spring Bean 容器,包括如下内容:

  1. 容器接口和实现

  2. Bean 的定义和注册

  3. Bean 的依赖注入

  4. Bean 的生命周期管理

我只想写出主要的实现思路,不做具体详细的细节实现,一起勾勒这个简单的版图。也推荐初学者看看这篇博文 Spring 手撸专栏希望各位在成长之路有所受益~

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

用户头像

Java你猿哥

关注

一只在编程路上渐行渐远的程序猿 2023-03-09 加入

关注我,了解更多Java、架构、Spring等知识

评论

发布
暂无评论
如何从零实现一个简单的Spring Bean容器_Java_Java你猿哥_InfoQ写作社区