從零實(shí)現(xiàn)一個(gè)簡單的Spring Bean容器的代碼案例
Spring是一個(gè)非常流行的Java Web開發(fā)框架,它提供了強(qiáng)大的依賴注入、面向切面編程、聲明式事務(wù)管理等功能,為開發(fā)者提供了高效、快速地構(gòu)建 Web 應(yīng)用程序的工具。
最近在學(xué)習(xí)Spring這個(gè)框架源碼時(shí),我明白我們不僅需要掌握其基本使用方法,還應(yīng)該深入了解其內(nèi)部實(shí)現(xiàn)原理。本博文將會(huì)帶領(lǐng)大家一步一步地實(shí)現(xiàn)一個(gè)簡單的 Spring Bean 容器,涉及到容器接口和實(shí)現(xiàn)、Bean的定義和注冊、Bean的依賴注入、Bean的生命周期管理等多個(gè)方面,旨在幫助讀者更加深入地理解Spring內(nèi)部的運(yùn)行機(jī)制。
如果你想更加深入地了解Spring框架的內(nèi)部原理,或者想從零開始手動(dòng)實(shí)現(xiàn)一個(gè)簡單的Spring Bean容器的話,歡迎以后一起學(xué)習(xí)探討,共同進(jìn)步!
在這篇文章中,放松心情,提高興趣,咱們將一步一步地構(gòu)建一個(gè)簡單的Spring Bean容器,包括如下內(nèi)容:
- 容器接口和實(shí)現(xiàn)
- Bean 的定義和注冊
- Bean 的依賴注入
- Bean 的生命周期管理
1. 容器接口和實(shí)現(xiàn)
我們先定義一個(gè)容器接口 BeanFactory,包含三個(gè)方法:獲取 Bean、注冊 Bean、是否包含 Bean。
public interface BeanFactory {
Object getBean(String name);
void registerBean(String name, Object bean);
boolean containsBean(String name);
}然后,我們可以編寫一個(gè)簡單的實(shí)現(xiàn) SimpleBeanFactory。這個(gè)實(shí)現(xiàn)采用了一個(gè) Map<String, Object> 來存儲(chǔ) Bean,其中鍵為 Bean 名稱,值為 Bean 實(shí)例。
public class SimpleBeanFactory implements BeanFactory {
private final Map<String, Object> beans = new HashMap<>();
@Override
public Object getBean(String name) {
return beans.get(name);
}
@Override
public void registerBean(String name, Object bean) {
beans.put(name, bean);
}
@Override
public boolean containsBean(String name) {
return beans.containsKey(name);
}
}2. Bean 的定義和注冊
在 Spring 中,Bean 是通過 XML 或注解來定義的。但是我們這里為了簡化,還是采用常規(guī)的方式來定義和注冊 Bean。
我們定義一個(gè) BeanDefinition 類,用于保存 Bean 的定義信息。其中包含了 Bean 的名稱、類型、構(gòu)造函數(shù)參數(shù)、屬性等。
public class BeanDefinition {
private final Class<?> type;
private final Object[] constructorArgs;
private final Map<String, Object> properties = new HashMap<>();
public BeanDefinition(Class<?> type, Object[] constructorArgs) {
this.type = type;
this.constructorArgs = constructorArgs;
}
public void setProperty(String name, Object value) {
properties.put(name, value);
}
public Class<?> getType() {
return type;
}
public Object[] getConstructorArgs() {
return constructorArgs;
}
public Map<String, Object> getProperties() {
return properties;
}
}我們可以編寫一個(gè)簡單的類 BeanDefinitionReader,用于從配置文件中讀取 Bean 定義信息,并將其轉(zhuǎn)換成 BeanDefinition 對(duì)象。
public class BeanDefinitionReader {
private final ResourceLoader resourceLoader;
public BeanDefinitionReader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public List<BeanDefinition> readBeanDefinitions(String location) throws Exception {
InputStream inputStream = resourceLoader.getResource(location).getInputStream();
Properties props = new Properties();
props.load(inputStream);
List<BeanDefinition> result = new ArrayList<>();
for (Map.Entry<Object, Object> entry : props.entrySet()) {
String name = (String) entry.getKey();
String[] args = ((String) entry.getValue()).split(",");
Class<?> type = Class.forName(args[0]);
Object[] constructorArgs = new Object[args.length - 1];
for (int i = 1; i < args.length; i++) {
constructorArgs[i - 1] = args[i];
}
BeanDefinition beanDefinition = new BeanDefinition(type, constructorArgs);
result.add(beanDefinition);
}
return result;
}
}我們可以在配置文件中定義 Bean,比如:
userService=com.example.UserService,dao
表示我們要?jiǎng)?chuàng)建一個(gè)名為 userService 的 Bean,類型為 com.example.UserService,構(gòu)造函數(shù)參數(shù)為一個(gè)類型為 dao 的字符串。這個(gè)字符串可以用來表示依賴的其他 Bean。
然后,我們可以編寫一個(gè)簡單的類 BeanDefinitionRegistry,用于管理所有的 BeanDefinition,并提供一些注冊方法。
public interface BeanDefinitionRegistry {
void registerBeanDefinition(String name, BeanDefinition beanDefinition);
BeanDefinition getBeanDefinition(String name);
}3. Bean 的依賴注入
在 Spring 中,Bean 的依賴注入主要通過構(gòu)造函數(shù)或?qū)傩赃M(jìn)行注入。這里我們先實(shí)現(xiàn)屬性注入。
我們可以編寫一個(gè)簡單的類 BeanFactoryPostProcessor,用于在 Bean 實(shí)例化之前,對(duì) Bean 的定義信息進(jìn)行修改。在這個(gè)方法中,我們可以將依賴的其他 Bean 注入到當(dāng)前 Bean 的屬性中。
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(DefaultListableBeanFactory beanFactory);
}
public class DefaultListableBeanFactory implements BeanFactory {
private final Map<String, BeanDefinition> beanDefinitions = new HashMap<>();
private final Map<String, Object> beans = new HashMap<>();
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
// TODO: addBeanPostProcessor
}
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {
beanFactoryPostProcessor.postProcessBeanFactory(this);
}
public void preInstantiateSingletons() {
// TODO: preInstantiateSingletons
}
@Override
public Object getBean(String name) throws Exception {
// TODO: getBean
}
@Override
public void registerBean(String name, Object bean) {
beans.put(name, bean);
}
@Override
public boolean containsBean(String name) {
return beans.containsKey(name);
}
}
public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor {
private final BeanFactory beanFactory;
public AutowiredAnnotationBeanPostProcessor(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
// TODO: postProcessBeforeInitialization
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
// TODO: postProcessAfterInitialization
}
}4. Bean 的生命周期管理
在 Spring 中,Bean 的生命周期是由容器來管理的。在創(chuàng)建某個(gè) Bean 之前,容器會(huì)先調(diào)用它的 postProcessBeforeInitialization 方法對(duì)其進(jìn)行修改,而在銷毀它時(shí),容器會(huì)調(diào)用其 destroy 方法。
我們可以在 BeanDefinition 類中添加一些方法,用于實(shí)現(xiàn) Bean 的生命周期管理,比如 initMethod 和 destroyMethod。
public class BeanDefinition {
private final Class<?> type;
private final Object[] constructorArgs;
private final Map<String, Object> properties = new HashMap<>();
private String initMethod;
private String destroyMethod;
public void setInitMethod(String initMethod) {
this.initMethod = initMethod;
}
public void setDestroyMethod(String destroyMethod) {
this.destroyMethod = destroyMethod;
}
public Class<?> getType() {
return type;
}
public Object[] getConstructorArgs() {
return constructorArgs;
}
public Map<String, Object> getProperties() {
return properties;
}
public void init(Object bean) throws Exception {
if (initMethod != null) {
Method method = bean.getClass().getMethod(initMethod);
method.invoke(bean);
}
}
public void destroy(Object bean) throws Exception {
if (destroyMethod != null) {
Method method = bean.getClass().getMethod(destroyMethod);
method.invoke(bean);
}
}
}然后,我們可以在 DefaultListableBeanFactory 類中添加一些方法,用于實(shí)現(xiàn) Bean 的生命周期管理。
public class DefaultListableBeanFactory implements BeanFactory, BeanDefinitionRegistry {
private final Map<String, BeanDefinition> beanDefinitions = new HashMap<>();
private final Map<String, Object> beans = new HashMap<>();
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
// TODO: addBeanPostProcessor
}
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {
beanFactoryPostProcessor.postProcessBeanFactory(this);
}
public void preInstantiateSingletons() throws Exception {
for (Map.Entry<String, BeanDefinition> entry : beanDefinitions.entrySet()) {
String beanName = entry.getKey();
BeanDefinition beanDefinition = entry.getValue();
if (!beanDefinition.getType().isInterface()) {
Object bean = createBean(beanName, beanDefinition);
registerBean(beanName, bean);
beanDefinition.init(bean);
}
}
}
@Override
public Object getBean(String name) throws Exception {
// TODO: getBean
}
@Override
public void registerBean(String name, BeanDefinition beanDefinition) {
beanDefinitions.put(name, beanDefinition);
}
@Override
public BeanDefinition getBeanDefinition(String name) {
return beanDefinitions.get(name);
}
@Override
public boolean containsBean(String name) {
return beans.containsKey(name);
}
private Object createBean(String name, BeanDefinition beanDefinition) throws Exception {
Class<?> beanClass = beanDefinition.getType();
Object[] constructorArgs = beanDefinition.getConstructorArgs();
if (constructorArgs == null) {
return beanClass.newInstance();
}
List<Object> objects = new ArrayList<>();
for (Object arg : constructorArgs) {
if (arg instanceof String) {
objects.add(getBean((String) arg));
} else {
objects.add(arg);
}
}
Constructor<?> constructor = beanClass.getConstructor(constructorArgs.getClass());
return constructor.newInstance(objects.toArray());
}
}5. 總結(jié)
通過以上的步驟,我們可以簡單地實(shí)現(xiàn)了一個(gè) Spring Bean 容器。雖然這個(gè)容器不具備 Spring 的完整的功能和特性,但是對(duì)于初學(xué)者或者想深入了解 Spring 內(nèi)部原理的開發(fā)者而言,本文提供了一個(gè)簡易的參考實(shí)現(xiàn)。
在實(shí)現(xiàn)過程中,我們涉及了容器接口和實(shí)現(xiàn)、Bean 的定義和注冊、Bean 的依賴注入、Bean 的生命周期管理等多個(gè)方面。通過不斷地切分和優(yōu)化問題,我們逐步向著完整的 Spring 功能逼近,也更加深入地了解了 Spring 內(nèi)部的運(yùn)行機(jī)制。
當(dāng)然,在實(shí)際使用 Spring 框架時(shí),我們可以直接使用 Spring 自帶的 Bean 容器,通過 XML 或者注解來配置和管理 Bean。但是通過手動(dòng)實(shí)現(xiàn)一個(gè)簡單的 Bean 容器,我們可以更加深入地理解 Spring 內(nèi)部的運(yùn)行機(jī)制,這對(duì)于我們?nèi)蘸箝_發(fā)、維護(hù)和擴(kuò)展 Spring 應(yīng)用程序都具有重要意義。
以上就是從零實(shí)現(xiàn)一個(gè)簡單的SpringBean容器的代碼案例的詳細(xì)內(nèi)容,更多關(guān)于實(shí)現(xiàn)Spring Bean容器的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JAVA中NIO的技術(shù)原理及SpringBoot代碼實(shí)例詳解
Java NIO(Non-blocking I/O)是Java1.4引入的非阻塞I/O API,通過Channel、Buffer和Selector實(shí)現(xiàn)高效、低延遲的異步文件傳輸,適用于高并發(fā)服務(wù)器端場景,本文給大家介紹JAVA中NIO的技術(shù)原理及SpringBoot代碼實(shí)例,感興趣的朋友一起看看吧2025-10-10
關(guān)于springcloud集成nacos遇到的問題
這篇文章主要介紹了關(guān)于springcloud集成nacos遇到的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
Eolink上傳文件到Java后臺(tái)進(jìn)行處理的示例代碼
這篇文章主要介紹了Eolink上傳文件到Java后臺(tái)進(jìn)行處理,這里是上傳的excel表格數(shù)據(jù)并轉(zhuǎn)換為java集合對(duì)象、然后進(jìn)行業(yè)務(wù)邏輯處理判斷最后保存到數(shù)據(jù)庫?,需要的朋友可以參考下2022-12-12
SpringBoot完整實(shí)現(xiàn)滑塊拼圖驗(yàn)證+軌跡驗(yàn)證+Redis分布式方案
滑塊拼圖驗(yàn)證是一種行為驗(yàn)證技術(shù),通過要求用戶將拼圖塊拖動(dòng)到正確位置來區(qū)分人類用戶和自動(dòng)化程序,本文介紹SpringBoot完整實(shí)現(xiàn)滑塊拼圖驗(yàn)證+軌跡驗(yàn)證+Redis分布式方案,感興趣的朋友跟隨小編一起看看吧2026-03-03
Java實(shí)現(xiàn)導(dǎo)出合并Excel單元格
隨著數(shù)據(jù)的不斷增長,很多時(shí)候需要將數(shù)據(jù)導(dǎo)出到Excel中進(jìn)行分析、處理和展示。本文將介紹如何使用Java實(shí)現(xiàn)Excel導(dǎo)出,并且可以合并單元格,需要的可以參考一下2023-04-04
Java參數(shù)校驗(yàn)詳解之使用@Valid注解和自定義注解進(jìn)行參數(shù)驗(yàn)證
在后端開發(fā)中,參數(shù)校驗(yàn)是非常普遍的,下面這篇文章主要給大家介紹了關(guān)于Java參數(shù)校驗(yàn)詳解之使用@Valid注解和自定義注解進(jìn)行參數(shù)驗(yàn)證的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06

