您好,登錄后才能下訂單哦!
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 模塊。
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
參見 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.1-BeanFactory 基本實現
v0.0.2-ListBeanFactory 基本實現
v0.0.3-單例和延遲加載
v0.0.4-初始化和銷毀方法
v0.0.5-RespCode 添加和代碼優化
v0.0.6-構造器和 factoryMethod 新建對象
v0.0.7-property 屬性設置
v0.0.8-Aware 監聽器及 PostProcessor
v0.0.9-Parent 屬性繼承
v0.1.0-循環依賴檢測
v0.1.1-@Configuration-java 代碼配置
v0.1.2-@Bean-java 對象定義
v0.1.3-@Lazy-@Scope-java 對象屬性配置
v0.1.4-@Import 配置導入
v0.1.5-@Bean 參數構造以及 @Description
v0.1.6-@Autowired 自動裝配注解支持
v0.1.7-@Primary 指定優先級注解
v0.1.8-@Conditional 條件注解支持
v0.1.9-Environment 和 @Profile 實現
v0.1.10-Property 配置文件相關和 @Value/@PropertyResource 實現
v0.1.11-@ComponentScan 文件包掃描支持
Java IOC-00-ioc 是什么
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。