欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

從零實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Spring Bean容器的代碼案例

 更新時(shí)間:2023年06月01日 08:34:05   作者:Cosolar  
Spring是一個(gè)非常流行的Java?Web開發(fā)框架,它提供了強(qiáng)大的依賴注入、面向切面編程、聲明式事務(wù)管理等功能,為開發(fā)者提供了高效、快速地構(gòu)建Web應(yīng)用程序的工具,在這篇文章中,咱們將一步一步地構(gòu)建一個(gè)簡(jiǎn)單的SpringBean容器,需要的朋友可以參考下

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è)簡(jiǎn)單的 Spring Bean 容器,涉及到容器接口和實(shí)現(xiàn)、Bean的定義和注冊(cè)、Bean的依賴注入、Bean的生命周期管理等多個(gè)方面,旨在幫助讀者更加深入地理解Spring內(nèi)部的運(yùn)行機(jī)制。

如果你想更加深入地了解Spring框架的內(nèi)部原理,或者想從零開始手動(dòng)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Spring Bean容器的話,歡迎以后一起學(xué)習(xí)探討,共同進(jìn)步!

在這篇文章中,放松心情,提高興趣,咱們將一步一步地構(gòu)建一個(gè)簡(jiǎn)單的Spring Bean容器,包括如下內(nèi)容:

  • 容器接口和實(shí)現(xiàn)
  • Bean 的定義和注冊(cè)
  • Bean 的依賴注入
  • Bean 的生命周期管理

1. 容器接口和實(shí)現(xiàn)

我們先定義一個(gè)容器接口 BeanFactory,包含三個(gè)方法:獲取 Bean、注冊(cè) Bean、是否包含 Bean。

public interface BeanFactory {
    Object getBean(String name);
    void registerBean(String name, Object bean);
    boolean containsBean(String name);
}

然后,我們可以編寫一個(gè)簡(jiǎn)單的實(shí)現(xiàn) SimpleBeanFactory。這個(gè)實(shí)現(xiàn)采用了一個(gè) Map<String, Object> 來(lái)存儲(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 的定義和注冊(cè)

在 Spring 中,Bean 是通過(guò) XML 或注解來(lái)定義的。但是我們這里為了簡(jiǎn)化,還是采用常規(guī)的方式來(lái)定義和注冊(cè) 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è)簡(jiǎn)單的類 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è)字符串可以用來(lái)表示依賴的其他 Bean。

然后,我們可以編寫一個(gè)簡(jiǎn)單的類 BeanDefinitionRegistry,用于管理所有的 BeanDefinition,并提供一些注冊(cè)方法。

public interface BeanDefinitionRegistry {
    void registerBeanDefinition(String name, BeanDefinition beanDefinition);
    BeanDefinition getBeanDefinition(String name);
}

3. Bean 的依賴注入

在 Spring 中,Bean 的依賴注入主要通過(guò)構(gòu)造函數(shù)或?qū)傩赃M(jìn)行注入。這里我們先實(shí)現(xiàn)屬性注入。

我們可以編寫一個(gè)簡(jiǎn)單的類 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 的生命周期是由容器來(lái)管理的。在創(chuàng)建某個(gè) Bean 之前,容器會(huì)先調(diào)用它的 postProcessBeforeInitialization 方法對(duì)其進(jìn)行修改,而在銷毀它時(shí),容器會(huì)調(diào)用其 destroy 方法。

我們可以在 BeanDefinition 類中添加一些方法,用于實(shí)現(xiàn) Bean 的生命周期管理,比如 initMethoddestroyMethod。

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é)

通過(guò)以上的步驟,我們可以簡(jiǎn)單地實(shí)現(xiàn)了一個(gè) Spring Bean 容器。雖然這個(gè)容器不具備 Spring 的完整的功能和特性,但是對(duì)于初學(xué)者或者想深入了解 Spring 內(nèi)部原理的開發(fā)者而言,本文提供了一個(gè)簡(jiǎn)易的參考實(shí)現(xiàn)。

