看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead

代码过宽,可以shift + 鼠标滚轮 左右滑动查看

AbstractApplicationContext类refresh()方法中的第三个调用方法prepareBeanFactory()的跟踪。

  1. @Override
  2. public void refresh() throws BeansException, IllegalStateException {
  3. synchronized (this.startupShutdownMonitor) {
  4. ...
  5. // Prepare the bean factory for use in this context.
  6. // 准备在上下文中bean factory的使用
  7. prepareBeanFactory(beanFactory);
  8. ···
  9. }

断点进入跟踪。

此方法的实现在AbstractApplicationContext类中。

prepareBeanFactory(零)

  1. /**
  2. * Configure the factory's standard context characteristics,
  3. * such as the context's ClassLoader and post-processors.
  4. *
  5. * 配置工厂的标准上下文特征,比如上下文的ClassLoader和post-processors
  6. */
  7. protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  8. // Tell the internal bean factory to use the context's class loader etc.
  9. //告知内部的bean工厂,使用上下文的类加载器
  10. beanFactory.setBeanClassLoader(getClassLoader());
  11. //设置bean表达式解析器,
  12. //StandardBeanExpressionResolver内部expressionParser属性默认SpelExpressionParser类型
  13. //spel = spring el表达式
  14. beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
  15. //将ResourceEditorRegistrar实例添加到工厂的propertyEditorRegistrars属性中,
  16. //propertyEditorRegistrars是一个LinkedHashSet,里面的元素将会应用到工厂bean中
  17. //ResourceEditorRegistrar持有上下文和environment的引用
  18. beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
  19. // Configure the bean factory with context callbacks.
  20. // 使用上下文回调配置bean 工厂
  21. //在工厂的beanPostProcessor属性中添加处理器,beanPostProcessor是一个ArrayList
  22. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
  23. //在工厂的ignoredDependencyInterfaces属性中添加Aware系列接口,
  24. //ignoredDependencyInterfaces是一个HashSet
  25. beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
  26. beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
  27. beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
  28. beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
  29. beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
  30. // BeanFactory interface not registered as resolvable type in a plain factory.
  31. // MessageSource registered (and found for autowiring) as a bean.
  32. // 在普通的工厂中,BeanFactory接口并没有按照resolvable类型进行注册
  33. // MessageSource被注册成一个Bean(并被自动注入)
  34. //BeanFactory.class为key,beanFactory为value放入到了beanFactory的resolvableDependencies属性中
  35. //resolvableDependencies是一个ConcurrentHashMap,映射依赖类型和对应的被注入的value
  36. //这样的话BeanFactory/ApplicationContext虽然没有以bean的方式被定义在工厂中,
  37. //但是也能够支持自动注入,因为他处于resolvableDependencies属性中
  38. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
  39. //再将上下文的一些接口与上下文本身做映射,一一放入到resolvableDependencies中
  40. beanFactory.registerResolvableDependency(ResourceLoader.class, this);
  41. beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
  42. beanFactory.registerResolvableDependency(ApplicationContext.class, this);
  43. // Detect a LoadTimeWeaver and prepare for weaving, if found.
  44. // 检测LoadTimeWeaver,如果有就准备织入
  45. //1.跟踪进入,浅看下containsBean方法
  46. if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
  47. //如果有LoadTimeWeaver,加入bean后处理器
  48. beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
  49. // Set a temporary ClassLoader for type matching.
  50. // 为匹配类型设置一个临时的ClassLoader
  51. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
  52. }
  53. // Register default environment beans.
  54. // 注册默认的environment beans
  55. // 判断目前这个bean工厂中是否包含指定name的bean,忽略父工厂
  56. if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
  57. //虽然XmlWebApplicationContext中持有默认实现的StandardServletEnvironment
  58. //但是没有注册到beanFactory中,通过getEnvironment方法拿到持有的引用
  59. //2.注册environment单例
  60. beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
  61. }
  62. if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
  63. //注册systemProperties单例
  64. beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
  65. }
  66. if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
  67. //注册systemEnvironment单例
  68. beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
  69. }
  70. }

1.containsBean

跟踪标记为1的方法

