深入探究getBeansOfType

一、定義與作用

getBeansOfType是Spring Framework框架中定義的一個方法,用於獲取指定類型的所有Bean實例。

在Spring應用程序中,Bean需要通過IoC容器才能被創建。在IoC容器初始化後,我們可以使用getBeansOfType方法獲取指定類型的所有Bean實例,例如:

Map<String, User> usersMap = applicationContext.getBeansOfType(User.class);

這個方法返回一個Map,其中Key表示Bean名稱,Value表示Bean實例。

二、方法參數

getBeansOfType方法有一個必需的參數,用於指定需要獲取Bean的類型,例如:

Map<String, User> usersMap = applicationContext.getBeansOfType(User.class);

除此之外,該方法還有一個可選的參數,用於是否包括非單例Bean。默認情況下,該參數為true,表示包括非單例Bean;如果該參數為false,表示僅包括單例Bean。

Map<String, User> usersMap = applicationContext.getBeansOfType(User.class, false);

通過指定參數為false,我們可以避免獲取非單例Bean,降低應用程序的內存佔用。

三、方法實現

getBeansOfType方法的實現主要是通過調用IoC容器的getBeanNamesForType方法獲取指定類型的所有Bean的名稱,之後根據名稱獲取Bean實例。

@Override
public <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException {
    Assert.notNull(type, "Type must not be null");
    Map<String, T> result = new LinkedHashMap<>();
    boolean isFactoryType = (type != null && FactoryBean.class.isAssignableFrom(type));
    if (!isFactoryType && !this.allowEagerClassLoading) {
        ClassLoader cl = ClassUtils.getDefaultClassLoader();
        if (cl != this.beanClassLoader && cl instanceof SmartClassLoader) {
            for (String name : ((SmartClassLoader) cl).getClassPathResourceUrls("")) {
                this.knownPackagePaths.add(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + name);
            }
            this.beanClassLoader = cl;
        }
    }

    List<String> beanNames = new ArrayList<>();

    // 獲取指定類型的Bean的名稱
    for (String name : this.beanDefinitionNames) {
        if (!name.startsWith(FACTORY_BEAN_PREFIX)) {
            try {
                RootBeanDefinition mbd = getBeanDefinition(name);
                Class<?> beanType = mbd.getTargetType();

                if (beanType != null && (matchBeanType(type, beanType) ||
                        (isFactoryType && FactoryBean.class.isAssignableFrom(beanType))) &&
                        (!mbd.isAbstract() || getBeanFactory().getBeanClassLoader().getResource(mbd.getBeanClassName()) != null) &&
                        (!(mbd instanceof ScopedProxyBeanDefinition) || !((ScopedProxyBeanDefinition) mbd).isTargetBean())) {
                    beanNames.add(name);
                }
            }
            catch (CannotLoadBeanClassException ex) {
                if (allowEagerInit) {
                    throw ex;
                }
                // Probably contains a placeholder => ignore it for type matching purposes.
                if (logger.isTraceEnabled()) {
                    logger.trace("Ignoring bean class loading failure for bean '" + name + "'", ex);
                }
                onSuppressedException(ex);
            }
            catch (Throwable ex) {
                if (allowEagerInit) {
                    throw new BeanCreationException(name, "Instantiation of bean failed", ex);
                }
                if (logger.isTraceEnabled()) {
                    logger.trace("Failed to check candidate bean '" + name + "' for type match", ex);
                }
                onSuppressedException(ex);
            }
        }
    }

    // 根據Bean名稱獲取Bean實例
    for (String beanName : beanNames) {
        if (!ScopedProxyUtils.isScopedTarget(beanName)) {
            try {
                boolean isFactoryBean = isFactoryBean(beanName);
                if (includeNonSingletons || isSingleton(beanName, isFactoryBean)) {
                    Object beanInstance = getBean(beanName);
                    if (beanType.isInstance(beanInstance)) {
                        result.put(beanName, (T) beanInstance);
                    }
                    else if (isFactoryBean && beanType.isInstance(getObjectFromFactoryBean(beanInstance, beanName))) {
                        result.put(beanName, (T) getObjectFromFactoryBean(beanInstance, beanName));
                    }
                }
            }
            catch (BeanInstantiationException ex) {
                throw new BeanCreationException(beanName, "InstantiationException trying to instantiate [" + type + "]", ex);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Could not instantiate [" + type + "] using constructor " + ex, ex);
            }
        }
    }

    return result;
}

四、方法應用場景

getBeansOfType方法可以應用於多種場景,例如:

1、批量處理

我們可以使用getBeansOfType方法獲取所有的處理器實例,並對它們進行批量處理,例如:

