Spring 框架源码解读1

作者: 想54256 | 来源:发表于2020-04-14 20:29 被阅读0次

    title: Spring 框架源码解读1
    date: 2020/04/14


    前言

    为什么要阅读 Spring 源码?

    作为一个 Java 后台开发,在工作中肯定离不开 Spring,但是却对 Spring 中的实现原理只有大致的了解,没有深入的理解,所以想要通过这部分专栏带大家一起“深入”的了解 Spring 源码。

    Spring 简介

    Spring 是一个 IoC(Inversion of Control,控制反转)框架。

    IoC 是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递(注入)给它。 —— 维基百科

    为什么需要 IoC ?

    Java 是面向对象语言,在 Java 中万物皆对象,我们的程序就是由各种对象组成的,当多个类之间关系变成下面这样复杂的时候,维护起来心里可能会有1万只“草泥马”。

    image

    我们知道,在计算机领域,没有什么问题是加一层解决不了的,所以为了解决这个问题,我们引入 IoC 框架,让框架来维护类与类之间那错综复杂的关系,使我们解脱出来。

    image

    这个时候我们发现,我们类之间的关系都由 IoC 框架负责维护类,同时将类注入到需要的类中。

    类的使用者只负责使用,而不负责维护。

    本专栏内容

    1、我会带着大家从0开始自己写一个 IoC 框架,功能与 Spring 大体相同。

    2、当实现完一部分功能之后,我就会带着大家一起看看 Spring 0.9 中是怎样实现的

    3、然后再分析与 5.0 版本的区别

    本节内容 & 思考题

    今天会带大家动手搓一个 BeanFactory。

    大家想一下在 Spring 中 BeanFactory 的作用是什么,它采用了什么设计模式?

    手写 BeanFactory

    1、创建 Maven 项目,引入 hutool 工具类

    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>4.6.1</version>
    </dependency>
    

    2、书写 BeanDefinition

    BeanDefinition 定义了 bean 的信息,例如:它的名字、全类名、单例还是原型等

    /**
     * bean 的属性
     *
     * @author yujx
     * @date 2020/04/14 14:57
     */
    public interface BeanDefinition {
    
        /**
         * 名称
         */
        String getName();
    
        /**
         * 设置名称
         */
        void setName(String name);
    
        /**
         * 类名称
         */
        String getClassName();
    
        /**
         * 设置类名称
         */
        void setClassName(String className);
    
        ScopeEnum getScope();
    
        void setScope(ScopeEnum scope);
    
    
        enum ScopeEnum {
            SINGLETON,
            PROTOTYPE
        }
    }
    
    /**
     * 默认实现(Spring 中有两个实现 RootBD 和 ChildBD 其中 ChildBD 我们基本用不到)
     *
     * @author yujx
     * @date 2020/04/14 15:05
     */
    public class DefaultBeanDefinition implements BeanDefinition {
    
        // 名称
        private String name;
    
        // 全类名
        private String className;
    
        // 生命周期
        private ScopeEnum scope = ScopeEnum.SINGLETON;
    
        /**
         * 名称
         */
        @Override
        public String getName() {
            return name;
        }
    
        /**
         * 设置名称
         */
        @Override
        public void setName(String name) {
            this.name = name;
        }
    
        /**
         * 类名称
         */
        @Override
        public String getClassName() {
            return className;
        }
    
        /**
         * 设置类名称
         */
        @Override
        public void setClassName(String className) {
            this.className = className;
        }
    
        @Override
        public ScopeEnum getScope() {
            return scope;
        }
    
        @Override
        public void setScope(ScopeEnum scope) {
            this.scope = scope;
        }
    }
    
    

    3、定义 BeanFactory 接口

    BeanFactory 是生产 bean 的工厂

    AbstractBeanFactory 实现了 BeanFactory 中的所有方法,并维护了单例的 Map,并提供一个抽象方法getBeanDefinition(beanName)

    在 Spring 中 ListableBeanFactory 接口继承了它并扩展了它,提供了遍历 bd 相关的方法

    ListableBeanFactoryImpl 继承了 AbstractBeanFactory 并实现了 ListableBeanFactory 接口,实现了他们的抽象方法,它的主要功能是维护 bd 的 Map。

    JsonBeanFactory 是 Spring 中 XmlBF 的代替品,因为我不想解析恶心人的 xml,它负责读取 json 文件,向 bf 中注册 bd 信息。

    /**
     * 生产 bean 的工厂
     *
     * @author yujx
     * @date 2020/04/14 14:37
     */
    public interface BeanFactory {
    
        /**
         * 根据名称获取对应的 bean(工厂方法模式)
         */
        Object getBean(String name);
    
        /**
         * 根据名称和它的类型获取对应的 bean
         */
        <T> T getBean(String name, Class<T> requiredType);
    }
    
    /**
     * 负责维护单例对象(在 Spring 源码中该类还负责维护 parent 的bf,应该是为了 Spring MVC)
     *
     * @author yujx
     * @date 2020/04/14 19:14
     */
    public abstract class AbstractBeanFactory implements BeanFactory {
    
        // key:名字 value:单例对象
        private final Map<String, Object> sharedInstanceCache = new ConcurrentHashMap<>();
    
        /**
         * 根据名称获取对应的 bean (工厂方法模式)
         */
        @Override
        public Object getBean(String name) {
            if (sharedInstanceCache.containsKey(name)) {
                return sharedInstanceCache.get(name);
            }
    
            // 获取 bean 的属性信息
            BeanDefinition beanDefinition = this.getBeanDefinition(name);
            if (ObjectUtil.isNull(beanDefinition)) {
                throw new RuntimeException("获取的bean不存在!");
            }
    
            Object bean = this.createBean(beanDefinition);
            // 如果该对象是单例的,则加入到缓存中。
            if (beanDefinition.getScope().equals(BeanDefinition.ScopeEnum.SINGLETON)) {
                sharedInstanceCache.put(name, bean);
            }
            return bean;
        }
    
        // 根据 bd 创建对象
        private Object createBean(BeanDefinition beanDefinition) {
            return ReflectUtil.newInstance(beanDefinition.getClassName());
        }
    
    
        /**
         * 根据名称和它的类型获取对应的 bean
         */
        public <T> T getBean(String name, Class<T> requiredType) {
            Object bean = getBean(name);
            if (bean.getClass().equals(requiredType)) {
                return (T) bean;
            }
            throw new RuntimeException("获取bean的类型错误!");
        }
    
        /**
         * 根据名称获取 bd (子类实现)
         *
         * @param beanName
         * @return
         */
        protected abstract BeanDefinition getBeanDefinition(String beanName);
    }
    
    
    /**
     * 扩展了bf,可以根据类型返回容器中所有的 bean
     * <p>
     * BeanFactory的扩展将由可以枚举其所有bean实例的bean工厂来实现,而不是按照客户的要求按名称一一尝试。
     *
     * @author yujx
     * @date 2020/04/14 14:48
     */
    public interface ListableBeanFactory extends BeanFactory {
    
        /**
         * 根据类型获取容器中所有该类型的对象
         */
        <T> Map<String, T> getBeansOfType(Class<T> type);
    }
    
    
    /**
     * ListableBeanFactory 工厂的实现,并负责维护 bd 信息
     *
     * @author yujx
     * @date 2020/04/14 14:56
     */
    public class ListableBeanFactoryImpl extends AbstractBeanFactory implements ListableBeanFactory {
    
        // key:名字 value:bean 的信息
        private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    
        // key:字节码类型 value:名字数组(Spring 源码中是通过 beanDefinitionMap 遍历出来的,我们这里为了方便)
        private final Map<Class<?>, Set<String>> allBeanNamesByType = new ConcurrentHashMap<>(64);
    
        /**
         * 注册 bean 的信息
         */
        protected final void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
            beanDefinitionMap.put(name, beanDefinition);
    
            // 将相同类型的beanName放入 allBeanNamesByType 中
            String className = beanDefinition.getClassName();
            Class<?> type = this.getType(className);
    
            Set<String> beanNameSet = allBeanNamesByType.getOrDefault(type, new HashSet<>(1));
            beanNameSet.add(beanDefinition.getName());
            allBeanNamesByType.put(type, beanNameSet);
        }
    
        // 根据全类名获取类型
        private Class<?> getType(String className) {
            try {
                return Thread.currentThread().getContextClassLoader().loadClass(className);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
    
        /**
         * 根据类型获取容器中所有该类型的对象
         */
        @Override
        public <T> Map<String, T> getBeansOfType(Class<T> type) {
            Set<String> beanNameSet = allBeanNamesByType.get(type);
            if (ObjectUtil.isNull(beanNameSet)) {
                return new HashMap<>(0);
            }
    
            Map<String, T> map = new HashMap<>(beanNameSet.size());
            for (String beanName : beanNameSet) {
                map.put(beanName, this.getBean(beanName, type));
            }
            return map;
        }
    
        /**
         * 根据名称获取 bd (子类实现)
         *
         * @param beanName
         * @return
         */
        @Override
        protected BeanDefinition getBeanDefinition(String beanName) {
            return beanDefinitionMap.get(beanName);
        }
    }
    
    
    /**
     * 因为我不想解析xml,所以用json来代替
     * <p>
     * 负责从不同类型文件中读取配置并注册进 bd 的 Map 中
     *
     * @author yujx
     * @date 2020/04/14 15:26
     */
    public class JsonBeanFactoryImpl extends ListableBeanFactoryImpl {
    
        public JsonBeanFactoryImpl(String fileName) {
            JSONArray jsonArray = JSONUtil.readJSONArray(new File(fileName), StandardCharsets.UTF_8);
            this.loadBeanDefinitions(jsonArray);
        }
    
        private void loadBeanDefinitions(JSONArray jsonArray) {
            List<DefaultBeanDefinition> beanDefinitionList = jsonArray.toList(DefaultBeanDefinition.class);
            for (DefaultBeanDefinition bd : beanDefinitionList) {
                super.registerBeanDefinition(bd.getName(), bd);
            }
        }
    }
    

    4、测试

    public class Apple {
    
        private String name = "红富士";
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Apple{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    
    public class TestJsonBF {
        public static void main(String[] args) {
            ListableBeanFactory bf = new JsonBeanFactory("/Users/x5456/IdeaProjects/Summer/src/test/resources/apple.json");
            Apple apple = bf.getBean("apple", Apple.class);
            System.out.println(apple);
    
            Map<String, Apple> beansOfType = bf.getBeansOfType(Apple.class);
            System.out.println(beansOfType);
        }
    }
    
    apple.json
    
    [
    {"name":"apple","className":"cn.x5456.summer.Apple"},
    {"name":"apple2","className":"cn.x5456.summer.Apple"},
    {"name":"apple3","className":"cn.x5456.summer.Apple"}
    ]
    

    其实我觉得 BeanFactory、AbstractBeanFactory、ListableBeanFactoryImpl、JsonBeanFactoryImpl 他们几个符合单一职责,他们虽然是父子关系,但他们几个彼此之间都在做不同的事情。

    脑海中有一个念头告诉我,这应该是不好的,应该可以用设计模式优化,但是我想不起来。

    Spring 0.9 中的实现

    BeanFactory 和我的写法基本相同,相较于多了别名相关的东西。

    AbstractBeanFactory 中的方法也基本相同,多了一个父BF。

    image

    ListableBeanFactoryImpl 也和我的写法相同

    XmlBeanFactory 也基本相同

    image

    Spring 5.0 中区别

    各个类的职责依然没变,只是方法增多了很多,依赖注入部分增加了对注解的支持(AbstractAutowireCapableBeanFactory),虽然依赖注入我还没说,XmlBF 也已经被标注成废弃,现在主要使用的是 ApplicationContext 了,ApplicationContext 部分我们下次再说。

    思考题答案

    BeanFactory 是用来获取我们交给 Spring 容器管理的对象的。

    它采用了工厂方法模式。

    相关文章

      网友评论

        本文标题:Spring 框架源码解读1

        本文链接:https://www.haomeiwen.com/subject/lejxvhtx.html