手写一个简单的Spring容器(原理+源码)

原理

手写一个简单的Spring容器,用配置文件方式,在配置文件中写入我们想要的bean,bean实例被用到时注册(注册到仓库,或者说缓存),后续我们就可以直接根据bean的名字拿到这个bean的单例。

在这里插入图片描述

Spring容器,就是Spring帮忙管理类(JavaBean),我们先写一个简单的单例容器,Bean的配置写在配置文件(beans.properties)中,格式是:

<beanName>:<fullClassName>

要根据名字获取一个bean,就需要用到工厂,当工厂被实例化时,就会用资源加载器,去反射创建bean(也就是beanDefinition),然后存入beanDefinitionMap。

beanDefinition不是一个普通的类,而是一个有beanName和ClassName的类,有了这两项才好被用来创建(反射)和管理(配合注册机)bean的使用实例。

通过资源加载创建的beanDefinition先放置到beanDefinitionMap(一个临时的bean表),每次getBean(通过beanName)的时候,如果注册机已经注册了这个bean,那么直接从注册机获取,否则从beanDefinitionMap中取出beanDefinition,根据beanDefinition的内容反射创建实例,并通过工厂内部的BeanRegister注册机(本质也是一个HashMap)进行注册。(甚至可以理解为缓存)

代码

bean配置

beans.properties
这里边只有一个bean的beanName:fullClassName

userDao:UserDao
bean工厂

BeanFactory.java

import java.util.*;

public class BeanFactory {

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

    private BeanRegister beanRegister;

    public BeanFactory() {
        //创建bean注册器
        beanRegister = new BeanRegister();
        //加载资源
        this.beanDefinitionMap = new ResourceLoader().getResource();
    }

    /**
     * 获取bean
     *
     * @param beanName bean名称
     * @return
     */
    public Object getBean(String beanName) {
        //从bean缓存中取
        Object bean = beanRegister.getSingletonBean(beanName);
        if (bean != null) {
            return bean;
        }
        //根据bean定义,创建bean
        return createBean(beanDefinitionMap.get(beanName));
    }

    /**
     * 创建Bean
     *
     * @param beanDefinition bean定义
     * @return
     */
    private Object createBean(BeanDefinition beanDefinition) {
        try {
            Object bean = beanDefinition.getBeanClass().newInstance();
            //缓存bean
            beanRegister.registerSingletonBean(beanDefinition.getBeanName(), bean);
            return bean;
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
}
注册机

BeanRegister.java
一个HashMap实现单例注册

import java.util.*;

public class BeanRegister {
    //单例Bean缓存
    private Map<String, Object> singletonMap = new HashMap<>(32);

    /**
     * 获取单例Bean
     *
     * @param beanName bean名称
     * @return
     */
    public Object getSingletonBean(String beanName) {
        return singletonMap.get(beanName);
    }

    /**
     * 注册单例bean
     *
     * @param beanName
     * @param bean
     */
    public void registerSingletonBean(String beanName, Object bean) {
        if (singletonMap.containsKey(beanName)) {
            return;
        }
        singletonMap.put(beanName, bean);
    }
}
资源加载

ResourceLoader.java

import java.util.*;
import java.io.*;

public class ResourceLoader {
    public static Map<String, BeanDefinition> getResource() {
        Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(16);
        Properties properties = new Properties();
        try {
            InputStream inputStream = ResourceLoader.class.getResourceAsStream("/beans.properties");
            properties.load(inputStream);
            Iterator<String> it = properties.stringPropertyNames().iterator();
            while (it.hasNext()) {
                String key = it.next();
                String className = properties.getProperty(key);
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setBeanName(key);
                Class clazz = Class.forName(className);
                beanDefinition.setBeanClass(clazz);
                beanDefinitionMap.put(key, beanDefinition);
            }
            inputStream.close();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return beanDefinitionMap;
    }
}

Bean定义

BeanDefinition.java

public class BeanDefinition {

    private String beanName;

    private Class beanClass;
    //省略getter、setter


    public String getBeanName() {
        return beanName;
    }

    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    public Class getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(Class beanClass) {
        this.beanClass = beanClass;
    }
}
Bean原型

UserDao.java

public class UserDao {

    public void queryUserInfo(){
        System.out.println("A good man.");
    }
}
测试

ApiTest.java

public class ApiTest {

    public void test_BeanFactory() {
        //1.创建bean工厂(同时完成了加载资源、创建注册单例bean注册器的操作)
        BeanFactory beanFactory = new BeanFactory();

        //2.第一次获取bean(通过反射创建bean,缓存bean)
        UserDao userDao1 = (UserDao) beanFactory.getBean("userDao");
        userDao1.queryUserInfo();

        //3.第二次获取bean(从缓存中获取bean)
        UserDao userDao2 = (UserDao) beanFactory.getBean("userDao");
        userDao2.queryUserInfo();
    }

    public static void main(String[] args) {
        new ApiTest().test_BeanFactory();
    }
}

参考:
程序员鱼皮《五分钟,手撸一个Spring容器!》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值