此方法的实现在AbstractBeanFactory类中

  1. //1.跟踪看下containsBean方法
  2. beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)
  3. /**
  4. * Does this bean factory contain a bean definition or externally registered singleton
  5. * instance with the given name?
  6. * <p>If the given name is an alias, it will be translated back to the corresponding
  7. * canonical bean name.
  8. * <p>If this factory is hierarchical, will ask any parent factory if the bean cannot
  9. * be found in this factory instance.
  10. * <p>If a bean definition or singleton instance matching the given name is found,
  11. * this method will return {@code true} whether the named bean definition is concrete
  12. * or abstract, lazy or eager, in scope or not. Therefore, note that a {@code true}
  13. * return value from this method does not necessarily indicate that {@link #getBean}
  14. * will be able to obtain an instance for the same name.
  15. *
  16. * bean工厂是否包含一个给定name的bean definition,或者外部被注册的单例bean?
  17. * 如果name是一个别名,会被转换成对应的beanName
  18. * 如果工厂是有层级的,那么当工厂实例中找不到这个bean时,就会去父工厂中查找
  19. * 如果找到匹配name的bean definition或者单例,那么这个方法会返回true
  20. * 不管这个bean definition是具体的还是抽象的,提前加载还是懒加载,是否在范围中。
  21. * 因此,注意从这个方法中返回的true值并不代表从getBean方法中能够获取一个同名称的实例
  22. */
  23. @Override
  24. public boolean containsBean(String name) {
  25. //1.1对name进行必要的转换
  26. String beanName = transformedBeanName(name);
  27. //singletonObjects或者beanDefinitionMap中已注册beanName则进入条件
  28. //说明该beanName有对应的bean definition,或者单例bean
  29. if (containsSingleton(beanName) || containsBeanDefinition(beanName)) {
  30. //name开头不为&返回true,如果带了&但是是FactoryBean也返回true
  31. //要注意下FactoryBean和BeanFactory的区别,可以看下文参考链接
  32. return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));
  33. }
  34. // Not found -> check parent.
  35. // 如果没有找到对应beanName的bean或者bean definition,那么从父工厂查找
  36. BeanFactory parentBeanFactory = getParentBeanFactory();
  37. return (parentBeanFactory != null && parentBeanFactory.containsBean(originalBeanName(name)));
  38. }

1.1 transformedBeanName

跟踪标记为1.1的方法

此方法的实现在AbstractBeanFactory类中

  1. //1.1对name进行必要的转换
  2. String beanName = transformedBeanName(name);
  3. /**
  4. * Return the bean name, stripping out the factory dereference prefix if necessary,
  5. * and resolving aliases to canonical names.
  6. *
  7. * 返回bean name,剥离factory dereference 前缀,并将别名解析为bean name
  8. */
  9. protected String transformedBeanName(String name) {
  10. //总的来说,如果name代表factory,那么name前就带有&前缀,去掉此前缀
  11. //如果这个name是beanName,则直接返回,如果name是alias,在aliasMap中查找对应的beanName,再返回
  12. return canonicalName(BeanFactoryUtils.transformedBeanName(name));
  13. }
  14. //先看下transformedBeanName方法的实现
  15. //进入BeanFactoryUtils类中
  16. /**
  17. * Return the actual bean name, stripping out the factory dereference
  18. * prefix (if any, also stripping repeated factory prefixes if found).
  19. *
  20. * 返回真实的beanName,剥离工厂前缀(如果有的话,也剥离重复的工厂前缀)
  21. */
  22. public static String transformedBeanName(String name) {
  23. Assert.notNull(name, "'name' must not be null");
  24. String beanName = name;
  25. //FACTORY_BEAN_PREFIX常量为:&
  26. while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
  27. beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
  28. }
  29. return beanName;
  30. }
  31. //再进入canonicalName方法查看
  32. //此方法在SimpleAliasRegistry中实现,被默认bean工厂间接继承
  33. /**
  34. * Determine the raw name, resolving aliases to canonical names.
  35. *
  36. * 确定原生的name,将别名解析为BeanName
  37. */
  38. public String canonicalName(String name) {
  39. String canonicalName = name;
  40. // Handle aliasing...
  41. // 处理别名
  42. String resolvedName;
  43. do {
  44. //拿到canonicalName对应的实际名称
  45. resolvedName = this.aliasMap.get(canonicalName);
  46. if (resolvedName != null) {
  47. canonicalName = resolvedName;
  48. }
  49. }
  50. //只有当canonicalName在aliasMap中对应的value为null时,才跳出循环
  51. //这时候说明canonicalName已经不作为其他任何BeanName的别名,排除了间接引用
  52. //canonicalName就为真正的beanName
  53. while (resolvedName != null);
  54. return canonicalName;
  55. }

2.registerSingleton

跟踪标记为2的方法

