概述
本文作为Spring中如何获取到一个Bean实例(一)?的姊妹篇,我们 对获取bean实例的流程做一些补充说明。
【1】主动获取方式
除了在项目启动过程中,refresh方法过程中spring会自动实例化单例bean并解析bean依赖之外,我们通常可能使用如下两种方式主动获取bean,触发bean实例化过程。
如下所示,分别是根据bean class type以及beanName来获取一个bean实例。
SysUser bean = applicationContext.getBean(SysUser.class);
SysUser bean1 = (SysUser) applicationContext.getBean("myuser");
//根据bean类型
public <T> T getBean(Class<T> requiredType) throws BeansException {}
//根据beanName
public Object getBean(String name) throws BeansException {}
① 根据bean类型
我们分析这个流程:
// AbstractApplicationContext#getBean(java.lang.Class<T>)
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(requiredType);
}
getBean:1126, AbstractApplicationContext (org.springframework.context.support)
getBean:342, DefaultListableBeanFactory (org.springframework.beans.factory.support)
getBean:349, DefaultListableBeanFactory (org.springframework.beans.factory.support)
resolveBean:416, DefaultListableBeanFactory (org.springframework.beans.factory.support)
resolveNamedBean:1155, DefaultListableBeanFactory (org.springframework.beans.factory.support)
getBean:227, AbstractBeanFactory (org.springframework.beans.factory.support)
doGetBean:245, AbstractBeanFactory (org.springframework.beans.factory.support)
② 根据beanName
// AbstractApplicationContext#getBean(java.lang.String)
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
// 然后走到了这里
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
在前面Spring中如何获取到一个Bean实例(一)?我们提到过,这个AbstractBeanFactory
的doGetBean方法就是触发bean实例初始化流程的入口方法。综上可以看出,根据beanName获取bean实例相对很简洁,根据Bean type则要麻烦得多。最终二者都是由doGetBean方法触发了bean的实例化。
【2】根据Bean Type获取bean时如何确定beanName?
这个过程发生在DefaultListableBeanFactory的resolveNamedBean方法中。
private <T> NamedBeanHolder<T> resolveNamedBean(
ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
// 从beanDefinitionNames 和 manualSingletonNames 集合中检测beanName
String[] candidateNames = getBeanNamesForType(requiredType);
// 第一次判断,如果length > 1 ,也就是有多个同样类型的bean,判断是否为候选bean
if (candidateNames.length > 1) {
List<String> autowireCandidates = new ArrayList<>(candidateNames.length);
for (String beanName : candidateNames) {
// 判断beanDefinitionMap是否不包含beanName 或者当前beanName的BeanDefinition中isAutowireCandidate是否为true
if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
autowireCandidates.add(beanName);
}
}
if (!autowireCandidates.isEmpty()) {
candidateNames = StringUtils.toStringArray(autowireCandidates);
}
}
//如果此时候选beanName 只有一个,则直接触发getBean流程
if (candidateNames.length == 1) {
String beanName = candidateNames[0];
return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
}
else if (candidateNames.length > 1) {
Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length);
for (String beanName : candidateNames) {
// 判断一级缓存singletonObjects里面是否有当前beanName
if (containsSingleton(beanName) && args == null) {
Object beanInstance = getBean(beanName);
candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
}
else {
candidates.put(beanName, getType(beanName));
}
}
// 获取标注了primary的bean,如果有多个均标注了@Primary注解则抛出异常
String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());
if (candidateName == null) {
// 如果候选name为空,则尝试判读其@Priority值,如果有多个一样的,则抛出异常
candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
}
// 如果判断Primary Priority后,candidateName 不为null,则获取当前candidateName对应的实例返回
if (candidateName != null) {
Object beanInstance = candidates.get(candidateName);
if (beanInstance == null || beanInstance instanceof Class) {
beanInstance = getBean(candidateName, requiredType.toClass(), args);
}
return new NamedBeanHolder<>(candidateName, (T) beanInstance);
}
// 如果上面没有返回,则抛出异常NoUniqueBeanDefinitionException
if (!nonUniqueAsNull) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
}
}
return null;
}
方法流程梳理如下 :
- 根据beanType从
beanDefinitionNames
和manualSingletonNames
集合中检测beanName - 第一次判断,如果length > 1 ,也就是有多个同样类型的bean,判断是否为候选bean
- 如果此时候选beanName 只有一个,则直接触发getBean流程
- 如果candidateNames length > 1,则触发判断逻辑
- 获取标注了@Primary的bean,如果有多个均标注了@Primary注解则抛出异常,尝试得到唯一一个
- 如果candidateName为空,则尝试判读其@Priority值,如果有多个一样的,则抛出异常
- 如果判断Primary、 Priority后,candidateName 不为null,则获取当前candidateName对应的实例返回
- 如果上面没有返回,则抛出异常NoUniqueBeanDefinitionException
【3】获取RootBeanDefinition
这里我们分析的是AbstractBeanFactory的doGetBean方法中实例化的前置步骤,获取bean定义。
AbstractBeanFactory
的getMergedLocalBeanDefinition
方法如下所示,直接从mergedBeanDefinitions
这个ConcurrentHashMap中获取beanName对应的RootBeanDefinition 。
// AbstractBeanFactory
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);
// AbstractBeanFactory
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
// 本文从这里直接返回
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null && !mbd.stale) {
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
如果mergedBeanDefinitions
中没有呢?那么将会从beanDefinitionMap
中获取,如果beanDefinitionMap
也没有将抛出异常。
// DefaultListableBeanFactory
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
// DefaultListableBeanFactory#getBeanDefinition
@Override
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
BeanDefinition bd = this.beanDefinitionMap.get(beanName);
if (bd == null) {
if (logger.isTraceEnabled()) {
logger.trace("No bean named '" + beanName + "' found in " + this);
}
throw new NoSuchBeanDefinitionException(beanName);
}
return bd;
}
那么getMergedBeanDefinition方法是做什么呢?顾名思义,其将尝试获取得到一个“合并”后的BeanDefinition。也就是说如果当前BeanDefinition有parent,则将二者BeanDefinition合并,拥有同样属性的以child BeanDefinition为主。
综上也可以说明在使用spring的getBean进行bean实例化时,这里不再触发bean定义的加载,其默认在上下文refresh中已经完成了资源的扫描、定位和加载,BeanDefinition存放在DefaultListableBeanFactory中。
最后
以上就是激昂胡萝卜为你收集整理的Spring中如何获取到一个Bean实例(二)?【1】主动获取方式【2】根据Bean Type获取bean时如何确定beanName?【3】获取RootBeanDefinition的全部内容,希望文章能够帮你解决Spring中如何获取到一个Bean实例(二)?【1】主动获取方式【2】根据Bean Type获取bean时如何确定beanName?【3】获取RootBeanDefinition所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复