Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理。java
使用 spring 很长时间,对于 spring 使用很是频繁,实际上对于源码一直没有静下心来学习过。git
可是 spring 源码存在一个问题,那就是过于抽象,致使学习起来成本上升。github
因此本项目由渐入深,只实现 spring 的核心功能,便于本身和他人学习 spring 的核心原理。spring
Spring 的核心就是 spring-beans,后面的一切 spring-boot,spring-cloud 都是创建在这个地基之上。编程
当别人问你 spring 的时候,但愿你能够谈谈本身对于 spring ioc 本身更深层的看法,而不是网上人云亦云的几句话。json
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,能够用来减低计算机代码之间的耦合度。数据结构
其中最多见的方式叫作依赖注入(Dependency Injection,简称DI)。app
经过控制反转,对象在被建立的时候,由一个调控系统内全部对象的外界实体,将其所依赖的对象的引用传递给它。框架
也能够说,依赖被注入到对象中。maven
IoC 是解耦的一种方法。
咱们知道Java 是一门面向对象的语言,在 Java 中 Everything is Object,咱们的程序就是由若干对象组成的。
当咱们的项目愈来愈大,合做的开发者愈来愈多的时候,咱们的类就会愈来愈多,类与类之间的引用就会成指数级的增加。
这样的工程简直就是灾难,若是咱们引入 Ioc 框架。
由框架来维护类的生命周期和类之间的引用。
咱们的系统就会变成这样:
这个时候咱们发现,咱们类之间的关系都由 IoC 框架负责维护类,同时将类注入到须要的类中。
也就是类的使用者只负责使用,而不负责维护。
把专业的事情交给专业的框架来完成,大大的减小开发的复杂度。
<dependency> <groupId>com.github.houbb</groupId> <artifactId>ioc</artifactId> <version>0.1.11</version> </dependency>
所有测试代码,见 test 模块。
public class Apple { public void color() { System.out.println("Apple color: red. "); } }
相似于 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-beans 一切都是围绕 bean 展开的。
BeanFactory 负责对 bean 进行生命周期的相关管理,本节展现第一小节的简单实现流程。
Spring IoC 主要是如下几个步骤。
初始化 IoC 容器。
读取配置文件。
将配置文件转换为容器识别对的数据结构(这个数据结构在Spring中叫作 BeanDefinition)
利用数据结构依次实例化相应的对象
BeanDefinition 是 spring 对 java bean 属性的一个抽象,通过这一层抽象,配置文件能够是 xml/json/properties/yaml 等任意一种,甚至包括注解扫包。
为 spring 的拓展带来极大的灵活性。
本框架考虑到实现的简单性,初步只实现了 json 和基于注解扫包两种方式。
后期若是有时间能够考虑添加 xml 的实现,其实更可能是 xml 的解析工做量,核心流程已经所有实现。
包含了对于 java bean 的基本信息抽象。
其默认实现为 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); }
/** * 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); }
为接口最基础的实现,源码以下:
/** * 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
基于 json 配置文件实现的基本实现,使用方式见开始种的例子代码。
/** * 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.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 实现
v0.1.11-@ComponentScan 文件包扫描支持