spring根据名称获取bean_带你从零开始手写 spring ioc 框架,深入学习 spring 源码
IoC
Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理。
创作目的
使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过。
但是 spring 源码存在一个问题,那就是过于抽象,导致学习起来成本上升。
所以本项目由渐入深,只实现 spring 的核心功能,便于自己和他人学习 spring 的核心原理。
spring 的核心
Spring 的核心就是 spring-beans,后面的一切 spring-boot,spring-cloud 都是建立在这个地基之上。
当别人问你 spring 的时候,希望你可以谈谈自己对于 spring ioc 自己更深层的见解,而不是网上人云亦云的几句话。
什么是 IOC
开始之前,记得点赞收藏加关注哦 ,需要下载PDF版本和获取更多知识点、面试题的朋友可以私信回复“资料”免费领取
控制反转(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 主要是以下几个步骤。
- 初始化 IoC 容器。
- 读取配置文件。
- 将配置文件转换为容器识别对的数据结构(这个数据结构在Spring中叫做 BeanDefinition)
- 利用数据结构依次实例化相应的对象
- 注入对象之间的依赖关系
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;}}
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);}}}}
最后
我这里准备了一线大厂面试资料和我原创的超硬核PDF技术文档,以及我为大家精心准备的多套简历模板(不断更新中),希望大家都能找到心仪的工作!
有需要的朋友可以私信回复“资料”免费领取
spring根据名称获取bean_带你从零开始手写 spring ioc 框架,深入学习 spring 源码相关推荐
- 高级JAVA - 手写简单的重试组件学习Spring Retry
目录 一 . 定义注解 二 . 利用cglib代理扩展重试业务 三 . 编写代理类 , 使用自定义的XRetryInterceptor作为拦截器 四 . 编写相关业务方法 , 测试代码 五 . 测试结 ...
- druid连接池初始化慢_从零开始手写 mybatis (三)jdbc pool 从零实现数据库连接池
前景回顾 第一节 从零开始手写 mybatis(一)MVP 版本 中我们实现了一个最基本的可以运行的 mybatis. 第二节 从零开始手写 mybatis(二)mybatis interceptor ...
- hashmap remove 没释放内存_java从零开始手写 redis(13)HashMap 源码原理详解
为什么学习 HashMap 源码? 作为一名 java 开发,基本上最常用的数据结构就是 HashMap 和 List,jdk 的 HashMap 设计还是非常值得深入学习的. 无论是在面试还是工作中 ...
- spring aop原理_Spring知识点总结!已整理成142页离线文档(源码笔记+思维导图)...
写在前面 由于Spring家族的东西很多,一次性写完也不太现实.所以这一次先更新Spring[最核心]的知识点:AOP和IOC 无论是入门还是面试,理解AOP和IOC都是非常重要的.在面试的时候,我没 ...
- 深蓝学院《从零开始手写VIO》作业七
深蓝学院<从零开始手写VIO>作业七 深蓝学院<从零开始手写VIO>作业七 深蓝学院<从零开始手写VIO>作业七 将第二讲中的仿真数据(视觉特征,imu数据)接入V ...
- node怎么把token放到redis_从零开始手写 redis(八)朴素 LRU 淘汰算法性能优化
前言 java从零手写实现redis(一)如何实现固定大小的缓存? java从零手写实现redis(三)redis expire 过期原理 java从零手写实现redis(三)内存数据如何重启不丢失? ...
- web网页设计——体育气步枪射击主题(5页面)带图片轮播特效(HTML+CSS) ~学生网页设计作业源码
web网页设计--体育气步枪射击主题(5页面)带图片轮播特效(HTML+CSS) ~学生网页设计作业源码 临近期末, 你还在为HTML网页设计结课作业,老师的作业要求感到头大?HTML网页作业无从下手 ...
- 从零开始手写VIO 第二章 IMU传感器
第二章 IMU传感器 课程代码: https://github.com/kahowang/Visual_Internal_Odometry/tree/main/%E7%AC%AC%E4%BA%8C%E ...
- 一箭双雕 刷完阿里P8架构师spring学习笔记+源码剖析,涨薪8K
关于Spring的叙述: 我之前死磕spring的时候,刷各种资料看的我是一头雾水的,后面从阿里的P8架构师那里拿到这两份资料,从源码到案例详细的讲述了spring的各个细节,是我学Spring的启蒙 ...
最新文章
- 开心周末:这就是2018年的我~
- cf534D 枚举握手次数
- 生成式模型:LDA与LSI-SVD分解
- 域名解析文件hosts文件是什么?如何修改hosts文件?
- javascript 键值转换
- 机械学哪种计算机语言,对于机器学习,到底该选择哪种编程语言?
- com.android.backupconfirm,终于去掉beta俱乐部了
- base | 使用apply族函数进行向量化运算
- 形态学上的图像顶帽运算和黑帽运算是什么?
- 【java学习之路】(javaWeb篇)007.正则表达式专题
- 25%的CPU利用率也能够让一台笔记本如此狼狈 (小红伞)
- xtwpro2编程器_最近喜欢上折腾路由器了,买的XTW100编程器给大家看看
- 雷达动画在地图显示_本周在我们的雷达上:RebeccaPurple,动画等!
- 顺序表的类型定义与基本操作
- spring基础知识(IOC、DI、AOP)
- 《经济学通识》十二、谈环保
- ktt算法 约化_矩阵特征与特征向量的计算
- SQLiteSpy导入db文件(导入数据库文件)
- oracle多表关联多字段update
- 【泛微ecology】ecology的补丁包升级