深入探究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/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

发表回复

登录后才能评论