>>分享流行的Java框架以及开源软件,对孙卫琴的《精通Spring:Java Web开发技术详解》提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 15840 个阅读者 刷新本主题
 * 贴子主题:  从零开始手写 spring ioc 框架,深入学习 spring 源码 回复文章 点赞(0)  收藏  
作者:flybird    发表时间:2021-02-04 06:39:25     消息  查看  搜索  好友  邮件  复制  引用

  

IoC

Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理。

创作目的

使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过。

     但是 spring 源码存在一个问题,那就是过于抽象,导致学习起来成本上升。

     所以本项目由渐入深,只实现 spring 的核心功能,便于自己和他人学习 spring 的核心原理。

spring 的核心

Spring 的核心就是 spring-beans,后面的一切 spring-boot,spring-cloud 都是建立在这个地基之上。

     当别人问你 spring 的时候,希望你可以谈谈自己对于 spring ioc 自己更深层的见解,而不是网上人云亦云的几句话。

什么是 IOC

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。

     其中最常见的方式叫做依赖注入(Dependency Injection,简称DI)。

     通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。

     也可以说,依赖被注入到对象中。

为什么需要 IOC

IoC 是解耦的一种方法。

     我们知道Java 是一门面向对象的语言,在 Java 中 Everything is Object,我们的程序就是由若干对象组成的。

     当我们的项目越来越大,合作的开发者越来越多的时候,我们的类就会越来越多,类与类之间的引用就会成指数级的增长。

     点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

     这样的工程简直就是灾难,如果我们引入 Ioc 框架。

     由框架来维护类的生命周期和类之间的引用。

     我们的系统就会变成这样:

     点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

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

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

     把专业的事情交给专业的框架来完成,大大的减少开发的复杂度。

快速开始

maven 引入

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>ioc</artifactId>
    <version>0.1.11</version>
</dependency>

测试准备

全部测试代码,见 test 模块。
  • Apple.java
public class Apple {

    public void color() {
        System.out.println("Apple color: red. ");
    }

}

  • apple.json
类似于 xml 的配置,我们暂时使用 json 进行配置验证。    

[
{"name":"apple","className":"com.github.houbb.ioc.test.service.Apple"}
]

执行测试

  • 测试
BeanFactory beanFactory = new JsonApplicationContext("apple.json");
Apple apple = (Apple) beanFactory.getBean("apple");
apple.color();

  • 日志
Apple color: red.

spring 基本实现流程

说明

spring-beans 一切都是围绕 bean 展开的。

     BeanFactory 负责对 bean 进行生命周期的相关管理,本节展示第一小节的简单实现流程。

spring 核心流程

Spring IoC 主要是以下几个步骤。
  1.   初始化 IoC 容器。
  2.   读取配置文件。
  3.   将配置文件转换为容器识别对的数据结构(这个数据结构在Spring中叫做 BeanDefinition)
  4.   利用数据结构依次实例化相应的对象
  5. 注入对象之间的依赖关系

BeanDefinition 的抽象

BeanDefinition 是 spring 对 java bean 属性的一个抽象,经过这一层抽象,配置文件可以是 xml/json/properties/yaml 等任意一种,甚至包括注解扫包。

     为 spring 的拓展带来极大的灵活性。

     本框架考虑到实现的简单性,初步只实现了 json 和基于注解扫包两种方式。

     后期如果有时间可以考虑添加 xml 的实现,其实更多是 xml 的解析工作量,核心流程已经全部实现。

实现源码节选

BeanDefinition 相关

包含了对于 java bean 的基本信息抽象。
  • BeanDefinition.java
其默认实现为

DefaultBeanDefinition.java

,就是对接口实现的最基本的 java POJO
  参见 DefaultBeanDefinition
/**
* 对象定义属性
* @author binbin.hou
* @since 0.0.1
*/

public interface BeanDefinition {

    /**
     * 名称
     * @return 名称
     * @since 0.0.1
     */

    String getName();

    /**
     * 设置名称
     * @param name 名称
     * @since 0.0.1
     */

    void setName(final String name);

    /**
     * 类名称
     * @return 类名称
     */

    String getClassName();

    /**
     * 设置类名称
     * @param className 类名称
     * @since 0.0.1
     */

    void setClassName(final String className);

}

BeanFactory 核心管理相关

  • BeanFactory.java
/**
* bean 工厂接口
* @author binbin.hou
* @since 0.0.1
*/

public interface BeanFactory {

    /**
     * 根据名称获取对应的实例信息
     * @param beanName bean 名称
     * @return 对象信息
     * @since 0.0.1
     */

    Object getBean(final String beanName);

    /**
     * 获取指定类型的实现
     * @param beanName 属性名称
     * @param tClass 类型
     * @param <T> 泛型
     * @return 结果
     * @since 0.0.1
     */

    <T> T getBean(final String beanName, final Class<T> tClass);

}

  • DefaultBeanFactory.java
为接口最基础的实现,源码如下:    

/**
* bean 工厂接口
* @author binbin.hou
* @since 0.0.1
*/

public class DefaultBeanFactory implements BeanFactory {

    /**
     * 对象信息 map
     * @since 0.0.1
     */

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

    /**
     * 对象 map
     * @since 0.0.1
     */

