前面实现了 ClassPathXmlApplicationContext 的构造,接下来分析其调用的 getBean 方法。

getBean(UserDao.class) 为例。

1 AbstractApplicationContext

public <T> T getBean(Class<T> requiredType) throws BeansException {
// 断言 Bean 工厂活动
assertBeanFactoryActive();
// 获取 Bean 工厂
// 获取 Bean
return getBeanFactory().getBean(requiredType);
}

1-1 断言 Bean 工厂活动

assertBeanFactoryActive()
protected void assertBeanFactoryActive() {
if (!this.active.get()) {
if (this.closed.get()) {
// 获取显示名称
throw new IllegalStateException(getDisplayName() + " has been closed already");
}
else {
// 获取显示名称
throw new IllegalStateException(getDisplayName() + " has not been refreshed yet");
}
}
}

获取显示名称前面已经分析过了,这里不再分析。

1-1 获取 Bean 工厂

getBeanFactory()

2 AbstractRefreshableApplicationContext

public final ConfigurableListableBeanFactory getBeanFactory() {
DefaultListableBeanFactory beanFactory = this.beanFactory;
if (beanFactory == null) {
throw new IllegalStateException("BeanFactory not initialized or already closed - " + "call 'refresh' before accessing beans via the ApplicationContext");
}
return beanFactory;
}

if (beanFactory == null) 由于前面定义了 beanFactory,这里直接返回。

1 AbstractApplicationContext

1-1 获取 Bean

getBean(requiredType)

3 DefaultListableBeanFactory

public <T> T getBean(Class<T> requiredType) throws BeansException {
// 获取 Bean
return getBean(requiredType, (Object[]) null);
}
public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
// 解析 Bean
Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
if (resolved == null) {
throw new NoSuchBeanDefinitionException(requiredType);
}
return (T) resolved;
}

3-1 解析 Bean

resolveBean(ResolvableType.forRawClass(requiredType), args, false)
private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
// 解析 Bean 命名
NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
if (namedBean != null) {
return namedBean.getBeanInstance();
}
// 获取父级 Bean 工厂
BeanFactory parent = getParentBeanFactory();
if (parent instanceof DefaultListableBeanFactory) {
// 解析 Bean,递归调用
return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);
}
else if (parent != null) {
ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);
if (args != null) {
return parentProvider.getObject(args);
}
else {
return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());
}
}
return null;
}

3-2 解析 Bean 命名

resolveNamedBean(requiredType, args, nonUniqueAsNull)
private <T> NamedBeanHolder<T> resolveNamedBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
// 获取类型的 Bean 名称
String[] candidateNames = getBeanNamesForType(requiredType);
if (candidateNames.length > 1) {
List<String> autowireCandidates = new ArrayList<>(candidateNames.length);
for (String beanName : candidateNames) {
if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
autowireCandidates.add(beanName);
}
}
if (!autowireCandidates.isEmpty()) {
candidateNames = StringUtils.toStringArray(autowireCandidates);
}
}
if (candidateNames.length == 1) {
// 解析 Bean 命名
return resolveNamedBean(candidateNames[0], requiredType, args);
} else if (candidateNames.length > 1) {
Map<String, Object> candidates = CollectionUtils.newLinkedHashMap(candidateNames.length);
for (String beanName : candidateNames) {
if (containsSingleton(beanName) && args == null) {
Object beanInstance = getBean(beanName);
candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
} else {
candidates.put(beanName, getType(beanName));
}
}
// 确定主要候选
String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());
if (candidateName == null) {
// 确定最高优先级候选
candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
}
if (candidateName != null) {
Object beanInstance = candidates.get(candidateName);
if (beanInstance == null) {
return null;
}
if (beanInstance instanceof Class) {
// 解析 Bean 命名
return resolveNamedBean(candidateName, requiredType, args);
}
return new NamedBeanHolder<>(candidateName, (T) beanInstance);
}
if (!nonUniqueAsNull) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
}
}
return null;
}

3-3 确定主要候选

determinePrimaryCandidate(candidates, requiredType.toClass())
protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) {
String primaryBeanName = null;
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateBeanName = entry.getKey();
Object beanInstance = entry.getValue();
if (isPrimary(candidateBeanName, beanInstance)) {
if (primaryBeanName != null) {
boolean candidateLocal = containsBeanDefinition(candidateBeanName);
boolean primaryLocal = containsBeanDefinition(primaryBeanName);
if (candidateLocal && primaryLocal) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(), "more than one 'primary' bean found among candidates: " + candidates.keySet());
} else if (candidateLocal) {
primaryBeanName = candidateBeanName;
}
} else {
primaryBeanName = candidateBeanName;
}
}
}
return primaryBeanName;
}

