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

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

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

  1. @Override
  2. public void refresh() throws BeansException, IllegalStateException {
  3. synchronized (this.startupShutdownMonitor) {
  4. ...
  5. try {
  6. // Allows post-processing of the bean factory in context subclasses.
  7. // 允许在上下文的子类中对bean factory进行后处理
  8. postProcessBeanFactory(beanFactory);
  9. ···
  10. }

断点进入跟踪。

postProcessBeanFactory(零)

此方法的实现在AbstractRefreshableWebApplicationContext类中,它是XmlWebApplicationContext的父类。进入方法查看:

  1. /**
  2. * Register request/session scopes, a {@link ServletContextAwareProcessor}, etc.
  3. *
  4. * 注册request/session scopes,一个ServletContextAwareProcessor处理器等。
  5. */
  6. @Override
  7. protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  8. //ServletContextAwareProcessor中拿到应用上下文持有的servletContext引用和servletConfig引用
  9. //1.添加ServletContextAwareProcessor处理器
  10. beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
  11. //在自动注入时忽略指定的依赖接口
  12. //通常被应用上下文用来注册以其他方式解析的依赖项
  13. beanFactory.ignoreDependencyInterface(ServletContextAware.class);
  14. beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
  15. //2.注册web应用的scopes
  16. WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
  17. //3.注册和环境有关的beans
  18. WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
  19. }

postProcessBeanFactory方法的接口声明在AbstractApplicationContext类中:

  1. /**
  2. * Modify the application context's internal bean factory after its standard
  3. * initialization. All bean definitions will have been loaded, but no beans
  4. * will have been instantiated yet. This allows for registering special
  5. * BeanPostProcessors etc in certain ApplicationContext implementations.
  6. *
  7. * 在应用上下文的内部bean factory初始化之后修改bean factory。
  8. * 所有的bean definitions已经被加载,但是还没有bean被实例化。
  9. * 在明确的ApplicationContext实现中允许指定BeanPostProcessors等的注册
  10. */
  11. protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  12. }

1.addBeanPostProcessor

跟踪标记为1的方法

此方法的实现在AbstractBeanFactory类中

这里要注册的处理器ServletContextAwareProcessor带有Aware单词,这个单词是“有意识、能意识到”的意思,个人理解就是能意识到ServletContext的存在,也就是能拿到ServletContext的引用,或者能对其进行设置。

  1. //1.添加ServletContextAwareProcessor处理器
  2. beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
  3. /**
  4. * Add a new BeanPostProcessor that will get applied to beans created
  5. * by this factory. To be invoked during factory configuration.
  6. * <p>Note: Post-processors submitted here will be applied in the order of
  7. * registration; any ordering semantics expressed through implementing the
  8. * {@link org.springframework.core.Ordered} interface will be ignored. Note
  9. * that autodetected post-processors(e.g. as beans in an ApplicationContext)
  10. * will always be applied after programmatically registered ones.
  11. *
  12. * 添加一个新的BeanPostProcessor,在工厂创建bean的时候会应用得到。
  13. * 在工厂配置时被调用。
  14. * 注意:Post-processors是按照注册的顺序被提交的
  15. * 任何通过实现Ordered接口的排序表达式都将被忽略。
  16. * 注意,自动检测的post-processors(作为一个在ApplicationContext的bean)总是在编程方式注册后才会被使用。
  17. */
  18. @Override
  19. public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
  20. Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
  21. //beanPostProcessors是一个ArrayList,持有在创建bean时被应用的BeanPostProcessors
  22. this.beanPostProcessors.remove(beanPostProcessor);
  23. this.beanPostProcessors.add(beanPostProcessor);
  24. //InstantiationAwareBeanPostProcessor这个接口有两个方法
  25. //一个在实例化之前被调用
  26. //一个在实例化之后,初始化之前被调用,可以用来做一些特殊用途,比如代理
  27. if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
  28. this.hasInstantiationAwareBeanPostProcessors = true;
  29. }
  30. //DestructionAwareBeanPostProcessor这个接口只有一个方法,在被销毁前调用
  31. if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
  32. this.hasDestructionAwareBeanPostProcessors = true;
  33. }
  34. }

2.registerWebApplicationScopes

跟踪标记为2的方法

此方法的实现在WebApplicationContextUtils类中

  1. //2.注册web应用的scopes
  2. WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
  3. /**
  4. * Register web-specific scopes ("request", "session", "globalSession", "application")
  5. * with the given BeanFactory, as used by the WebApplicationContext.
  6. *
  7. * 注册web特有的scopes("request", "session", "globalSession", "application")到指定的bean工厂
  8. * 被WebApplicationContext使用
  9. */
  10. public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, ServletContext sc) {
  11. //2.1注册request Scope
  12. beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
  13. //注册session Scope
  14. beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope(false));
  15. //注册global session Scope
  16. beanFactory.registerScope(WebApplicationContext.SCOPE_GLOBAL_SESSION, new SessionScope(true));
  17. if (sc != null) {
  18. ServletContextScope appScope = new ServletContextScope(sc);
  19. //注册application Scope
  20. beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
  21. // Register as ServletContext attribute, for ContextCleanupListener to detect it.
  22. // 为了能让ContextCleanupListener监听器检测到,
  23. // 将application Scope作为ServletContext的属性进行注册
  24. sc.setAttribute(ServletContextScope.class.getName(), appScope);
  25. }
  26. //ServletRequest.class为key,对象为value放入到了beanFactory的resolvableDependencies属性中
  27. //resolvableDependencies是一个ConcurrentHashMap,映射依赖类型和对应的被注入的value
  28. //value要是依赖类型的实例,要不value就应该是个ObjectFactory
  29. //ObjectFactory和FactoryBean的区别可以看下文参考
  30. beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
  31. beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
  32. beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
  33. beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
  34. //是否存在jsf
  35. if (jsfPresent) {
  36. FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
  37. }
  38. }