此方法的实现在DefaultListableBeanFactory类中

  1. //2.注册environment单例
  2. beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
  3. @Override
  4. public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
  5. //2.1调用父类方法,注册单例
  6. super.registerSingleton(beanName, singletonObject);
  7. //AbstractBeanFactory类中有个集合属性alreadyCreated
  8. //里面保存在至少被创建过一次的beanName
  9. //如果这个集合中存在beanName,那么说明已经进入了bean创建阶段
  10. if (hasBeanCreationStarted()) {
  11. // Cannot modify startup-time collection elements anymore (for stable iteration)
  12. // 无法再修改启动时集合元素(为了稳定迭代)
  13. synchronized (this.beanDefinitionMap) {
  14. //beanName不在beanDefinitionMap中,说明是手动注册
  15. if (!this.beanDefinitionMap.containsKey(beanName)) {
  16. Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames.size() + 1);
  17. updatedSingletons.addAll(this.manualSingletonNames);
  18. updatedSingletons.add(beanName);
  19. this.manualSingletonNames = updatedSingletons;
  20. }
  21. }
  22. }
  23. else {
  24. // Still in startup registration phase
  25. // 仍然处于启动注册阶段
  26. if (!this.beanDefinitionMap.containsKey(beanName)) {
  27. //属于手动注册情况
  28. //environment属于手动注册单例
  29. this.manualSingletonNames.add(beanName);
  30. }
  31. }
  32. //进入这个方法查看
  33. clearByTypeCache();
  34. }
  35. /**
  36. * Remove any assumptions about by-type mappings.
  37. *
  38. * 删除按照类型映射有关的任何假设
  39. */
  40. private void clearByTypeCache() {
  41. //allBeanNamesByType是单例和非单例beanName的映射,key是依赖类型
  42. this.allBeanNamesByType.clear();
  43. //仅单例beanName的映射,key是依赖类型
  44. this.singletonBeanNamesByType.clear();
  45. }

2.1 registerSingleton

跟踪标记为2.1的方法

此方法的实现在DefaultSingletonBeanRegistry类中

  1. //2.1调用父类方法,注册单例
  2. super.registerSingleton(beanName, singletonObject);
  3. /**
  4. * Register the given existing object as singleton in the bean registry,
  5. * under the given bean name.
  6. * <p>The given instance is supposed to be fully initialized; the registry
  7. * will not perform any initialization callbacks (in particular, it won't
  8. * call InitializingBean's {@code afterPropertiesSet} method).
  9. * The given instance will not receive any destruction callbacks
  10. * (like DisposableBean's {@code destroy} method) either.
  11. * <p>When running within a full BeanFactory: <b>Register a bean definition
  12. * instead of an existing instance if your bean is supposed to receive
  13. * initialization and/or destruction callbacks.</b>
  14. * <p>Typically invoked during registry configuration, but can also be used
  15. * for runtime registration of singletons. As a consequence, a registry
  16. * implementation should synchronize singleton access; it will have to do
  17. * this anyway if it supports a BeanFactory's lazy initialization of singletons.
  18. *
  19. * 在给定的bean name下,将存在的对象作为单例注册在工厂中
  20. * 给定的实例应该是完全初始化;工厂不执行任何初始化回调(特别是,他不会调用InitializingBean的
  21. * afterPropertiesSet方法)
  22. * 给定的实例也不接收任何销毁回调(像DisposableBean的destroy方法)
  23. * 当在完整的BeanFactory运行时:
  24. * 如果你的bean需要接收初始化或者销毁的回调,注册一个bean definition替代一个存在的实例
  25. * 通常此方法在工厂配置时被调用,也能在运行时单例注册时被调用。
  26. * 作为结果,工厂的实现应该同步单例的访问;如果支持BeanFactory的单例的延迟初始化就不得不这样做
  27. */
  28. @Override
  29. public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
  30. Assert.notNull(beanName, "'beanName' must not be null");
  31. synchronized (this.singletonObjects) {
  32. Object oldObject = this.singletonObjects.get(beanName);
  33. //不能注册两次
  34. if (oldObject != null) {
  35. throw new IllegalStateException("Could not register object [" + singletonObject +
  36. "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
  37. }
  38. //进入这个方法
  39. addSingleton(beanName, singletonObject);
  40. }
  41. }
  42. /**
  43. * Add the given singleton object to the singleton cache of this factory.
  44. * <p>To be called for eager registration of singletons.
  45. *
  46. * 添加给定单例对象到工厂的单例缓存中
  47. * 用来被提早注册的单例调用
  48. */
  49. protected void addSingleton(String beanName, Object singletonObject) {
  50. synchronized (this.singletonObjects) {
  51. //singletonObjects是一个ConcurrentHashMap
  52. //用来缓存单例对象
  53. this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
  54. //singletonFactories是一个HashMap
  55. //里面缓存着单例工厂
  56. this.singletonFactories.remove(beanName);
  57. //早期单例对象
  58. //earlySingletonObjects是一个HashMap
  59. this.earlySingletonObjects.remove(beanName);
  60. //registeredSingletons是一个LinkedHashSet
  61. //被注册单例的集合,以注册的顺序包含着bean name
  62. this.registeredSingletons.add(beanName);
  63. }
  64. }

