Spring自己实现一个简单的 Spring IOC 自己实现简单的 Spring

Posted 九师兄

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring自己实现一个简单的 Spring IOC 自己实现简单的 Spring相关的知识,希望对你有一定的参考价值。

1.概述

你有自己实现过简单的 Spring 吗?

Spring 的 IOC 本质就是一个大工厂,我们想想一个工厂是怎么运行的呢?

生产产品:一个工厂最核心的功能就是生产产品。在 Spring 里,不用 Bean 自己来实例化,而是交给 Spring,应该怎么实现呢?——答案毫无疑问,反射。

那么这个厂子的生产管理是怎么做的?你应该也知道——工厂模式。

库存产品:工厂一般都是有库房的,用来库存产品,毕竟生产的产品不能立马就拉走。Spring 我们都知道是一个容器,这个容器里存的就是对象,不能每次来取对象,都得现场来反射创建对象,得把创建出的对象存起来。

订单处理:还有最重要的一点,工厂根据什么来提供产品呢?订单。这些订单可能五花八门,有线上签签的、有到工厂签的、还有工厂销售上门签的……最后经过处理,指导工厂的出货。

在 Spring 里,也有这样的订单,它就是我们 bean 的定义和依赖关系,可以是 xml 形式,也可以是我们最熟悉的注解形式。

我们简单地实现一个 mini 版的 Spring IOC:


Bean 定义:

Bean 通过一个配置文件定义,把它解析成一个类型。

beans.properties

偷懒,这里直接用了最方便解析的 properties,这里直接用一个<key,value>类型的配置来代表 Bean 的定义,其中 key 是 beanName,value 是 class

userDao:cn.fighter3.bean.UserDao

BeanDefinition.java

bean 定义类,配置文件中 bean 定义对应的实体

public class BeanDefinition 

    private String beanName;

    private Class beanClass;
     //省略getter、setter
 

ResourceLoader.java

资源加载器,用来完成配置文件中配置的加载

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;
    


BeanRegister.java

对象注册器,这里用于单例 bean 的缓存,我们大幅简化,默认所有 bean 都是单例的。可以看到所谓单例注册,也很简单,不过是往 HashMap 里存对象。

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);
    



BeanFactory.java


对象工厂,我们最核心的一个类,在它初始化的时候,创建了 bean 注册器,完成了资源的加载。

获取 bean 的时候,先从单例缓存中取,如果没有取到,就创建并注册一个 bean

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;
    

2.测试

UserDao.java

我们的 Bean 类,很简单

public class UserDao 

    public void queryUserInfo()
        System.out.println("A good man.");
    

单元测试

public class ApiTest 
    @Test
    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();
    

运行结果

A good man.
A good man.

至此,我们一个乞丐+破船版的 Spring 就完成了,代码也比较完整,有条件的可以跑一下。

M.参考

转载:Spring:35道精选面试题

以上是关于Spring自己实现一个简单的 Spring IOC 自己实现简单的 Spring的主要内容,如果未能解决你的问题,请参考以下文章

javaSpring 自己模拟 Spring 实现 IOC依赖注入 并且 解决 循环依赖

深入理解Spring--动手实现一个简单的SpringIOC容器

spring Ioc简单实践

day02-Spring基本介绍02

spring教程:简单实现(转)

简单了解Spring中常用工具类_java - JAVA