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

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

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

  1. @Override
  2. public void refresh() throws BeansException, IllegalStateException {
  3. synchronized (this.startupShutdownMonitor) {
  4. ...
  5. // Tell the subclass to refresh the internal bean factory.
  6. // 告知子类去刷新内部的 bean factory
  7. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  8. ···
  9. }

断点进入跟踪。

  1. /**
  2. * Tell the subclass to refresh the internal bean factory.
  3. * @return the fresh BeanFactory instance
  4. *
  5. * 告知子类去刷新内部的 bean factory,返回刷新后的 bean factory 实例
  6. */
  7. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  8. //刷新 bean factory,进入此方法查看
  9. refreshBeanFactory();
  10. //返回已被刷新、注册了beandefinition的factory
  11. ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  12. if (logger.isDebugEnabled()) {
  13. logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
  14. }
  15. return beanFactory;
  16. }

refreshBeanFactory(零)

refreshBeanFactory方法在子类AbstractRefreshableApplicationContext中实现,在AbstractApplicationContext中被定义。

  1. //1.刷新 bean factory
  2. refreshBeanFactory();
  3. //先看下这个方法的定义
  4. /**
  5. * Subclasses must implement this method to perform the actual configuration load.
  6. * The method is invoked by {@link #refresh()} before any other initialization work.
  7. * <p>A subclass will either create a new bean factory and hold a reference to it,
  8. * or return a single BeanFactory instance that it holds. In the latter case, it will
  9. * usually throw an IllegalStateException if refreshing the context more than once.
  10. * @throws BeansException if initialization of the bean factory failed
  11. * @throws IllegalStateException if already initialized and multiple refresh
  12. * attempts are not supported
  13. *
  14. * 子类必须实现这个方法去执行配置的加载。这个方法在其他任何初始化工作之前被 refresh 方法所调用,
  15. * 他的子类要么创建一个新的 bean factory ,并拿到factory的引用;要么返回一个
  16. * 已有的单例 bean factory 实例。
  17. * 在后一个情况中,如果刷新这个 context 超过一次,那么就会抛出非法状态异常
  18. */
  19. protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
  20. /**
  21. * This implementation performs an actual refresh of this context's underlying
  22. * bean factory, shutting down the previous bean factory (if any) and
  23. * initializing a fresh bean factory for the next phase of the context's lifecycle.
  24. *
  25. * 这个实现对 context 底层的 bean factory 执行刷新操作,关闭以前的 bean factory(如果有),
  26. * 并且为 context 生命周期的下一个阶段初始化一个新的 bean factory
  27. */
  28. @Override
  29. protected final void refreshBeanFactory() throws BeansException {
  30. //此时没有 bean factory,直接跳过
  31. if (hasBeanFactory()) {
  32. destroyBeans();
  33. closeBeanFactory();
  34. }
  35. try {
  36. //1.创建一个 bean factory
  37. DefaultListableBeanFactory beanFactory = createBeanFactory();
  38. //将 context 的 id 设置为 bean factory 的序列化id,
  39. //并建立起id和该 bean factory 实例的映射关系
  40. beanFactory.setSerializationId(getId());
  41. //2.自定义内部的 bean factory
  42. customizeBeanFactory(beanFactory);
  43. //3.加载 beanDefinition
  44. loadBeanDefinitions(beanFactory);
  45. synchronized (this.beanFactoryMonitor) {
  46. // 新创建的工厂,其内部属性就位后,被 context 拿到引用
  47. this.beanFactory = beanFactory;
  48. }
  49. }
  50. catch (IOException ex) {
  51. throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
  52. }
  53. }

1.createBeanFactory

跟踪标记1的方法

