一、定义与作用
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