Map<String, Handler> handlers = applicationContext.getBeansOfType(Handler.class);
for (Handler handler : handlers.values()) {
    handler.handle();
}

2、動態代理

如果一個類型有多種不同實現,我們可以使用getBeansOfType方法獲取所有實現,並通過動態代理來調用對應實現,例如:

public class ProxyHandler implements InvocationHandler {
    private Map<String, Handler> handlers;
    public ProxyHandler(Map<String, Handler> handlers) {
        this.handlers = handlers;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        for (Handler handler : handlers.values()) {
            if (method.getDeclaringClass().isAssignableFrom(handler.getClass())) {
                return method.invoke(handler, args);
            }
        }
        return null;
    }
}
Map<String, Handler> handlers = applicationContext.getBeansOfType(Handler.class);
Handler handler = (Handler) Proxy.newProxyInstance(
        Thread.currentThread().getContextClassLoader(),
        new Class<?>[]{Handler.class}, new ProxyHandler(handlers));
handler.handle();

3、統計信息

我們可以使用getBeansOfType方法獲取所有指定類型Bean的實例,並統計它們的狀態信息,例如:

@Component
public class Statistics {
    public void print() {
        Map<String, Status> statusMap = new HashMap<>();
        Map<String, Handler> handlers = applicationContext.getBeansOfType(Handler.class);
        for (Handler handler : handlers.values()) {
            Status status = handler.getStatus();
            if (statusMap.containsKey(status.getName())) {
                statusMap.get(status.getName()).addCount(status.getCount());
            } else {
                statusMap.put(status.getName(), status);
            }
        }
        for (Status status : statusMap.values()) {
            System.out.println(status.getName() + " count: " + status.getCount());
        }
    }
}

原創文章,作者:TPHNP,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/335069.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
TPHNP的頭像TPHNP
上一篇 2025-02-05 13:06
下一篇 2025-02-05 13:06

相關推薦

  • 深入解析Vue3 defineExpose

    Vue 3在開發過程中引入了新的API `defineExpose`。在以前的版本中,我們經常使用 `$attrs` 和` $listeners` 實現父組件與子組件之間的通信,但…

    編程 2025-04-25
  • 深入理解byte轉int

    一、字節與比特 在討論byte轉int之前,我們需要了解字節和比特的概念。字節是計算機存儲單位的一種,通常表示8個比特(bit),即1字節=8比特。比特是計算機中最小的數據單位,是…

    編程 2025-04-25
  • 深入理解Flutter StreamBuilder

    一、什麼是Flutter StreamBuilder? Flutter StreamBuilder是Flutter框架中的一個內置小部件,它可以監測數據流(Stream)中數據的變…

    編程 2025-04-25
  • 深入探討OpenCV版本

    OpenCV是一個用於計算機視覺應用程序的開源庫。它是由英特爾公司創建的,現已由Willow Garage管理。OpenCV旨在提供一個易於使用的計算機視覺和機器學習基礎架構,以實…

    編程 2025-04-25
  • 深入了解scala-maven-plugin

    一、簡介 Scala-maven-plugin 是一個創造和管理 Scala 項目的maven插件,它可以自動生成基本項目結構、依賴配置、Scala文件等。使用它可以使我們專註於代…

    編程 2025-04-25
  • 深入了解LaTeX的腳註(latexfootnote)

    一、基本介紹 LaTeX作為一種排版軟件,具有各種各樣的功能,其中腳註(footnote)是一個十分重要的功能之一。在LaTeX中,腳註是用命令latexfootnote來實現的。…

    編程 2025-04-25
  • 深入理解Python字符串r

    一、r字符串的基本概念 r字符串(raw字符串)是指在Python中,以字母r為前綴的字符串。r字符串中的反斜杠(\)不會被轉義,而是被當作普通字符處理,這使得r字符串可以非常方便…

    編程 2025-04-25
  • 深入了解Python包

    一、包的概念 Python中一個程序就是一個模塊,而一個模塊可以引入另一個模塊,這樣就形成了包。包就是有多個模塊組成的一個大模塊,也可以看做是一個文件夾。包可以有效地組織代碼和數據…

    編程 2025-04-25
  • 深入探討馮諾依曼原理

    一、原理概述 馮諾依曼原理,又稱“存儲程序控制原理”,是指計算機的程序和數據都存儲在同一個存儲器中,並且通過一個統一的總線來傳輸數據。這個原理的提出,是計算機科學發展中的重大進展,…

    編程 2025-04-25
  • 深入剖析MapStruct未生成實現類問題

    一、MapStruct簡介 MapStruct是一個Java bean映射器,它通過註解和代碼生成來在Java bean之間轉換成本類代碼,實現類型安全,簡單而不失靈活。 作為一個…

    編程 2025-04-25

發表回復

登錄後才能評論