这个方法在AbstractRefreshableApplicationContext类中

  1. //1.创建一个 bean factory
  2. DefaultListableBeanFactory beanFactory = createBeanFactory();
  3. /**
  4. * Create an internal bean factory for this context.
  5. * Called for each {@link #refresh()} attempt.
  6. * <p>The default implementation creates a
  7. * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
  8. * with the {@linkplain #getInternalParentBeanFactory() internal bean factory} of this
  9. * context's parent as parent bean factory. Can be overridden in subclasses,
  10. * for example to customize DefaultListableBeanFactory's settings.
  11. *
  12. * 为 context 创建一个内部的 bean factory。
  13. * 每个refresh方法都会尝试调用该方法
  14. * 默认的实现是创建一个DefaultListableBeanFactory对象,利用getInternalParentBeanFactory方法
  15. * 将 context 的 parent 的 bean factory ,作为该 context 内部 bean factory 的 parent bean factory
  16. * 该方法可以被子类覆盖,例如自定义DefaultListableBeanFactory的设定
  17. */
  18. protected DefaultListableBeanFactory createBeanFactory() {
  19. return new DefaultListableBeanFactory(getInternalParentBeanFactory());
  20. }

getInternalParentBeanFactory方法在AbstractApplicationContext类中

AbstractApplicationContext是AbstractRefreshableApplicationContext的父类

  1. /**
  2. * Return the internal bean factory of the parent context if it implements
  3. * ConfigurableApplicationContext; else, return the parent context itself.
  4. *
  5. * 如果 parent context 实现了ConfigurableApplicationContext接口,
  6. * 那么返回 parent context 内部的 bean factory
  7. * 否则返回 parent context 自身
  8. */
  9. protected BeanFactory getInternalParentBeanFactory() {
  10. return (getParent() instanceof ConfigurableApplicationContext) ?
  11. ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent();
  12. }

不管是 application context 还是 bean factory,都有实现BeanFactory这个接口,所以 context 也可以看做是一个特殊类型的 bean factory 。

2.customizeBeanFactory

跟踪标记2.自定义内部的bean工厂

  1. //2.自定义内部的 bean factory
  2. customizeBeanFactory(beanFactory);
  3. /**
  4. * Customize the internal bean factory used by this context.
  5. * Called for each {@link #refresh()} attempt.
  6. * <p>The default implementation applies this context's
  7. * {@linkplain #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}
  8. * and {@linkplain #setAllowCircularReferences "allowCircularReferences"} settings,
  9. * if specified. Can be overridden in subclasses to customize any of
  10. *
  11. * 自定义内部的 bean factory 用于这个 context
  12. * 每个refresh方法都会尝试调用该方法
  13. * 默认实现应用这个context的setAllowBeanDefinitionOverriding方法和setAllowCircularReferences方法
  14. * 去设置,如果有这两个方法所需的参数的话。
  15. * 可以在子类中覆盖该方法去自定义DefaultListableBeanFactory中的任何设定
  16. */
  17. protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
  18. if (this.allowBeanDefinitionOverriding != null) {
  19. //相同名称的不同bean definition能否被重复注册
  20. beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
  21. }
  22. if (this.allowCircularReferences != null) {
  23. //是否尝试自动去解决两个bean之间的循环引用问题
  24. beanFactory.setAllowCircularReferences(this.allowCircularReferences);
  25. }
  26. }

3.loadBeanDefinitions

跟踪标记3的方法