    private Map<String, Object> beanMap = new ConcurrentHashMap<>();

    /**
     * 注册对象定义信息
     * @since 0.0.1
     */

    protected void registerBeanDefinition(final String beanName, final BeanDefinition beanDefinition) {
        // 这里可以添加监听器
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }

    @Override
    public Object getBean(String beanName) {
        Object bean = beanMap.get(beanName);
        if(ObjectUtil.isNotNull(bean)) {
            // 这里直接返回的是单例,如果用户指定为多例,则每次都需要新建。
            return bean;
        }

        // 获取对应配置信息
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(ObjectUtil.isNull(beanDefinition)) {
            throw new IocRuntimeException(beanName + " not exists in bean define.");
        }

        // 直接根据
        Object newBean = createBean(beanDefinition);
        // 这里可以添加对应的监听器
        beanMap.put(beanName, newBean);
        return newBean;
    }

    /**
     * 根据对象定义信息创建对象
     * @param beanDefinition 对象定义信息
     * @return 创建的对象信息
     * @since 0.0.1
     */

    private Object createBean(final BeanDefinition beanDefinition) {
        String className = beanDefinition.getClassName();
        Class clazz = ClassUtils.getClass(className);
        return ClassUtils.newInstance(clazz);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T getBean(String beanName, Class<T> tClass) {
        Object object = getBean(beanName);
        return (T)object;
    }

}

  其中 ClassUtils 是基于 class 的反射工具类,详情见 ClassUtils.java

JsonApplicationContext

基于 json 配置文件实现的基本实现,使用方式见开始种的例子代码。
  • JsonApplicationContext.java
/**
* JSON 应用上下文
* @author binbin.hou
* @since 0.0.1
*/

public class JsonApplicationContext extends DefaultBeanFactory {

    /**
     * 文件名称
     * @since 0.0.1
     */

    private final String fileName;

    public JsonApplicationContext(String fileName) {
        this.fileName = fileName;

        // 初始化配置
        this.init();
    }

    /**
     * 初始化配置相关信息
     *
     * <pre>
     *  new TypeReference<List<BeanDefinition>>(){}
     * </pre>
     *
     * 读取文件:https://blog.csdn.net/feeltouch/article/details/83796764
     * @since 0.0.1
     */

    private void init() {
        InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
        final String jsonConfig = FileUtil.getFileContent(is);
        List<DefaultBeanDefinition> beanDefinitions = JsonBs.deserializeArray(jsonConfig, DefaultBeanDefinition.class);
        if(CollectionUtil.isNotEmpty(beanDefinitions)) {
            for (BeanDefinition beanDefinition : beanDefinitions) {
                super.registerBeanDefinition(beanDefinition.getName(), beanDefinition);
            }
        }
    }

}

小结

至此,一个最基本的 spring ioc 就基本实现了。

     如果你想继续学习,可以分别参考以下代码分支。

分支说明

v0.0.1-BeanFactory 基本实现

     v0.0.2-ListBeanFactory 基本实现

     v0.0.3-单例和延迟加载

     v0.0.4-初始化和销毁方法

     v0.0.5-RespCode 添加和代码优化

     v0.0.6-构造器和 factoryMethod 新建对象

     v0.0.7-property 属性设置

     v0.0.8-Aware 监听器及 PostProcessor

     v0.0.9-Parent 属性继承

     v0.1.0-循环依赖检测

     v0.1.1-@Configuration-java 代码配置

     v0.1.2-@Bean-java 对象定义

     v0.1.3-@Lazy-@Scope-java 对象属性配置

     v0.1.4-@Import 配置导入

     v0.1.5-@Bean 参数构造以及 @Description

     v0.1.6-@Autowired 自动装配注解支持

     v0.1.7-@Primary 指定优先级注解

     v0.1.8-@Conditional 条件注解支持

     v0.1.9-Environment 和 @Profile 实现

     v0.1.10-Property 配置文件相关和 @Value/@PropertyResource 实现

     v0.1.11-@ComponentScan 文件包扫描支持

拓展阅读

Java IOC-00-ioc 是什么



----------------------------
原文链接:https://blog.51cto.com/9250070/2455156

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 flybird 在 2021-02-04 23:43:03 重新编辑]
  Java面向对象编程-->类的生命周期
  JavaWeb开发-->Servlet技术详解(Ⅲ)
  JSP与Hibernate开发-->立即检索和延迟检索策略
  Java网络编程-->通过JavaMail API收发邮件
  精通Spring-->计算属性和数据监听
  Vue3开发-->绑定表单
  Spring boot参考指南
  如何编写优雅的Spring架构API
  Mybatis-plus大数据量流式查询
  Spring事务的声明和管理
  孙卫琴系列Java书籍的QQ交流读者群
  springmvc处理异步请求的示例
  springMVC:HandlerInterceptor拦截器的使用
  【项目实践】后端接口统一规范的同时,如何优雅地扩展规范
  Spring MVC数据验证
  SpringMVC Model、ModelMap和ModelAndView的区别和用法
  SpringCloud Gateway-整体流程
  Nginx技术探秘
  spring cloud分布式微服务的概览
  kubernetes 中的资源
  Java-CORBA
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。