参考源

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

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

1-1 断言 Bean 工厂活动

  1. assertBeanFactoryActive()
  1. protected void assertBeanFactoryActive() {
  2. if (!this.active.get()) {
  3. if (this.closed.get()) {
  4. // 获取显示名称
  5. throw new IllegalStateException(getDisplayName() + " has been closed already");
  6. }
  7. else {
  8. // 获取显示名称
  9. throw new IllegalStateException(getDisplayName() + " has not been refreshed yet");
  10. }
  11. }
  12. }

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

1-1 获取 Bean 工厂

  1. getBeanFactory()

2 AbstractRefreshableApplicationContext

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

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

1 AbstractApplicationContext

1-1 获取 Bean

  1. getBean(requiredType)

3 DefaultListableBeanFactory

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

3-1 解析 Bean

  1. resolveBean(ResolvableType.forRawClass(requiredType), args, false)
  1. private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
  2. // 解析 Bean 命名
  3. NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
  4. if (namedBean != null) {
  5. return namedBean.getBeanInstance();
  6. }
  7. // 获取父级 Bean 工厂
  8. BeanFactory parent = getParentBeanFactory();
  9. if (parent instanceof DefaultListableBeanFactory) {
  10. // 解析 Bean,递归调用
  11. return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);
  12. }
  13. else if (parent != null) {
  14. ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);
  15. if (args != null) {
  16. return parentProvider.getObject(args);
  17. }
  18. else {
  19. return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());
  20. }
  21. }
  22. return null;
  23. }

3-2 解析 Bean 命名

  1. resolveNamedBean(requiredType, args, nonUniqueAsNull)
  1. private <T> NamedBeanHolder<T> resolveNamedBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
  2. Assert.notNull(requiredType, "Required type must not be null");
  3. // 获取类型的 Bean 名称
  4. String[] candidateNames = getBeanNamesForType(requiredType);
  5. if (candidateNames.length > 1) {
  6. List<String> autowireCandidates = new ArrayList<>(candidateNames.length);
  7. for (String beanName : candidateNames) {
  8. if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
  9. autowireCandidates.add(beanName);
  10. }
  11. }
  12. if (!autowireCandidates.isEmpty()) {
  13. candidateNames = StringUtils.toStringArray(autowireCandidates);
  14. }
  15. }
  16. if (candidateNames.length == 1) {
  17. // 解析 Bean 命名
  18. return resolveNamedBean(candidateNames[0], requiredType, args);
  19. } else if (candidateNames.length > 1) {
  20. Map<String, Object> candidates = CollectionUtils.newLinkedHashMap(candidateNames.length);
  21. for (String beanName : candidateNames) {
  22. if (containsSingleton(beanName) && args == null) {
  23. Object beanInstance = getBean(beanName);
  24. candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
  25. } else {
  26. candidates.put(beanName, getType(beanName));
  27. }
  28. }
  29. // 确定主要候选
  30. String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());
  31. if (candidateName == null) {
  32. // 确定最高优先级候选
  33. candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
  34. }
  35. if (candidateName != null) {
  36. Object beanInstance = candidates.get(candidateName);
  37. if (beanInstance == null) {
  38. return null;
  39. }
  40. if (beanInstance instanceof Class) {
  41. // 解析 Bean 命名
  42. return resolveNamedBean(candidateName, requiredType, args);
  43. }
  44. return new NamedBeanHolder<>(candidateName, (T) beanInstance);
  45. }
  46. if (!nonUniqueAsNull) {
  47. throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
  48. }
  49. }
  50. return null;
  51. }