这个方法在AbstractRefreshableApplicationContext中被定义,在XmlWebApplicationContext中被实现

  1. //3.加载 beanDefinition
  2. loadBeanDefinitions(beanFactory);
  3. //在AbstractRefreshableApplicationContext类中的定义
  4. /**
  5. * Load bean definitions into the given bean factory, typically through
  6. * delegating to one or more bean definition readers.
  7. *
  8. * 通常通过一个或者多个 bean definition readers 去加载 bean definitions 到指定的 bean factory
  9. */
  10. protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
  11. throws BeansException, IOException;
  12. //在XmlWebApplicationContext类中的实现
  13. /**
  14. * Loads the bean definitions via an XmlBeanDefinitionReader.
  15. * 通过一个XmlBeanDefinitionReader加载bean definitions
  16. */
  17. @Override
  18. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
  19. // Create a new XmlBeanDefinitionReader for the given BeanFactory.
  20. // 为指定的 BeanFactory 创建一个新的XmlBeanDefinitionReader
  21. // 3.1XmlBeanDefinitionReader的初始化需要了解下
  22. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
  23. // Configure the bean definition reader with this context's
  24. // resource loading environment.
  25. // 将context加载了资源的environment配置给bean definition reader
  26. beanDefinitionReader.setEnvironment(getEnvironment());
  27. // 将 ResourceLoader 换成 XmlWebApplicationContext 对象
  28. // XmlWebApplicationContext 实现了 ResourceLoader 接口
  29. beanDefinitionReader.setResourceLoader(this);
  30. beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
  31. // Allow a subclass to provide custom initialization of the reader,
  32. // then proceed with actually loading the bean definitions.
  33. // 允许子类提供reader的自定义初始化
  34. // 然后处理正在加载中的bean definitions
  35. // 此方法是空实现
  36. initBeanDefinitionReader(beanDefinitionReader);
  37. // 3.2加载beanDefinition操作
  38. loadBeanDefinitions(beanDefinitionReader);
  39. }

3.1 XmlBeanDefinitionReader

跟踪3.1XmlBeanDefinitionReader的初始化的过程

  1. // 3.1XmlBeanDefinitionReader的初始化需要了解下
  2. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
  3. /**
  4. * Create new XmlBeanDefinitionReader for the given bean factory.
  5. *
  6. * 通过给定的 bean factory 创建一个新的 XmlBeanDefinitionReader
  7. */
  8. public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
  9. super(registry);
  10. }

先看下几个类的继承关系图。

XmlBeanDefinitionReader的构造入参接受的是BeanDefinitionRegistry,这是工厂默认实现DefaultListableBeanFactory所实现的接口

root web application context 的默认实现是 XmlWebApplicationContext,他实现了ApplicationContext,ApplicationContext有几个上层接口比较重要。

XmlBeanDefinitionReader调用了父类的构造并传递 bean factory,父类构造的注释上做了很多说明:

  1. /**
  2. * Create a new AbstractBeanDefinitionReader for the given bean factory.
  3. * <p>If the passed-in bean factory does not only implement the BeanDefinitionRegistry
  4. * interface but also the ResourceLoader interface, it will be used as default
  5. * ResourceLoader as well. This will usually be the case for
  6. * {@link org.springframework.context.ApplicationContext} implementations.
  7. * <p>If given a plain BeanDefinitionRegistry, the default ResourceLoader will be a
  8. * {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}.
  9. * <p>If the passed-in bean factory also implements {@link EnvironmentCapable} its
  10. * environment will be used by this reader. Otherwise, the reader will initialize and
  11. * use a {@link StandardEnvironment}. All ApplicationContext implementations are
  12. * EnvironmentCapable, while normal BeanFactory implementations are not.
  13. *
  14. *
  15. * 通过给定的 bean factory 创建一个新的 AbstractBeanDefinitionReader。
  16. * 如果传入的 bean factory 不仅仅实现了 BeanDefinitionRegistry 接口,
  17. * 还实现了ResourceLoader接口,那么 bean factory 还会被当做ResourceLoader资源加载器。
  18. * 通常这种情况的 bean factory 它往往是ApplicationContext的实现。
  19. * 如果给定一个简单的BeanDefinitionRegistry实现,那么默认的ResourceLoader采用
  20. * PathMatchingResourcePatternResolver。
  21. * 如果传入的 bean factory 还实现了EnvironmentCapable接口,
  22. * 那么这个 bean factory 的environment会被这个reader所使用。
  23. * 否者这个reader初始化使用默认StandardEnvironment。
  24. * 所有的 ApplicationContext 都实现了 EnvironmentCapable 接口,
  25. * 但是普通的BeanFactory实现并没有实现.
  26. */
  27. protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
  28. Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
  29. //拿到 bean factory 的引用,解析后的beandefinition会放入 bean factory 中
  30. this.registry = registry;
  31. // Determine ResourceLoader to use.
  32. // 确定ResourceLoader资源加载器使用哪一个
  33. if (this.registry instanceof ResourceLoader) {
  34. this.resourceLoader = (ResourceLoader) this.registry;
  35. }
  36. else {
  37. // DefaultListableBeanFactory未实现ResourceLoader,所以走这个
  38. this.resourceLoader = new PathMatchingResourcePatternResolver();
  39. }
  40. // Inherit Environment if possible
  41. // 如果可以的话拿到他的environment
  42. if (this.registry instanceof EnvironmentCapable) {
  43. this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
  44. }
  45. else {
  46. // DefaultListableBeanFactory未实现EnvironmentCapable,所以走这个
  47. // StandardEnvironment初始化的时候就会将systemEnvironment和systemProperties加载进来
  48. this.environment = new StandardEnvironment();
  49. }
  50. }