2.1 registerScope

跟踪标记为2.1的方法

此方法的实现在AbstractBeanFactory类中

  1. //2.1注册request Scope
  2. beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
  3. @Override
  4. public void registerScope(String scopeName, Scope scope) {
  5. Assert.notNull(scopeName, "Scope identifier must not be null");
  6. Assert.notNull(scope, "Scope must not be null");
  7. //singleton和prototype在这个方法中不进行注册
  8. if (SCOPE_SINGLETON.equals(scopeName) || SCOPE_PROTOTYPE.equals(scopeName)) {
  9. //不能替换已存在的 singleton scope和 prototype scope
  10. throw new IllegalArgumentException("Cannot replace existing scopes 'singleton' and 'prototype'");
  11. }
  12. //scopes是AbstractBeanFactory的LinkedHashMap属性
  13. Scope previous = this.scopes.put(scopeName, scope);
  14. //打印日志
  15. if (previous != null && previous != scope) {
  16. //对已经注册过的scope进行替换
  17. if (logger.isInfoEnabled()) {
  18. logger.info("Replacing scope '" + scopeName + "' from [" + previous + "] to [" + scope + "]");
  19. }
  20. }
  21. else {
  22. //没注册过的和同一个实例注册两次的scope都打印日志记录下
  23. if (logger.isDebugEnabled()) {
  24. logger.debug("Registering scope '" + scopeName + "' with implementation [" + scope + "]");
  25. }
  26. }
  27. }

3.registerEnvironmentBeans

跟踪标记为3的方法

此方法的实现在WebApplicationContextUtils类中

  1. //3.注册和环境有关的beans
  2. WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
  3. /**
  4. * Register web-specific environment beans ("contextParameters", "contextAttributes")
  5. * with the given BeanFactory, as used by the WebApplicationContext.
  6. *
  7. * 注册web特有的environment beans ("contextParameters", "contextAttributes")到指定工厂中
  8. * 被WebApplicationContext所使用
  9. */
  10. public static void registerEnvironmentBeans(
  11. ConfigurableListableBeanFactory bf, ServletContext servletContext, ServletConfig servletConfig) {
  12. //单例或者beanDefinition中不包含servletContext进入条件
  13. if (servletContext != null && !bf.containsBean(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME)) {
  14. //3.1注册servletContext单例,注册方法跟踪过一次,这里再跟踪一次加深印象
  15. bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext);
  16. }
  17. //单例或者beanDefinition中不包含servletConfig进入条件
  18. if (servletConfig != null && !bf.containsBean(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME)) {
  19. //注册servletConfig单例
  20. bf.registerSingleton(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME, servletConfig);
  21. }
  22. //单例或者beanDefinition中不包含contextParameters进入条件
  23. if (!bf.containsBean(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME)) {
  24. Map<String, String> parameterMap = new HashMap<String, String>();
  25. if (servletContext != null) {
  26. Enumeration<?> paramNameEnum = servletContext.getInitParameterNames();
  27. while (paramNameEnum.hasMoreElements()) {
  28. String paramName = (String) paramNameEnum.nextElement();
  29. //将servletContext参数配置放入集合中
  30. //也就是web.xml中context-param标签里的param-name和param-value
  31. parameterMap.put(paramName, servletContext.getInitParameter(paramName));
  32. }
  33. }
  34. if (servletConfig != null) {
  35. Enumeration<?> paramNameEnum = servletConfig.getInitParameterNames();
  36. while (paramNameEnum.hasMoreElements()) {
  37. String paramName = (String) paramNameEnum.nextElement();
  38. //将servletConfig中的参数配置放入集合
  39. parameterMap.put(paramName, servletConfig.getInitParameter(paramName));
  40. }
  41. }
  42. //以contextParameters作为name,集合转换成不可修改状态,作为value,进行注册
  43. bf.registerSingleton(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME,
  44. Collections.unmodifiableMap(parameterMap));
  45. }
  46. //单例或者beanDefinition中不包含contextAttributes进入条件
  47. if (!bf.containsBean(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME)) {
  48. Map<String, Object> attributeMap = new HashMap<String, Object>();
  49. if (servletContext != null) {
  50. Enumeration<?> attrNameEnum = servletContext.getAttributeNames();
  51. while (attrNameEnum.hasMoreElements()) {
  52. String attrName = (String) attrNameEnum.nextElement();
  53. //将servletContext中设置的Attribute放入集合
  54. attributeMap.put(attrName, servletContext.getAttribute(attrName));
  55. }
  56. }
  57. //以contextAttributes作为name,集合转换成不可修改状态,作为value,进行注册
  58. bf.registerSingleton(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME,
  59. Collections.unmodifiableMap(attributeMap));
  60. }
  61. }