3-3 确定主要候选

  1. determinePrimaryCandidate(candidates, requiredType.toClass())
  1. protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) {
  2. String primaryBeanName = null;
  3. for (Map.Entry<String, Object> entry : candidates.entrySet()) {
  4. String candidateBeanName = entry.getKey();
  5. Object beanInstance = entry.getValue();
  6. if (isPrimary(candidateBeanName, beanInstance)) {
  7. if (primaryBeanName != null) {
  8. boolean candidateLocal = containsBeanDefinition(candidateBeanName);
  9. boolean primaryLocal = containsBeanDefinition(primaryBeanName);
  10. if (candidateLocal && primaryLocal) {
  11. throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(), "more than one 'primary' bean found among candidates: " + candidates.keySet());
  12. } else if (candidateLocal) {
  13. primaryBeanName = candidateBeanName;
  14. }
  15. } else {
  16. primaryBeanName = candidateBeanName;
  17. }
  18. }
  19. }
  20. return primaryBeanName;
  21. }

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

  1. determineHighestPriorityCandidate(candidates, requiredType.toClass())
  1. protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) {
  2. String highestPriorityBeanName = null;
  3. Integer highestPriority = null;
  4. for (Map.Entry<String, Object> entry : candidates.entrySet()) {
  5. String candidateBeanName = entry.getKey();
  6. Object beanInstance = entry.getValue();
  7. if (beanInstance != null) {
  8. Integer candidatePriority = getPriority(beanInstance);
  9. if (candidatePriority != null) {
  10. if (highestPriorityBeanName != null) {
  11. if (candidatePriority.equals(highestPriority)) {
  12. throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(), "Multiple beans found with the same priority ('" + highestPriority + "') among candidates: " + candidates.keySet());
  13. } else if (candidatePriority < highestPriority) {
  14. highestPriorityBeanName = candidateBeanName;
  15. highestPriority = candidatePriority;
  16. }
  17. } else {
  18. highestPriorityBeanName = candidateBeanName;
  19. highestPriority = candidatePriority;
  20. }
  21. }
  22. }
  23. }
  24. return highestPriorityBeanName;
  25. }

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

  1. spring源码浅析——IOC

    =========================================== 原文链接: spring源码浅析--IOC   转载请注明出处! ======================= ...

  2. spring源码分析---IOC(1)

    我们都知道spring有2个最重要的概念,IOC(控制反转)和AOP(依赖注入).今天我就分享一下spring源码的IOC. IOC的定义:直观的来说,就是由spring来负责控制对象的生命周期和对象 ...

  3. Spring源码解析-ioc容器的设计

    Spring源码解析-ioc容器的设计 1 IoC容器系列的设计:BeanFactory和ApplicatioContext 在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFac ...

  4. Spring源码 05 IOC 注解方式

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

  5. Spring源码 16 IOC refresh方法11

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

  6. Spring源码 17 IOC refresh方法12

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

  7. Spring源码 11 IOC refresh方法6

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

  8. Spring源码 07 IOC refresh方法2

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

  9. Spring源码 06 IOC refresh方法1

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

随机推荐

  1. 《Effective C++》阅读总结(四): 设计、声明与实现

    第四章: 设计与声明 18. 让接口更容易被正确使用,不易被误用 将你的class的public接口设计的符合class所扮演的角色,必要时不仅对传参类型限制,还对传参的值域进一步限制. 19. 设计 ...

  2. Dubbo3 源码系列 Dubbo“纠葛”(入门篇)

    日期 更新说明 2022年5月28日 spring xml部分解读 2022年6月3日 spring annotation部分解读 人生不相见, 动如参与商. 今夕复何夕, 共此灯烛光. 少壮能几时, ...

  3. 用STM32玩OLED(显示文字、图片、动图gif等)

    目录 用STM32玩OLED(显示文字.图片.动图gif等) 1. 显示字符串 2. 显示中文 3. 显示图片 4. 显示动图 5. 总结测试 用STM32玩OLED(显示文字.图片.动图gif等) ...

  4. 字节开源RPC框架Kitex的日志库klog源码解读

    前言 这篇文章将着重于分析字节跳动开源的RPC框架Kitex的日志库klog的源码,通过对比Go原生日志库log的实现,探究其作出的改进. 为了平滑学习曲线,我写下了这篇分析Go原生log库的文章,希 ...

  5. CNN Training Loop Refactoring Simultaneous Hyperameter Testing

    上例中, 尝试两个不同的值 为此: alt+shift可以有多个光标,再jupyter notebook中. alt+d,alt+shift,ctrl+鼠标左键多点几个,都可以同时选择多个目标,并进行 ...

  6. redis持久化之RDB (七)

    一:什么是redis的持久化 Redis 持久化 Redis 提供了不同级别的持久化方式: RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储. AOF持久化方式记录每次对服务器写的操作,当 ...

  7. 论文解读(SR-GNN)《Shift-Robust GNNs: Overcoming the Limitations of Localized Graph Training Data》

    论文信息 论文标题:Shift-Robust GNNs: Overcoming the Limitations of Localized Graph Training Data论文作者:Qi Zhu, ...

  8. Servlet 体系结构

    Servlet体系结构 Servlet -- 接口 Genericservlet -- 抽象类 继承类接口 实现了空方法  只需要复写service方法 HttpServlet -- 抽象类  对Ht ...

  9. windows如何结束某个端口的进程

    netstat -ano | findstr 端口号 (查询端口号被哪个进程占用) tasklist | findstr 进程PID (根据PID找到进程名称) taskkill -PID 进程PID ...

  10. Kafka 延时队列&重试队列

    一.延时队列 1. 简介 TimingWheel是kafka时间轮的实现,内部包含了⼀个TimerTaskList数组,每个数组包含了⼀些链表组成的TimerTaskEntry事件,每个TimerTa ...