这样3.1XmlBeanDefinitionReader的初始化也就走完了。

3.2 loadBeanDefinitions

在XmlWebApplicationContext类中,跟踪3.2标记方法

  1. // 3.2加载beanDefinition操作
  2. loadBeanDefinitions(beanDefinitionReader);
  3. /**
  4. * Load the bean definitions with the given XmlBeanDefinitionReader.
  5. * <p>The lifecycle of the bean factory is handled by the refreshBeanFactory method;
  6. * therefore this method is just supposed to load and/or register bean definitions.
  7. * <p>Delegates to a ResourcePatternResolver for resolving location patterns
  8. * into Resource instances.
  9. *
  10. * 使用给定的XmlBeanDefinitionReader加载 bean definitions
  11. * bean factory 的生命周期已经被refreshBeanFactory方法所处理
  12. * 因此这个方法应该仅仅只是加载或者注册 bean definitions
  13. * 委派一个 ResourcePatternResolver 去将 location patterns 解析成资源实例
  14. */
  15. protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
  16. //3.2.1返回 context 的 configLocations,如果没有被指定则返回null
  17. //这里web.xml只配置了一个,就是"classpath:spring/applicationContext.xml"
  18. String[] configLocations = getConfigLocations();
  19. if (configLocations != null) {
  20. for (String configLocation : configLocations) {
  21. //3.2.2加载解析beanDefinitions
  22. reader.loadBeanDefinitions(configLocation);
  23. }
  24. }
  25. }

3.2.1 getConfigLocations

跟踪标记3.2.1的方法

getConfigLocations 方法调用的是父类 AbstractRefreshableWebApplicationContext 的 getConfigLocations 方法

