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 主要是如下幾個步驟。
BeanDefinition 是 spring 對 java bean 屬性的一個抽象,通過這一層抽象,配置文件能夠是 xml/json/properties/yaml 等任意一種,甚至包括註解掃包。
爲 spring 的拓展帶來極大的靈活性。
本框架考慮到實現的簡單性,初步只實現了 json 和基於註解掃包兩種方式。
後期若是有時間能夠考慮添加 xml 的實現,其實更可能是 xml 的解析工做量,核心流程已經所有實現。
包含了對於 java bean 的基本信息抽象。
其默認實現爲 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); }
/** * 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 文件包掃描支持