在實(shí)現(xiàn)過(guò)程中,我們涉及了容器接口和實(shí)現(xiàn)、Bean 的定義和注冊(cè)、Bean 的依賴注入、Bean 的生命周期管理等多個(gè)方面。通過(guò)不斷地切分和優(yōu)化問(wèn)題,我們逐步向著完整的 Spring 功能逼近,也更加深入地了解了 Spring 內(nèi)部的運(yùn)行機(jī)制。

當(dāng)然,在實(shí)際使用 Spring 框架時(shí),我們可以直接使用 Spring 自帶的 Bean 容器,通過(guò) XML 或者注解來(lái)配置和管理 Bean。但是通過(guò)手動(dòng)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 Bean 容器,我們可以更加深入地理解 Spring 內(nèi)部的運(yùn)行機(jī)制,這對(duì)于我們?nèi)蘸箝_發(fā)、維護(hù)和擴(kuò)展 Spring 應(yīng)用程序都具有重要意義。

以上就是從零實(shí)現(xiàn)一個(gè)簡(jiǎn)單的SpringBean容器的代碼案例的詳細(xì)內(nèi)容,更多關(guān)于實(shí)現(xiàn)Spring Bean容器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • servlet創(chuàng)建web后端程序的示例代碼

    servlet創(chuàng)建web后端程序的示例代碼

    本文主要介紹了servlet創(chuàng)建web后端程序的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • 基于@RequestMapping 用法詳解之地址映射

    基于@RequestMapping 用法詳解之地址映射

    這篇文章主要介紹了@RequestMapping 用法詳解之地址映射,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 基于Java實(shí)現(xiàn)的大樂(lè)透號(hào)碼生成器工具類

    基于Java實(shí)現(xiàn)的大樂(lè)透號(hào)碼生成器工具類

    大樂(lè)透是中國(guó)體育彩票的一種玩法,是國(guó)家體育總局體彩中心為適應(yīng)市場(chǎng)發(fā)展需要。本文為大家準(zhǔn)備了一個(gè)大樂(lè)透號(hào)碼生成器工具類,感興趣的可以了解一下
    2022-08-08
  • java?ResourceBundle讀取properties文件方式

    java?ResourceBundle讀取properties文件方式

    這篇文章主要介紹了java?ResourceBundle讀取properties文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 詳解spring boot配置單點(diǎn)登錄

    詳解spring boot配置單點(diǎn)登錄

    本篇文章主要介紹了詳解spring boot配置單點(diǎn)登錄,常用的安全框架有spring security和apache shiro。shiro的配置和使用相對(duì)簡(jiǎn)單,本文使用shrio對(duì)接CAS服務(wù)。
    2017-03-03
  • Java兩個(gè)List<T> 求交集,差集,并集,去重后的并集

    Java兩個(gè)List<T> 求交集,差集,并集,去重后的并集

    本文主要介紹了Java兩個(gè)List<T> 求交集,差集,并集,去重后的并集,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • Spring?spel獲取自定義注解參數(shù)值方式

    Spring?spel獲取自定義注解參數(shù)值方式

    這篇文章主要介紹了Spring?spel獲取自定義注解參數(shù)值方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • java中DateUtils時(shí)間工具類詳解

    java中DateUtils時(shí)間工具類詳解

    這篇文章主要為大家詳細(xì)介紹了java中DateUtils時(shí)間工具類,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Java項(xiàng)目中防止SQL注入的四種方案總結(jié)

    Java項(xiàng)目中防止SQL注入的四種方案總結(jié)

    SQL注入是一種代碼注入技術(shù),通過(guò)把SQL命令插入到Web表單遞交或輸入域名或頁(yè)面請(qǐng)求的查詢字符串,最終達(dá)到欺騙服務(wù)器執(zhí)行惡意的SQL命令,下面我們就來(lái)看看如何在項(xiàng)目中防止SQL注入吧
    2023-10-10
  • java實(shí)現(xiàn)置換密碼加密解密

    java實(shí)現(xiàn)置換密碼加密解密

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)置換密碼加密解密,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-03-03

最新評(píng)論