此方法又调用了更上一级父类 AbstractRefreshableConfigApplicationContext 的 getConfigLocations 方法。

  1. //3.2.1返回 context 的配置路径,如果没有被指定则返回null
  2. String[] configLocations = getConfigLocations();
  3. //此方法在AbstractRefreshableWebApplicationContext中
  4. @Override
  5. public String[] getConfigLocations() {
  6. return super.getConfigLocations();
  7. }
  8. //此方法在AbstractRefreshableConfigApplicationContext类中
  9. /**
  10. * Return an array of resource locations, referring to the XML bean definition
  11. * files that this context should be built with. Can also include location
  12. * patterns, which will get resolved via a ResourcePatternResolver.
  13. * <p>The default implementation returns {@code null}. Subclasses can override
  14. * this to provide a set of resource locations to load bean definitions from.
  15. *
  16. * 返回一个资源路径的数组,它参照了 context 应该构建的xml bean definition文件。
  17. * 也可以包含被ResourcePatternResolver解析的location patterns 。
  18. * 默认的实现是返回一个null,子类可以覆盖并提供一个资源路径的集合从中加载bean definitions
  19. */
  20. protected String[] getConfigLocations() {
  21. //在web.xml文件中已经配置了contextConfigLocation属性,
  22. //所以变量configLocations值为classpath:spring/applicationContext.xml
  23. //顺便看如果configLocations为null,getDefaultConfigLocations()方法怎么实现的
  24. return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
  25. }
  26. //此方法在XmlWebApplicationContext类中
  27. /**
  28. * The default location for the root context is "/WEB-INF/applicationContext.xml",
  29. * and "/WEB-INF/test-servlet.xml" for a context with the namespace "test-servlet"
  30. * (like for a DispatcherServlet instance with the servlet-name "test").
  31. *
  32. * root context 默认路径是"/WEB-INF/applicationContext.xml"
  33. * 名称空间为"test-servlet"的上下文路径为"/WEB-INF/test-servlet.xml"
  34. * 像DispatcherServlet实例就是用"test"的servlet-name
  35. */
  36. @Override
  37. protected String[] getDefaultConfigLocations() {
  38. if (getNamespace() != null) {
  39. // "/WEB-INF/" + 名称空间 + ".xml"
  40. return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
  41. }
  42. else {
  43. // "/WEB-INF/applicationContext.xml"
  44. return new String[] {DEFAULT_CONFIG_LOCATION};
  45. }
  46. }

3.2.2 loadBeanDefinitions

跟踪标记3.2.2的方法,利用reader加载解析beanDefinitions

BeanDefinitionReader接口中对这个方法做了定义

AbstractBeanDefinitionReader中实现了这个方法

  1. //3.2.2加载解析beanDefinitions
  2. reader.loadBeanDefinitions(configLocation);
  3. //在AbstractBeanDefinitionReader类中
  4. /**
  5. * Load bean definitions from the specified resource location.
  6. * <p>The location can also be a location pattern, provided that the
  7. * ResourceLoader of this bean definition reader is a ResourcePatternResolver.
  8. *
  9. * 从指定的资源路径加载bean definitions
  10. * 如果bean definition reader的ResourceLoader资源加载器是ResourcePatternResolver
  11. * 那么这路径也可以是location pattern
  12. */
  13. @Override
  14. public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
  15. return loadBeanDefinitions(location, null);
  16. }
  17. //在AbstractBeanDefinitionReader类中
  18. public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
  19. //这里拿到的是 root web application context,ApplicationContext接口有继承ResourceLoader接口
  20. ResourceLoader resourceLoader = getResourceLoader();
  21. if (resourceLoader == null) {
  22. throw new BeanDefinitionStoreException(
  23. "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
  24. }
  25. //ApplicationContext接口也有继承ResourcePatternResolver接口
  26. if (resourceLoader instanceof ResourcePatternResolver) {
  27. // Resource pattern matching available.
  28. // 可以使用Resource pattern做匹配
  29. try {
  30. // 3.2.2.1通过路径获取 资源处理器 数组
  31. Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
  32. // 3.2.2.2通过 资源处理器 加载 BeanDefinitions
  33. int loadCount = loadBeanDefinitions(resources);
  34. // 这里传过来是null,跳过
  35. if (actualResources != null) {
  36. for (Resource resource : resources) {
  37. actualResources.add(resource);
  38. }
  39. }
  40. if (logger.isDebugEnabled()) {
  41. logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
  42. }
  43. return loadCount;
  44. }
  45. catch (IOException ex) {
  46. throw new BeanDefinitionStoreException(
  47. "Could not resolve bean definition resource pattern [" + location + "]", ex);
  48. }
  49. }
  50. else {
  51. // Can only load single resources by absolute URL.
  52. // 只能加载绝对URL路径的单一资源
  53. Resource resource = resourceLoader.getResource(location);
  54. int loadCount = loadBeanDefinitions(resource);
  55. if (actualResources != null) {
  56. actualResources.add(resource);
  57. }
  58. if (logger.isDebugEnabled()) {
  59. logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
  60. }
  61. return loadCount;
  62. }
  63. }
