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

你是不是有这样的感觉呢?

但是 spring 源码存在一个问题,那就是过于抽象,导致学习起来成本上升。所以本文由浅入深,只实现 spring 的核心功能,便于自己和他人学习 spring 的核心原理。

文章有点长,耐心阅读!如果对你有帮助,记得三连哦!

spring 的核心

Spring 的核心就是 spring-beans,后面的一切 spring-boot,spring-cloud 都是建立在这个地基之上。
当别人问你 spring 的时候,希望你可以谈谈自己对于 spring ioc 自己更深层的见解,而不是网上人云亦云的几句话。

另外本人整理收藏了20年多家公司面试知识点整理 ,以及各种Java核心知识点免费分享给大家,下方只是部分截图
想要资料的话也可以点击直接进入:暗号:csdn,免费获取。

什么是 IOC

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

为什么需要 IOC

IoC 是解耦的一种方法。
我们知道Java 是一门面向对象的语言,在 Java 中 Everything is Object,我们的程序就是由若干对象组成的。
当我们的项目越来越大,合作的开发者越来越多的时候,我们的类就会越来越多,类与类之间的引用就会成指数级的增长。


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

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

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

这个时候我们发现,我们类之间的关系都由 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

/*** 对象定义属性* @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);}@Overridepublic 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 的反射工具类

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 就基本实现了。

学海无涯,我们一起勉力前行!

Ps:有需要的小伙伴可以点击直接进入:暗号:csdn,免费获取。

面试专题文档。

技术文档

真实大厂面经

打怪上分! 手写Spring ioc 框架,狠狠的“撸撸”Spring 源码相关推荐

  1. 一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程)

    相关内容: 架构师系列内容:架构师学习笔记(持续更新) 一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程) 一步一步手绘Spring IOC运行时序图二(基于XM ...

  2. 博主熬夜手写个SpringMVC框架

    博主熬夜手写个SpringMVC框架 前言: 在spring全家桶流行的当下,只要你做的是Java技术栈基本上95%以上都使用的spring或springboot框架,剩下的5%基本上是一些老项目,政 ...

  3. 【RPC框架、RPC框架必会的基本知识、手写一个RPC框架案例、优秀的RPC框架Dubbo、Dubbo和SpringCloud框架比较】

    一.RPC框架必会的基本知识 1.1 什么是RPC? RPC(Remote Procedure Call --远程过程调用),它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络的技术. ...

  4. 手写MyBatis ORM框架

    手写MyBatis ORM框架 目标: 实现: 思路: 一.前期准备 1.加入依赖 2.自定义插入注解 3.自定义删除注解 4.自定义更新注解 5.自定义查询注解 6.自定义参数注解 7.定义和数据库 ...

  5. 认识Vue源码 (2)-- 手写类Vue框架:Zue

    一.手写类Vue框架:zue class Zue{constructor(options){//构造函数:this永远指向实例} } 1.在zue实例下创建$el,并指向挂载点 this.$el = ...

  6. 微信小程序 手写签名_你竟然还不知道在微信上就可以手写签名、签文件了~

    原标题:你竟然还不知道在微信上就可以手写签名.签文件了~ 你是否遇到以下问题: 正在休假却收到公司的夺命连环call,说有重要文件需要你签字确认? 正在上班,却有孩子学校.小区.甚至居委会各种需要通知 ...

  7. Java之手写实现ORM框架

    借鉴Mybatis框架手写一个ORM框架.mybatis整体架构中的整体思路是,首先解析一下配置文件,一个是框架的全局配置文件,一个是mapper配置文件,定义格式如下 <configurati ...

  8. pc手写识别_如何在Windows 10 PC上改善手写识别

    pc手写识别 Windows 10 lets you use handwriting input in any application, and many applications include f ...

  9. android毕业设计——基于Android+Java+Python的手机端办公自动化OA系统设计与实现(毕业论文+程序源码)——办公自动化OA系统

    基于Android+Java+Python的手机端办公自动化OA系统设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于Android+Java+Python的手机端办公自动化OA系统设计与实 ...

  10. java ssm框架论文,基于SSM框架的个人博客系统(源码+论文)

    需求分析 使用spring+springmvc+mybatis实现一个个人博客系统,可以记录个人生活日志, 进行技术分享, 并且浏览者可以对博客进行阅览与评论 本站提供了其他类型的 在线个人博客网站源 ...

最新文章

  1. 在windows10中安装 linux ubuntu 子系统
  2. 大学最后一个学期了,感觉没对头。。。
  3. 第二篇: Mysql____语法格式——键值
  4. 除了TensorFlow、PyTorch,还有哪些深度学习框架值得期待?
  5. 04_css盒子模型
  6. matlab 电压矢量开关,电压空间矢量研究及Matlab仿真
  7. oracle11g 卸载步骤
  8. VB.net小技巧——ClickOnce应用程序版本号自动递增
  9. 创建Tapestry5 工作环境
  10. 编程珠玑java_编程珠玑第八章
  11. Ubuntu20.04 在anaconda上,opencv-python支持h264编码
  12. CAD如何绘制固定面积的矩形
  13. 代写品牌故事-品牌故事的结构
  14. 闰年和平年的区别python_利用Python实现图书超期提醒
  15. Me-tetrazine-Disulfo-Cyanine5,甲基四嗪-磺酸基菁染料Cy5,蓝色固体
  16. python数据分析面试题_面试题——Python数据分析与应用(补充:简答)
  17. matlab hdf write,matlab读hdf
  18. PECL轻松安装PHP扩展
  19. 网络错误修复工具:Network Fault Repair Tool Build20160414
  20. node 中nextjs

热门文章

  1. 帷幕的帷是什么意思_帷是什么意思 帷字五行属什么
  2. Linux下ll 命令显示的文件类型
  3. 上海亚商投顾:沪指震荡调整 酒店等消费股逆势活跃
  4. Linux存储IO栈(4)-- SCSI子系统之概述
  5. php遍历语句_php遍历是什么意思
  6. Educoder–Java抽象类和接口 第1关:Fruit类
  7. 燃气蒸汽发生器助力酿酒企业更好把控啤酒加工温度
  8. Apple Store 的翻新机怎样?
  9. 怀旧服服务器阵营比例小程序,魔兽怀旧服阵营比例曝光 主播扎堆布鲁?10年老玩家表示:只关心排队问题...
  10. vue-router动态路由设置自定义首页