- Notifications
You must be signed in to change notification settings - Fork19
The java ioc framework(从零开始手写模拟 spring Ioc 框架)
License
houbb/ioc
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理。
使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过。
但是 spring 源码存在一个问题,那就是过于抽象,导致学习起来成本上升。
所以本项目由渐入深,只实现 spring 的核心功能,便于自己和他人学习 spring 的核心原理。
Spring 的核心就是 spring-beans,后面的一切 spring-boot,spring-cloud 都是建立在这个地基之上。
当别人问你 spring 的时候,希望你可以谈谈自己对于 spring ioc 自己更深层的见解,而不是网上人云亦云的几句话。
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。
其中最常见的方式叫做依赖注入(Dependency Injection,简称DI)。
通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。
也可以说,依赖被注入到对象中。
IoC 是解耦的一种方法。
我们知道Java 是一门面向对象的语言,在 Java 中 Everything is Object,我们的程序就是由若干对象组成的。
当我们的项目越来越大,合作的开发者越来越多的时候,我们的类就会越来越多,类与类之间的引用就会成指数级的增长。
这样的工程简直就是灾难,如果我们引入 Ioc 框架。
由框架来维护类的生命周期和类之间的引用。
我们的系统就会变成这样:
这个时候我们发现,我们类之间的关系都由 IoC 框架负责维护类,同时将类注入到需要的类中。
也就是类的使用者只负责使用,而不负责维护。
把专业的事情交给专业的框架来完成,大大的减少开发的复杂度。
<dependency> <groupId>com.github.houbb</groupId> <artifactId>ioc</artifactId> <version>0.1.11</version></dependency>
全部测试代码,见 test 模块。
- Apple.java
publicclassApple {publicvoidcolor() {System.out.println("Apple color: red. "); }}
- apple.json
类似于 xml 的配置,我们暂时使用 json 进行配置验证。
[{"name":"apple","className":"com.github.houbb.ioc.test.service.Apple"}]- 测试
BeanFactorybeanFactory =newJsonApplicationContext("apple.json");Appleapple = (Apple)beanFactory.getBean("apple");apple.color();
- 日志
Apple color: red.spring-beans 一切都是围绕 bean 展开的。
BeanFactory 负责对 bean 进行生命周期的相关管理,本节展示第一小节的简单实现流程。
Spring IoC 主要是以下几个步骤。
初始化 IoC 容器。
读取配置文件。
将配置文件转换为容器识别对的数据结构(这个数据结构在Spring中叫做 BeanDefinition)
利用数据结构依次实例化相应的对象
注入对象之间的依赖关系
BeanDefinition 是 spring 对 java bean 属性的一个抽象,经过这一层抽象,配置文件可以是 xml/json/properties/yaml 等任意一种,甚至包括注解扫包。
为 spring 的拓展带来极大的灵活性。
本框架考虑到实现的简单性,初步只实现了 json 和基于注解扫包两种方式。
后期如果有时间可以考虑添加 xml 的实现,其实更多是 xml 的解析工作量,核心流程已经全部实现。
包含了对于 java bean 的基本信息抽象。
- BeanDefinition.java
其默认实现为DefaultBeanDefinition.java,就是对接口实现的最基本的 java POJO
/** * 对象定义属性 * @author binbin.hou * @since 0.0.1 */publicinterfaceBeanDefinition {/** * 名称 * @return 名称 * @since 0.0.1 */StringgetName();/** * 设置名称 * @param name 名称 * @since 0.0.1 */voidsetName(finalStringname);/** * 类名称 * @return 类名称 */StringgetClassName();/** * 设置类名称 * @param className 类名称 * @since 0.0.1 */voidsetClassName(finalStringclassName);}
- BeanFactory.java
/** * bean 工厂接口 * @author binbin.hou * @since 0.0.1 */publicinterfaceBeanFactory {/** * 根据名称获取对应的实例信息 * @param beanName bean 名称 * @return 对象信息 * @since 0.0.1 */ObjectgetBean(finalStringbeanName);/** * 获取指定类型的实现 * @param beanName 属性名称 * @param tClass 类型 * @param <T> 泛型 * @return 结果 * @since 0.0.1 */ <T>TgetBean(finalStringbeanName,finalClass<T>tClass);}
- DefaultBeanFactory.java
为接口最基础的实现,源码如下:
/** * bean 工厂接口 * @author binbin.hou * @since 0.0.1 */publicclassDefaultBeanFactoryimplementsBeanFactory {/** * 对象信息 map * @since 0.0.1 */privateMap<String,BeanDefinition>beanDefinitionMap =newConcurrentHashMap<>();/** * 对象 map * @since 0.0.1 */privateMap<String,Object>beanMap =newConcurrentHashMap<>();/** * 注册对象定义信息 * @since 0.0.1 */protectedvoidregisterBeanDefinition(finalStringbeanName,finalBeanDefinitionbeanDefinition) {// 这里可以添加监听器this.beanDefinitionMap.put(beanName,beanDefinition); }@OverridepublicObjectgetBean(StringbeanName) {Objectbean =beanMap.get(beanName);if(ObjectUtil.isNotNull(bean)) {// 这里直接返回的是单例,如果用户指定为多例,则每次都需要新建。returnbean; }// 获取对应配置信息BeanDefinitionbeanDefinition =beanDefinitionMap.get(beanName);if(ObjectUtil.isNull(beanDefinition)) {thrownewIocRuntimeException(beanName +" not exists in bean define."); }// 直接根据ObjectnewBean =createBean(beanDefinition);// 这里可以添加对应的监听器beanMap.put(beanName,newBean);returnnewBean; }/** * 根据对象定义信息创建对象 * @param beanDefinition 对象定义信息 * @return 创建的对象信息 * @since 0.0.1 */privateObjectcreateBean(finalBeanDefinitionbeanDefinition) {StringclassName =beanDefinition.getClassName();Classclazz =ClassUtils.getClass(className);returnClassUtils.newInstance(clazz); }@Override@SuppressWarnings("unchecked")public <T>TgetBean(StringbeanName,Class<T>tClass) {Objectobject =getBean(beanName);return (T)object; }}
其中 ClassUtils 是基于 class 的反射工具类,详情见ClassUtils.java
基于 json 配置文件实现的基本实现,使用方式见开始种的例子代码。
- JsonApplicationContext.java
/** * JSON 应用上下文 * @author binbin.hou * @since 0.0.1 */publicclassJsonApplicationContextextendsDefaultBeanFactory {/** * 文件名称 * @since 0.0.1 */privatefinalStringfileName;publicJsonApplicationContext(StringfileName) {this.fileName =fileName;// 初始化配置this.init(); }/** * 初始化配置相关信息 * * <pre> * new TypeReference<List<BeanDefinition>>(){} * </pre> * * 读取文件:https://blog.csdn.net/feeltouch/article/details/83796764 * @since 0.0.1 */privatevoidinit() {InputStreamis =Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);finalStringjsonConfig =FileUtil.getFileContent(is);List<DefaultBeanDefinition>beanDefinitions =JsonBs.deserializeArray(jsonConfig,DefaultBeanDefinition.class);if(CollectionUtil.isNotEmpty(beanDefinitions)) {for (BeanDefinitionbeanDefinition :beanDefinitions) {super.registerBeanDefinition(beanDefinition.getName(),beanDefinition); } } }}
至此,一个最基本的 spring ioc 就基本实现了。
如果你想继续学习,可以分别参考以下代码分支。
v0.0.6-构造器和 factoryMethod 新建对象
v0.0.8-Aware 监听器及 PostProcessor
v0.1.1-@Configuration-java 代码配置
v0.1.3-@Lazy-@Scope-java 对象属性配置
v0.1.5-@Bean 参数构造以及 @Description
v0.1.9-Environment 和 @Profile 实现
v0.1.10-Property 配置文件相关和 @Value/@PropertyResource 实现
About
The java ioc framework(从零开始手写模拟 spring Ioc 框架)
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Packages0
Uh oh!
There was an error while loading.Please reload this page.