3.2.2.1 getResources

跟踪标记 3.2.2.1的方法。

该方法实际上走的是AbstractApplicationContext的getResources方法,通过 context 的成员属性resourcePatternResolver去解析资源,也就是PathMatchingResourcePatternResolver类的getResources方法

  1. // 3.2.2.1通过路径获取 资源处理器 数组
  2. Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
  3. /**
  4. * Resolve the given location pattern into Resource objects.
  5. * <p>Overlapping resource entries that point to the same physical
  6. * resource should be avoided, as far as possible. The result should
  7. * have set semantics.
  8. *
  9. * 解析指定的location pattern 生成资源对象
  10. * 尽可能的避免指向同一物理资源的多个资源项重复
  11. * 结果应该具有语义
  12. */
  13. @Override
  14. public Resource[] getResources(String locationPattern) throws IOException {
  15. return this.resourcePatternResolver.getResources(locationPattern);
  16. }

PathMatchingResourcePatternResolver实现了ResourcePatternResolver接口。在看他的实现前,先看下两个常量的定义。


  1. /**
  2. * Pseudo URL prefix for all matching resources from the class path: "classpath*:"
  3. * This differs from ResourceLoader's classpath URL prefix in that it
  4. * retrieves all matching resources for a given name (e.g. "/beans.xml"),
  5. * for example in the root of all deployed JAR files.
  6. * @see org.springframework.core.io.ResourceLoader#CLASSPATH_URL_PREFIX
  7. *
  8. * 从类路径中匹配所有资源的伪URL前缀:"classpath*:"
  9. * 他和ResourceLoader的类路径URL前缀("classpath:")有所不同
  10. * 他通过指定名称(例如 "/beans.xml"),检索所有的匹配资源,像在根中的被部署的所有jar文件
  11. */
  12. String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
  13. /**
  14. * Pseudo URL prefix for loading from the class path: "classpath:"
  15. *
  16. * 从类路径中加载的伪URL前缀:"classpath:"
  17. */
  18. String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
  19. @Override
  20. public Resource[] getResources(String locationPattern) throws IOException {
  21. Assert.notNull(locationPattern, "Location pattern must not be null");
  22. //因为web.xml中配置的是"classpath:" ,所以走第二个条件
  23. if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
  24. // a class path resource (multiple resources for same name possible)
  25. // 一个类路径资源(一样的名称可能有多个资源)
  26. if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
  27. // a class path resource pattern
  28. // 一个类路径的 resource pattern
  29. // 能进入这个条件,说明除去前缀的后面那一部分中,带有*或者?等表达式
  30. return findPathMatchingResources(locationPattern);
  31. }
  32. else {
  33. // all class path resources with the given name
  34. // 给定名称的所有类路径资源
  35. return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
  36. }
  37. }
  38. else {
  39. // Only look for a pattern after a prefix here
  40. // (to not get fooled by a pattern symbol in a strange prefix).
  41. // 只查找前缀后的pattern,也就是"classpath:spring/applicationContext.xml"中的
  42. // "spring/applicationContext.xml"部分,(classpath可能带*,后面的路径也可能带*)
  43. // 不要被在奇怪前缀中的pattern符号所迷惑
  44. int prefixEnd = locationPattern.indexOf(":") + 1;
  45. // 这里的判断和前面一样,看后部分有没有带*或者?等Pattern
  46. if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
  47. // a file pattern
  48. // 匹配pattern的文件
  49. return findPathMatchingResources(locationPattern);
  50. }
  51. else {
  52. // a single resource with the given name
  53. //指定名称的单一资源文件
  54. //web.xml中没有用通配符,所以走这个。
  55. //getResourceLoader返回的是 root web application context,
  56. //getResource方法进的是DefaultResourceLoader类中,
  57. //DefaultResourceLoader是 root web application context 的上层父类,进入这个方法
  58. return new Resource[] {getResourceLoader().getResource(locationPattern)};
  59. }
  60. }
  61. }
  62. /**
  63. * Return a Resource handle for the specified resource.
  64. * The handle should always be a reusable resource descriptor,
  65. * allowing for multiple {@link Resource#getInputStream()} calls.
  66. * <p><ul>
  67. * <li>Must support fully qualified URLs, e.g. "file:C:/test.dat".
  68. * <li>Must support classpath pseudo-URLs, e.g. "classpath:test.dat".
  69. * <li>Should support relative file paths, e.g. "WEB-INF/test.dat".
  70. * (This will be implementation-specific, typically provided by an
  71. * ApplicationContext implementation.)
  72. * </ul>
  73. * <p>Note that a Resource handle does not imply an existing resource;
  74. * you need to invoke {@link Resource#exists} to check for existence.
  75. *
  76. * 根据指定的资源返回一个资源处理器
  77. * 这个处理器是一个能够被重复使用的资源描述符
  78. * 允许多种输入流的调用方式
  79. * 一定支持完全限定URLS,例如 "file:C:/test.dat".
  80. * 一定支持类路径伪URLS,例如 "classpath:test.dat".
  81. * 应该支持相对文件路径,例如 "WEB-INF/test.dat".
  82. *(通常根据不同的ApplicationContext实现,这个方法的相应实现也不一样)
  83. * 注意,资源处理器并不意味着一个真实存在的资源,需要调用exists方法去检测
  84. */
  85. @Override
  86. public Resource getResource(String location) {
  87. Assert.notNull(location, "Location must not be null");
  88. // 没有协议解析器,跳过
  89. for (ProtocolResolver protocolResolver : this.protocolResolvers) {
  90. Resource resource = protocolResolver.resolve(location, this);
  91. if (resource != null) {
  92. return resource;
  93. }
  94. }
  95. if (location.startsWith("/")) {
  96. return getResourceByPath(location);
  97. }
  98. //走的这个
  99. else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
  100. //前缀被干掉
  101. return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
  102. }
  103. else {
  104. try {
  105. // Try to parse the location as a URL...
  106. // 尝试作为一个URL去解析
  107. URL url = new URL(location);
  108. return new UrlResource(url);
  109. }
  110. catch (MalformedURLException ex) {
  111. // No URL -> resolve as resource path.
  112. // 不是URL,还是作为资源路径去解析
  113. return getResourceByPath(location);
  114. }
  115. }
  116. }