3-3 确定最高优先级候选

determineHighestPriorityCandidate(candidates, requiredType.toClass())
protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) {
String highestPriorityBeanName = null;
Integer highestPriority = null;
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateBeanName = entry.getKey();
Object beanInstance = entry.getValue();
if (beanInstance != null) {
Integer candidatePriority = getPriority(beanInstance);
if (candidatePriority != null) {
if (highestPriorityBeanName != null) {
if (candidatePriority.equals(highestPriority)) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(), "Multiple beans found with the same priority ('" + highestPriority + "') among candidates: " + candidates.keySet());
} else if (candidatePriority < highestPriority) {
highestPriorityBeanName = candidateBeanName;
highestPriority = candidatePriority;
}
} else {
highestPriorityBeanName = candidateBeanName;
highestPriority = candidatePriority;
}
}
}
}
return highestPriorityBeanName;
}

参考

https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click

https://www.bilibili.com/video/BV12Z4y197MU?spm_id_from=333.999.0.0

《Spring源码深度解析(第2版)》

版本

Spring 5.3.15

Spring源码 19 IOC getBean方法的更多相关文章

  1. Spring源码 19 IOC getBean

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  2. Spring源码 16 IOC refresh方法11

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  3. Spring源码 17 IOC refresh方法12

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  4. Spring源码 11 IOC refresh方法6

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  5. Spring源码 07 IOC refresh方法2

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  6. Spring源码 06 IOC refresh方法1

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  7. Spring源码 18 IOC refresh方法13

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  8. Spring源码 15 IOC refresh方法10

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  9. Spring源码 14 IOC refresh方法9

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  10. Spring源码 09 IOC refresh方法4

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

随机推荐

  1. 【LeetCode二叉树#00】二叉树的基础知识

    基础知识 分类 满二叉树 如果二叉树中除了叶子结点,每个结点的度都为 2,则此二叉树称为满二叉树. 完全二叉树 除了底层外,其他部分是满的,且底层从左到右是连续的,称为完全二叉树 满二叉树一定是完全二 ...

  2. 【Azure Redis 缓存】对于Azure Redis 从 Redis 4 升级到 Redis 6 的一些疑问

    问题描述 使用Azure Redis服务,客户端使用Redisson 3.X , 在近期Microsoft Azure对Redis服务进行大规模变动升级( Redis 版本由 4 升级到 6),对于这 ...

  3. STL-stack模拟实现

    #pragma once #include<assert.h> #include<list> #include<vector> #include<deque& ...

  4. 文心一言 VS 讯飞星火 VS chatgpt (209)-- 算法导论15.4 6题

    六.设计一个 O(nlgn) 时间的算法,求一个 n 个数的序列的最长单调递增子序列.(提示:注意到,一个长度为 i 的候选子序列的尾元素至少不比一个长度为 i-1 候选子序列的尾元素小.因此,可以在 ...

  5. C++ Qt开发:QNetworkAccessManager网络接口组件

    Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用QNe ...

  6. vite ts 安装 js-cookie 库,vscode找不到类型说明(有波浪线),解决方案

    vite ts 安装 js-cookie 库,vscode找不到类型说明(有波浪线),解决方案 先安装库 https://www.npmjs.com/package/js-cookie 再安装类型 h ...

  7. 计算引擎-Flink

    参考:https://mp.weixin.qq.com/s/RUS9w-bGan6fDcF9CVqvFw checkpoint 1.Checkpoint Coordinator 向所有 source ...

  8. 3、Azure Devops之Azure Repos篇

    1.什么是Azure Repos Azure Repos,就是我们常说的代码仓库,相当于gitee,github,git,svn工具.主要是提供给开发人员使用的,管理.查看代码的部件.通过Files. ...

  9. 腾讯Linux 运维工程师面试真题

    腾讯Linux 运维工程师面试真题 1. 如何防止 DDOS 攻击?如提供足够资源给你,要保证用户访问不影响. 首先确定攻击源范围,如果是处于公司内部,那么暂时性的将这一区域的内部网络封掉,如 果是外 ...

  10. (2)Python解释器的安装

    鉴于有同学在安装Python解释器出现了问题,这里再安装一下 step1,下载安装包,链接https://www.python.org/downloads/ 这里我安装的是3.6.4版本 我选择的是6 ...