【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中。