3.2.2.2 loadBeanDefinitions

跟踪标记3.2.2.2的方法

此方法在类AbstractBeanDefinitionReader中

  1. // 3.2.2.2通过 资源处理器 加载 BeanDefinitions
  2. int loadCount = loadBeanDefinitions(resources);
  3. @Override
  4. public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
  5. Assert.notNull(resources, "Resource array must not be null");
  6. int counter = 0;
  7. for (Resource resource : resources) {
  8. counter += loadBeanDefinitions(resource);
  9. }
  10. return counter;
  11. }

counter += loadBeanDefinitions(resource); -> 此方法里面的内容非常多,单独开了一篇文章:

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

接下来跟踪prepareBeanFactory方法:

https://www.jianshu.com/p/3468118a31f9

总结

  • 已经有 BeanFactory ,摧毁相关Bean并关闭工厂
  • 1.创建一个 bean factory
  • 将 context 的 id 设置为 bean factory 的序列化id,并建立起id和该 bean factory 实例的映射关系
  • 2.自定义内部的 bean factory
  • 3.加载 beanDefinition
  • 返回刷新后的 BeanFactory

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

  • 1
  • 创建 bean factory,默认 DefaultListableBeanFactory
  • 添加依赖忽略接口,这些接口不会被自动注入。通常由 application contexts 注册这些以其他方式解析的依赖。
  • 如果 application contexts 有 parent,将这个 parent 内部的 bean factory 或者 parent 本身作为 bean factory 的parentBeanFactory,依据的条件是 parent 是否是 ConfigurableApplicationContext 的子类。

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

  • 2
  • 相同名称的不同bean definition能否被重复注册,默认为true
  • 是否尝试自动去解决两个bean之间的循环引用问题,默认为 true

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

  • 3
  • 为指定的 BeanFactory 创建一个新的 XmlBeanDefinitionReader,并设置 environment、resourceLoader 属性
  • 获取spring配置文件路径,如果web.xml中没有配置,默认去/WEB-INF/下查找
  • 3.2.2 利用创建的Reader实例去解析配置文件路径

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

  • 3.2.2
  • 解析配置文件路径生成 Resource 对象。资源的伪URL前缀classpath只加载类路径下的资源,classpath*检索所有的匹配资源,包括jar文件。
  • 遍历所有的Resource对象,一一解析生成 BeanDefinition

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

  1. prepareRefresh方法源码跟踪

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

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

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

  3. postProcessBeanFactory方法源码跟踪

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

  4. prepareBeanFactory方法源码跟踪

    看这篇文章之前可以先了解之前的跟踪流程,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. Python 之并发编程之线程中

    四.线程锁lock(线程的数据安全) 在数据量较大的时候,线程中的数据会被并发,所有数据会不同步,以至于数据会异常. 下面还介绍了两种的上锁方法. 例: from threading import T ...

  2. PAT T1009 Triple Inversions

    树状数组判断三元逆序对~ #include<bits/stdc++.h> using namespace std; ; int a[maxn]; ]; long long l[maxn], ...

  3. Educational Codeforces Round 72 (Rated for Div. 2)C(暴力)

    #define HAVE_STRUCT_TIMESPEC#include<bits/stdc++.h>using namespace std;char s[200007];int a[20 ...

  4. 小KING教你做android项目(二)---实现登陆页面并跳转和简单的注册页面

    原文:http://blog.csdn.net/jkingcl/article/details/10989773       今天我们主要来介绍登陆页面的实现,主要讲解的就是涉及到的布局,以及简单的跳 ...

  5. 二、linux基础-路径和目录_用户管理_组_权限

    2.1路径和目录1.相对路径:参照当前目录进行查找.   如:[root@localhost ~]# cd ../opt/hosts/备注:相对路径是从你的当前目录开始为基点,去寻找另外一个目录(或者 ...

  6. 「国家集训队」小Z的袜子

    「国家集训队」小Z的袜子 传送门 莫队板子题. 注意计算答案的时候,由于分子分母都要除以2,所以可以直接约掉,这样在开桶算的时候也方便一些. 参考代码: #include <algorithm& ...

  7. windows下hashcat利用GPU显卡性能破解密码

    由于一般密码破解工具的破解速度实在是太慢,而且支持的密码破解协议也不多,暴力破解的话,有的密码1年时间也破不出来,用字典跑的话必须要明文密码在字典里才行,而且密码字典太大的话,也很浪费时间,跑不出来也 ...

  8. 使用JNA替代JNI调用本地方法

    JNA全称是Java Native Access,是Sun推出的一种调用本地方法技术,比起它的同门师兄JNI,JNA大大简化了调用本地方法的过程,使用也比较方便, JNA是在JNI的基础上完善的,用青 ...

  9. [Database] MAC MySQL中文乱码问题

    1 确保数据库编码设置, 可修改my.cnf mysql> show variables like '%character%'; +--------------------------+---- ...

  10. Leet Code 8.字符串转换整数

    实现一个atoi函数,使其能将字符串转成整数,根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止.当我们寻找到的第一个非空字符为正或负号时,则将该符号与后面尽可能多的连续数字组合起来,作 ...