Ioc 是一款 spring ioc 核心功能簡(jiǎn)化實(shí)現(xiàn)版本,便于學(xué)習(xí)和理解原理。
我們提供的服務(wù)有:成都做網(wǎng)站、成都網(wǎng)站建設(shè)、微信公眾號(hào)開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、明溪ssl等。為上1000+企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的明溪網(wǎng)站制作公司
使用 spring 很長(zhǎng)時(shí)間,對(duì)于 spring 使用非常頻繁,實(shí)際上對(duì)于源碼一直沒有靜下心來學(xué)習(xí)過。
但是 spring 源碼存在一個(gè)問題,那就是過于抽象,導(dǎo)致學(xué)習(xí)起來成本上升。
所以本項(xiàng)目由漸入深,只實(shí)現(xiàn) spring 的核心功能,便于自己和他人學(xué)習(xí) spring 的核心原理。
Spring 的核心就是 spring-beans,后面的一切 spring-boot,spring-cloud 都是建立在這個(gè)地基之上。
當(dāng)別人問你 spring 的時(shí)候,希望你可以談?wù)勛约簩?duì)于 spring ioc 自己更深層的見解,而不是網(wǎng)上人云亦云的幾句話。
控制反轉(zhuǎn)(Inversion of Control,縮寫為IoC),是面向?qū)ο缶幊讨械囊环N設(shè)計(jì)原則,可以用來減低計(jì)算機(jī)代碼之間的耦合度。
其中最常見的方式叫做依賴注入(Dependency Injection,簡(jiǎn)稱DI)。
通過控制反轉(zhuǎn),對(duì)象在被創(chuàng)建的時(shí)候,由一個(gè)調(diào)控系統(tǒng)內(nèi)所有對(duì)象的外界實(shí)體,將其所依賴的對(duì)象的引用傳遞給它。
也可以說,依賴被注入到對(duì)象中。
IoC 是解耦的一種方法。
我們知道Java 是一門面向?qū)ο蟮恼Z言,在 Java 中 Everything is Object,我們的程序就是由若干對(duì)象組成的。
當(dāng)我們的項(xiàng)目越來越大,合作的開發(fā)者越來越多的時(shí)候,我們的類就會(huì)越來越多,類與類之間的引用就會(huì)成指數(shù)級(jí)的增長(zhǎng)。
這樣的工程簡(jiǎn)直就是災(zāi)難,如果我們引入 Ioc 框架。
由框架來維護(hù)類的生命周期和類之間的引用。
我們的系統(tǒng)就會(huì)變成這樣:
這個(gè)時(shí)候我們發(fā)現(xiàn),我們類之間的關(guān)系都由 IoC 框架負(fù)責(zé)維護(hù)類,同時(shí)將類注入到需要的類中。
也就是類的使用者只負(fù)責(zé)使用,而不負(fù)責(zé)維護(hù)。
把專業(yè)的事情交給專業(yè)的框架來完成,大大的減少開發(fā)的復(fù)雜度。
com.github.houbb
ioc
0.1.11
全部測(cè)試代碼,見 test 模塊。
public class Apple {
public void color() {
System.out.println("Apple color: red. ");
}
}
類似于 xml 的配置,我們暫時(shí)使用 json 進(jìn)行配置驗(yàn)證。
[
{"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 負(fù)責(zé)對(duì) bean 進(jìn)行生命周期的相關(guān)管理,本節(jié)展示第一小節(jié)的簡(jiǎn)單實(shí)現(xiàn)流程。
Spring IoC 主要是以下幾個(gè)步驟。
初始化 IoC 容器。
讀取配置文件。
將配置文件轉(zhuǎn)換為容器識(shí)別對(duì)的數(shù)據(jù)結(jié)構(gòu)(這個(gè)數(shù)據(jù)結(jié)構(gòu)在Spring中叫做 BeanDefinition)
利用數(shù)據(jù)結(jié)構(gòu)依次實(shí)例化相應(yīng)的對(duì)象
BeanDefinition 是 spring 對(duì) java bean 屬性的一個(gè)抽象,經(jīng)過這一層抽象,配置文件可以是 xml/json/properties/yaml 等任意一種,甚至包括注解掃包。
為 spring 的拓展帶來極大的靈活性。
本框架考慮到實(shí)現(xiàn)的簡(jiǎn)單性,初步只實(shí)現(xiàn)了 json 和基于注解掃包兩種方式。
后期如果有時(shí)間可以考慮添加 xml 的實(shí)現(xiàn),其實(shí)更多是 xml 的解析工作量,核心流程已經(jīng)全部實(shí)現(xiàn)。
包含了對(duì)于 java bean 的基本信息抽象。
其默認(rèn)實(shí)現(xiàn)為 DefaultBeanDefinition.java
,就是對(duì)接口實(shí)現(xiàn)的最基本的 java POJO
參見 DefaultBeanDefinition
/**
* 對(duì)象定義屬性
* @author binbin.hou
* @since 0.0.1
*/
public interface BeanDefinition {
/**
* 名稱
* @return 名稱
* @since 0.0.1
*/
String getName();
/**
* 設(shè)置名稱
* @param name 名稱
* @since 0.0.1
*/
void setName(final String name);
/**
* 類名稱
* @return 類名稱
*/
String getClassName();
/**
* 設(shè)置類名稱
* @param className 類名稱
* @since 0.0.1
*/
void setClassName(final String className);
}
/**
* bean 工廠接口
* @author binbin.hou
* @since 0.0.1
*/
public interface BeanFactory {
/**
* 根據(jù)名稱獲取對(duì)應(yīng)的實(shí)例信息
* @param beanName bean 名稱
* @return 對(duì)象信息
* @since 0.0.1
*/
Object getBean(final String beanName);
/**
* 獲取指定類型的實(shí)現(xiàn)
* @param beanName 屬性名稱
* @param tClass 類型
* @param 泛型
* @return 結(jié)果
* @since 0.0.1
*/
T getBean(final String beanName, final Class tClass);
}
為接口最基礎(chǔ)的實(shí)現(xiàn),源碼如下:
/**
* bean 工廠接口
* @author binbin.hou
* @since 0.0.1
*/
public class DefaultBeanFactory implements BeanFactory {
/**
* 對(duì)象信息 map
* @since 0.0.1
*/
private Map beanDefinitionMap = new ConcurrentHashMap<>();
/**
* 對(duì)象 map
* @since 0.0.1
*/
private Map beanMap = new ConcurrentHashMap<>();
/**
* 注冊(cè)對(duì)象定義信息
* @since 0.0.1
*/
protected void registerBeanDefinition(final String beanName, final BeanDefinition beanDefinition) {
// 這里可以添加監(jiān)聽器
this.beanDefinitionMap.put(beanName, beanDefinition);
}
@Override
public Object getBean(String beanName) {
Object bean = beanMap.get(beanName);
if(ObjectUtil.isNotNull(bean)) {
// 這里直接返回的是單例,如果用戶指定為多例,則每次都需要新建。
return bean;
}
// 獲取對(duì)應(yīng)配置信息
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if(ObjectUtil.isNull(beanDefinition)) {
throw new IocRuntimeException(beanName + " not exists in bean define.");
}
// 直接根據(jù)
Object newBean = createBean(beanDefinition);
// 這里可以添加對(duì)應(yīng)的監(jiān)聽器
beanMap.put(beanName, newBean);
return newBean;
}
/**
* 根據(jù)對(duì)象定義信息創(chuàng)建對(duì)象
* @param beanDefinition 對(duì)象定義信息
* @return 創(chuàng)建的對(duì)象信息
* @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 getBean(String beanName, Class tClass) {
Object object = getBean(beanName);
return (T)object;
}
}
其中 ClassUtils 是基于 class 的反射工具類,詳情見 ClassUtils.java
基于 json 配置文件實(shí)現(xiàn)的基本實(shí)現(xiàn),使用方式見開始種的例子代碼。
/**
* JSON 應(yīng)用上下文
* @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();
}
/**
* 初始化配置相關(guān)信息
*
*
* new TypeReference>(){}
*
*
* 讀取文件: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 beanDefinitions = JsonBs.deserializeArray(jsonConfig, DefaultBeanDefinition.class);
if(CollectionUtil.isNotEmpty(beanDefinitions)) {
for (BeanDefinition beanDefinition : beanDefinitions) {
super.registerBeanDefinition(beanDefinition.getName(), beanDefinition);
}
}
}
}
至此,一個(gè)最基本的 spring ioc 就基本實(shí)現(xiàn)了。
如果你想繼續(xù)學(xué)習(xí),可以分別參考以下代碼分支。
v0.0.1-BeanFactory 基本實(shí)現(xiàn)
v0.0.2-ListBeanFactory 基本實(shí)現(xiàn)
v0.0.3-單例和延遲加載
v0.0.4-初始化和銷毀方法
v0.0.5-RespCode 添加和代碼優(yōu)化
v0.0.6-構(gòu)造器和 factoryMethod 新建對(duì)象
v0.0.7-property 屬性設(shè)置
v0.0.8-Aware 監(jiān)聽器及 PostProcessor
v0.0.9-Parent 屬性繼承
v0.1.0-循環(huán)依賴檢測(cè)
v0.1.1-@Configuration-java 代碼配置
v0.1.2-@Bean-java 對(duì)象定義
v0.1.3-@Lazy-@Scope-java 對(duì)象屬性配置
v0.1.4-@Import 配置導(dǎo)入
v0.1.5-@Bean 參數(shù)構(gòu)造以及 @Description
v0.1.6-@Autowired 自動(dòng)裝配注解支持
v0.1.7-@Primary 指定優(yōu)先級(jí)注解
v0.1.8-@Conditional 條件注解支持
v0.1.9-Environment 和 @Profile 實(shí)現(xiàn)
v0.1.10-Property 配置文件相關(guān)和 @Value/@PropertyResource 實(shí)現(xiàn)
v0.1.11-@ComponentScan 文件包掃描支持
Java IOC-00-ioc 是什么