手写Spring-第一章-实现一个简单的Bean容器

前言

开个新坑,来整点儿大项目。有这个想法是因为用了那么久的Spring,但是某一天突然冒出来一个念头:Spring到底是怎么实现这些功能的。发现脑子一片空白。在我抽出纸巾擦干脑门儿上的汗之后,我决定去网上搜索Spring源码解读。但是找来找去,要么讲的乱七八糟,要么就是过于庞大,一下子堆到面前,看不下去。终于,找到了一个还不错的教程,作者基于Spring框架,自己手写了一个简化版的Spring,而且代码的命名、类之间的关系,都是根据真正的Spring来的,只不过有所简化。我想,这就是我要找的教程了。所以我也跟着一边学习,一边在这里记录自己的学习理解,也算是有所沉淀。

在这里说一下原作者的博客地址:https://bugstack.cn 作者叫小傅哥,教程的名字叫《手撸Spring》,也算个版权声明以及宣传吧~

教程的一开始,还是非常简单的。这也是吸引我学习下去的原因,由浅入深,逐步深入,才是正确的学习路线。在这一章,我们要搭建起一个简单的Bean容器,实现Bean的注册和获取

工程结构

├─src
│  ├─main
│  │  ├─java
│  │  │  └─com
│  │  │      └─akitsuki
│  │  │          └─springframework
│  │  │                  BeanDefinition.java
│  │  │                  BeanFactory.java
│  │  │
│  │  └─resources
│  └─test
│      └─java
│          └─com
│              └─akitsuki
│                  └─springframework
│                      └─test
│                          │  ApiTest.java
│                          │
│                          └─bean
│                                  UserService.java

看这里的工程目录,好像只有两个类。没错,我们一开始要做的就是这么多,两个类,就可以实现一个简单的Bean容器。

Bean定义

首先是我们两个类中的第一个类:BeanDefinition。

package com.akitsuki.springframework;

/**
 * @author ziling.wang@hand-china.com
 * @date 2022/11/7 9:28
 */
public class BeanDefinition {

    private Object bean;

    public BeanDefinition(Object bean) {
        this.bean = bean;
    }

    public Object getBean() {
        return bean;
    }
}

这里可能会觉得这个BeanDefinition有些莫名其妙,里面只有一个Object类型的属性bean。顾名思义,这里应该是用来放置我们实例化好的bean的。但实际上,这里是因为过于简化的结果。在后面的学习中,我们会逐渐扩充BeanDefinition的内容,比如加入bean的class、bean的属性和值等等内容。同时也会将现在的实例化bean进行移除。

所以BeanDefinition到底是用来做什么的呢,我理解,这个类是用来包装bean的一些“参数”的。bean的class是什么,有哪些属性,属性的初始化值是哪些,有没有初始化方法、销毁方法之类。就像它的名字一样,bean的定义,这个bean应该是什么样子的,由这个类来规定。

Bean工厂

看到这个名字,大家肯定都很清楚了,生产bean的工厂,还用到了工厂模式。

package com.akitsuki.springframework;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author ziling.wang@hand-china.com
 * @date 2022/11/7 9:30
 */
public class BeanFactory {

    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    public Object getBean(String beanName) {
        return beanDefinitionMap.get(beanName).getBean();
    }

    public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(name, beanDefinition);
    }
}

这个类的内容就比刚才的要复杂一些了,首先有这么两个方法:getBeanregisterBeanDefinition。而且,内部维护了一个Map,用来存放bean定义。

既然是Bean的工厂,那么自然是要用来生产bean了。这里有个很有意思的地方,就是内部维护的map,不是存放bean的,而是存放bean定义的。从这里我们也可以看出,bean定义是我们实例化bean的一个模子的概念。我们先要把bean定义好,才能去实现它。

首先我们看 getBean方法,这个方法是用来获取bean的。方法的内容则是从map中通过bean的名称,来获取相应的bean定义。这里是用bean的名称作为map的key来与bean定义进行关联。一开始我是有一些疑惑的,为什么bean的名称不是bean定义中的一个属性。但后来我考虑,bean定义中的内容,都是模板的内容,只有最终实例化好了的bean,才能有一个名称来与之对应,一个模板可以生产多个产品,也就是bean,所以bean的名称不能作为bean定义中的一个属性

然后我们看 registerBeanDefinition。这个方法是用来注册bean定义的。我们要先把一个bean定义注册到Spring中,才能根据这个定义来实例化具体的bean。这个注册具体的体现方式,自然就是我们的各种bean配置文件以及注解了。当然我们现在还没有发展到那一步,在后面会去继续完善的。

测试!

首先,我们要有一个等待交给Spring管理的bean

package com.akitsuki.springframework.test.bean;

/**
 * @author ziling.wang@hand-china.com
 * @date 2022/11/7 9:36
 */
public class UserService {

    public void queryUserInfo() {
        System.out.println("查询用户信息");
    }
}

非常简单,但它确实可以作为一个bean,而且有一个方法可以对外提供服务,嗯,你已经是一个合格的bean了。

然后,我们就要来编写具体的测试方法了

package com.akitsuki.springframework.test;

import com.akitsuki.springframework.BeanDefinition;
import com.akitsuki.springframework.BeanFactory;
import com.akitsuki.springframework.test.bean.UserService;
import org.junit.Test;

/**
 * @author ziling.wang@hand-china.com
 * @date 2022/11/7 9:37
 */
public class ApiTest {

    @Test
    public void testBeanFactory() {
        //初始化BeanFactory
        BeanFactory beanFactory = new BeanFactory();

        //注册Bean
        BeanDefinition beanDefinition = new BeanDefinition(new UserService());
        beanFactory.registerBeanDefinition("userService", beanDefinition);

        //获取Bean
        UserService userService = (UserService) beanFactory.getBean("userService");
        userService.queryUserInfo();
    }
}

可以看到,这里我们先初始化了BeanFactory,然后新建了一个bean定义,并将其注册到了factory中。最后再由factory生产出这个bean。

可以看到,这时候我们的Spring已经初具雏形了,虽然是各方面都经过简化的结果,但我们已经完成了bean的注册、生产、获取等操作。在后面,我们会逐步完善,把这些操作变成自动化、读取配置文件来进行,让我们的小demo逐渐的更加接近真正的Spring。

相关源码可以参考我的gitee:https://gitee.com/akitsuki-kouzou/mini-spring,这里对应的代码是mini-spring-01

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值