Spring源码 19 IOC getBean
参考源
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
前面实现了
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;
}
Spring源码 19 IOC getBean的更多相关文章
- spring源码浅析——IOC
=========================================== 原文链接: spring源码浅析--IOC 转载请注明出处! ======================= ...
- spring源码分析---IOC(1)
我们都知道spring有2个最重要的概念,IOC(控制反转)和AOP(依赖注入).今天我就分享一下spring源码的IOC. IOC的定义:直观的来说,就是由spring来负责控制对象的生命周期和对象 ...
- Spring源码解析-ioc容器的设计
Spring源码解析-ioc容器的设计 1 IoC容器系列的设计:BeanFactory和ApplicatioContext 在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFac ...
- Spring源码 05 IOC 注解方式
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
- Spring源码 16 IOC refresh方法11
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
- Spring源码 17 IOC refresh方法12
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
- Spring源码 11 IOC refresh方法6
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
- Spring源码 07 IOC refresh方法2
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
- Spring源码 06 IOC refresh方法1
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
随机推荐
- JavaSE_关键字 接口 代码块 枚举
1 Java中的关键字 1.1 static关键字 static特点 : 静态成员被所在类的所有对象共享 随着类的加载而加载 , 优先于对象存在 可以通过对象调用 , 也可以通过类名调用 , 建议使用 ...
- 第06组 Beta冲刺 (1/6)
目录 1.1 基本情况 1.2 冲刺概况汇报 1.郝雷明 2. 方梓涵 3.曾丽莉 4.黄少丹 5. 董翔云 6.杜筱 7.鲍凌函 8.詹鑫冰 9.曹兰英 10.吴沅静 1.3 冲刺成果展示 1.1 ...
- 《C Primer Plus》第六版笔记--4~6章
目录 第四章 字符串和格式化输入/输出 第五章 运算符.表达式和语句 第六章 C控制语句:循环 虽然匆匆忙忙,但还是要做笔记,虽然大概都知道...... 挑一些容易忘记的地方 第四章 字符串和格式化输 ...
- Egg上层框架CabloyJS是如何输出SQL语句日志的?
背景 在Egg开发实践中,经常会遇到一个问题:如何查看刚刚执行过的Egg组装的原生SQL语句呢? 1. 现有方案 可以直接在项目的config配置文件中添加MySQL配置debug: true.这会启 ...
- 苹果宣布 2022 年 Apple 设计大奖得主
Apple 今日举办了年度 Apple 设计大奖颁奖仪式,表彰 12 款出类拔萃的 app 与游戏佳作.今年的获奖者包括来自全球各地的开发者.他们通过 app 呈现锐意创新.别出心裁的优美设计体验,以 ...
- 拥抱 OpenAPI 3:springdoc-openapi 食用指南
概述 使用 springdoc-openapi 可以快速为 springboot 项目生成规范的 API 文档,具体使用步骤如下: 依赖配置 在 pom.xml 加入内容,即可开始使用: <de ...
- 22.LVS+Keepalived 高可用群集
LVS+Keepalived 高可用群集 目录 LVS+Keepalived 高可用群集 keepalived工具介绍 Keepalived实现原理剖析 VRRP(虚拟路由冗余协议) VRRP 相关术 ...
- 3.C++逐行读取txt文件数据,利用getline -windows编程
引言:今天学会了getline的用法,顺手编写一个逐行读取txt文件的程序.关于getline的用法可以看我之前的博客:2.C++标准库函数:getline函数 定界流输入截取函数 -zobol的 ...
- 基于SqlSugar的开发框架循序渐进介绍(9)-- 结合Winform控件实现字段的权限控制
字段的权限控制,一般就是控制对应角色人员对某个业务对象的一些敏感字段的可访问性:包括可见.可编辑性等处理.本篇随笔结合基于SqlSugar的开发框架进行的字段控制管理介绍. 在设计字段权限的时候,我们 ...
- Prometheus安装教程
Prometheus安装教程 欢迎关注H寻梦人公众号 参考目录 docker安装Prometheus 基于docker 搭建Prometheus+Grafana prometheus官方文档 dock ...