估計很多朋友使用 spring 很長時間,對于 spring 使用非常頻繁,實際上對于原始碼一直沒有靜下心來學習過,
你是不是有這樣的感覺呢?
但是 spring 原始碼存在一個問題,那就是過于抽象,導致學習起來成本上升,所以本文由淺入深,只實作 spring 的核心功能,便于自己和他人學習 spring 的核心原理,
文章有點長,耐心閱讀!如果對你有幫助,記得三連哦!

spring 的核心
Spring 的核心就是 spring-beans,后面的一切 spring-boot,spring-cloud 都是建立在這個地基之上,
當別人問你 spring 的時候,希望你可以談談自己對于 spring ioc 自己更深層的見解,而不是網上人云亦云的幾句話,
另外本人整理收藏了20年多家公司面試知識點整理 ,以及各種Java核心知識點免費分享給大家,下方只是部分截圖
想要資料的話也可以點擊直接進入:暗號:csdn,免費獲取,

什么是 IOC
控制反轉(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);
}
@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 的反射工具類
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);
}
}
}
}
小結
至此,一個最基本的 spring ioc 就基本實作了,
學海無涯,我們一起勉力前行!
Ps:有需要的小伙伴可以點擊直接進入:暗號:csdn,免費獲取,
面試專題檔案,

技術檔案

真實大廠面經

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/197277.html
標籤:java