3.1 registerSingleton

跟踪标记为3.1的方法

此方法的实现在DefaultListableBeanFactory类中

  1. //3.1注册servletContext单例
  2. bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext);
  3. @Override
  4. public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
  5. //3.1.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. this.manualSingletonNames.add(beanName);
  29. }
  30. }
  31. //进入这个方法查看
  32. clearByTypeCache();
  33. }
  34. /**
  35. * Remove any assumptions about by-type mappings.
  36. *
  37. * 删除按照类型映射有关的任何假设
  38. */
  39. private void clearByTypeCache() {
  40. //allBeanNamesByType是单例和非单例beanName的映射,key是依赖类型
  41. this.allBeanNamesByType.clear();
  42. //仅单例beanName的映射,key是依赖类型
  43. this.singletonBeanNamesByType.clear();
  44. }

3.1.1 registerSingleton

跟踪标记为3.1.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. }

postProcessBeanFactory方法也跟踪完了。

未完···

参考

FactoryBean与ObjectFactory区别:

https://blog.csdn.net/m0_38043362/article/details/80284577

总结

  • 添加后处理器、忽略依赖接口
  • 2.注册web应用的scopes
  • 3.注册和环境有关的beans

——————————————————————————————————

  • 2
  • 在工厂中注册request session globalSession Scope
  • 如果 ServletContext 不为null,用Scope实现类包裹后注册到工厂,注册为application。同时在ServletContext 的属性中保存一份。
  • 在工厂中注册各种可解析依赖

——————————————————————————————————

  • 3
  • 当 servletContext 不为null时,工厂以及其父工厂中没有对应单例或者BeanDefinition,那么就在工厂中注册单例,并标记为手动注册的单例
  • 同上注册 servletConfig
  • 拿到 servletContext 和 servletConfig 中的初始参数,都放入到map中,然后注册到工厂,name为 contextParameters ,最后标记为手动注册
  • 拿到 servletContext 中的属性,都放入到map中,然后注册到工厂,name为 contextAttributes,最后标记为手动注册

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

  1. prepareBeanFactory方法源码跟踪

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

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

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

  3. prepareRefresh方法源码跟踪

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

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

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

  5. obtainFreshBeanFactory方法源码跟踪

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

  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. 【C++初学者自学笔记二】函数重载(模块一)

    1.概念:同意作用域的一组参数列表不同,函数名相同的函数,这组函数叫函数重载(C语言是不能定义相同名称的函数,但是C++可以允许定义). 2作用:重载函数通常来命名一组功能相似的函数,这样做减少了函数 ...

  2. 计算机基础 - 时间戳(timestamp)位数

    分为10位数字(ten digit)和13位(thirteen digit)数字 1. Unix, Python为10 time +%s import time time.time() 2. Java ...

  3. spark实验(二)--scala安装(1)

    一.实验目的 (1)掌握在 Linux 虚拟机中安装 Hadoop 和 Spark 的方法: (2)熟悉 HDFS 的基本使用方法: (3)掌握使用 Spark 访问本地文件和 HDFS 文件的方法. ...

  4. vue学习笔记:Hello Vue

    编写简单例子,了解下基本语法 <!DOCTYPE html> <html> <head> <meta charset="utf-8 "&g ...

  5. unique() 函数详解

    简介 顾名思义,unique,独一无二的.这个函数可以对容器中的元素进行"去重". 但是需要注意,这里的"去重",并没有把重复的元素删除,只是不重复的元素放到了 ...

  6. H5新增的标签和属性

    声明 Web 世界中存在许多不同的文档.只有了解文档的类型,浏览器才能正确地显示文档. HTML 也有多个不同的版本,只有完全明白页面中使用的确切 HTML 版本,浏览器才能完全正确地显示出 HTML ...

  7. Python正则表达式就是这么简单【新手必学】

    一前言本篇文章带大家快速入门正则表达式的使用,正则表达式的规则不仅适用python语言,基本大多数编程语言都适用,在日常使用中极为广泛,读者们有必要学好正则表达式.看完这篇文章,读者们要理解什么是正则 ...

  8. axios发送post请求node服务器无法通过req.body获取参数

    问题: 项目前端使用Vue框架,后端使用node.js搭建本地服务器.前端通过 axios 方式请求后端数据的过程中,发现如果是 get 请求,服务器端能够通过 req.query 获取前端传递的参数 ...

  9. linux的ls -al指令

    ls是“list”的意思,参数-al则表示列出所有的文件,包括隐藏文件,就是文件前面第一个字符为.的文件.   1.第一列便是这个文件的属性: #第一个属性表示这个文件时“目录.文件或链接文件等”: ...

  10. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 表格:响应式表格

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...