一、定義與作用
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