spring 的 IOC 流程(资源定位)

本贴最后更新于 2079 天前,其中的信息可能已经水流花落

spring 的 IOC 流程大致可以分为三步:1.资源定位;2.资源解析;3.注册 BeanDefinition
现在,来详细了解一下各个步骤

资源定位

资源定位的最后结果是封装了资源,在 spring 中为 Resource 类,其默认实现类为 FileUrlResource,封装了文件信息。

起始

资源定位的开始在 AbstractBeanDefinitionReader 文件,我们看一下加载资源的代码:

public int loadBeanDefinitions(String location, @Nullable Set actualResources) throws BeanDefinitionStoreException {  
   ResourceLoader resourceLoader = getResourceLoader();  
   if (resourceLoader == null) {  
      throw new BeanDefinitionStoreException(  
            "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");  
   }  
  
   if (resourceLoader instanceof ResourcePatternResolver) {  
  try {  
//在这里,开始将我们传入的文件地址转化为spring封装的Resource类
         Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);  
         int loadCount = loadBeanDefinitions(resources);  
         if (actualResources != null) {  
            for (Resource resource : resources) {  
               actualResources.add(resource);  
            }  
         }  
         if (logger.isDebugEnabled()) {  
            logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");  
         }  
         return loadCount;  
      }  
      catch (IOException ex) {  
         throw new BeanDefinitionStoreException(  
               "Could not resolve bean definition resource pattern [" + location + "]", ex);  
      }  
   }  
   else {  
      // Can only load single resources by absolute URL.  
  Resource resource = resourceLoader.getResource(location);  
      int loadCount = loadBeanDefinitions(resource);  
      if (actualResources != null) {  
         actualResources.add(resource);  
      }  
      if (logger.isDebugEnabled()) {  
         logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");  
      }  
      return loadCount;  
   }  
}

解析

在上面,我们看到定位的主要函数是 getResources,通过此函数可以将资源文件地址转化为 Resource 类,而此函数的主要实现方法在 PathMatchingResourcePatternResolver(如果对此类面生,可以看看 ClassPathXmlApplicationContext 构造方法,在那个构造方法中,调用父类创建了一个默认的 PathMatchingResourcePatternResolver)类中

public Resource[] getResources(String locationPattern) throws IOException {  
   Assert.notNull(locationPattern, "Location pattern must not be null");  
   if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {  
      
  if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {  
    
         return findPathMatchingResources(locationPattern);  
      }  
      else {  
       return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));  
      }  
   }  
   else {  
            int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :  
            locationPattern.indexOf(':') + 1);  
      if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {  
        
          return findPathMatchingResources(locationPattern);  
      }  
      else {  
//我们的测试文件是直接写的路径,既没有classpath前缀也没有war等前缀,所以只执行到了这一步
          return new Resource[] {getResourceLoader().getResource(locationPattern)};  
      }  
   }  
}

封装

上一步,在默认的解析过后,进入了 getResource 方法(DefaultResourceLoader 类中),这个方法将开始进行封装操作,

public Resource getResource(String location) {  
   Assert.notNull(location, "Location must not be null");  
  
   for (ProtocolResolver protocolResolver : this.protocolResolvers) {  
      Resource resource = protocolResolver.resolve(location, this);  
      if (resource != null) {  
         return resource;  
      }  
   }  
  
   if (location.startsWith("/")) {  
      return getResourceByPath(location);  
   }  
   else if (location.startsWith(CLASSPATH_URL_PREFIX)) {  
      return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());  
   }  
   else {  
      try {  
//在这里,将资源文件路径封装为URL,并进一步封装为 FileUrlResource
  URL url = new URL(location);  
         return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));  
      }  
      catch (MalformedURLException ex) {  
         // No URL -> resolve as resource path.  
  return getResourceByPath(location);  
      }  
   }  
}

上面,最终将资源文件路径封装为了 FileUrlResource,整个定位流程结束。

  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    941 引用 • 1458 回帖 • 153 关注
  • 代码
    459 引用 • 591 回帖 • 8 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...