这样,整个prepareBeanFactory方法也就跟踪完毕了。

接下来跟踪postProcessBeanFactory方法:

https://www.jianshu.com/p/c05aea93b939

参考

BeanFactory和FactoryBean的区别:https://www.cnblogs.com/aspirant/p/9082858.html

总结

  • 为工厂设置类的加载器、表达式解析器、属性编辑器注册器等
  • 为工厂添加后处理器、要忽略的依赖接口
  • 在工厂中注册可解析的依赖
  • 在工厂中提前注册一些单例Bean

prepareBeanFactory方法源码跟踪的更多相关文章

  1. loadBeanDefinitions方法源码跟踪(一)

    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractBeanDe ...

  2. obtainFreshBeanFactory方法源码跟踪

    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractApplic ...

  3. prepareRefresh方法源码跟踪

    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractApplic ...

  4. postProcessBeanFactory方法源码跟踪

    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractApplic ...

  5. loadBeanDefinitions方法源码跟踪(三)

    因为字数超过了限制,所以分成了三篇,承接上篇: https://www.jianshu.com/p/46e27afd7d96 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 4.parseCus ...

  6. loadBeanDefinitions方法源码跟踪(二)

    因为字数超过了限制,所以分成了三篇,承接上篇: https://www.jianshu.com/p/a0cfaedf3fc5 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 3.parseDef ...

  7. erlang下lists模块sort(排序)方法源码解析(一)

    排序算法一直是各种语言最简单也是最复杂的算法,例如十大经典排序算法(动图演示)里面讲的那样 第一次看lists的sort方法的时候,蒙了,几百行的代码,我心想要这么复杂么(因为C语言的冒泡排序我记得不 ...

  8. Java源码跟踪阅读技巧

    转:https://www.jianshu.com/p/ab865109070c 本文基于Eclipse IDE 1.Quick Type Hierarchy 快速查看类继承体系. 快捷键:Ctrl ...

  9. Thread.interrupt()源码跟踪

    1 JDK源码跟踪 // java.lang.Thread public void interrupt() { if (this != Thread.currentThread()) checkAcc ...

随机推荐

  1. Vue.js项目的开发环境搭建与运行

    写作背景:手上入一个用Vue框架写的微信公众号项目,根据公司安排,我负责项目源代码的验收工作(当然专业的工作检测会交给web开发人员,我只是想运行起来看一看). 1 开发环境安装步骤: (一)安装no ...

  2. vue学习笔记:数据渲染操作

    {{xxx}} 基本的插值表达式 插值表达式 使用两个大括号 {{ data中定义的数据名 }} 可以将数据插入到指定的位置 这种写法不仅可以显示data属性里定义的值,也可以书写js中的表达式,可以 ...

  3. shell脚本添加脚本执行时间和当前运行次数current running time

    #!/bin/bash ############################ #Author:Bing #Create time:3/31/2017 ####################### ...

  4. Spring SpringMVC 和 Springboot 的关系(转载)

    原文链接 spring boot就是一个大框架里面包含了许许多多的东西,其中spring就是最核心的内容之一,当然就包含spring mvc. spring mvc 是只是spring 处理web层请 ...

  5. nginx日志模块与HTTP过滤模块与sub模块修改返回内容

    日志格式使用指令 指令介绍 Syntax: log_format name [escape=default|json|none] string ...; Default: log_format com ...

  6. tomcat注册为windows服务

    打开CMD,进入到Tomcat的bin目录,执行命令:service.bat install  [service_name] 如果卸载服务,可以执行:sc delete [service_name]

  7. Educational Codeforces Round 72 (Rated for Div. 2)E(线段树,思维)

    #define HAVE_STRUCT_TIMESPEC#include<bits/stdc++.h>using namespace std;#define BUF_SIZE 100000 ...

  8. CyclicBarrier 解读

    简介 字面上的意思: 可循环利用的屏障. 作用: 让所有线程都等待完成后再继续下一步行动. 举例模拟: 吃饭人没到齐不准动筷. 使用Demo package com.ronnie; import ja ...

  9. java第二次课件课后动手动脑习题整理总结(2019年9月23号)

    一.动手动脑 1 1.题目 2.程序源代码 package yang8; import java.util.Scanner; import java.util.Random; public class ...

  10. VS2008 error PRJ0002 : 错误的结果 31 (从“C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\rc.exe”返回)。

    解决方案,选择属性->配置属性->清单工具->输入和输出->嵌入清单,把是改成否