spring 的 IOC 流程(资源定位)

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

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 应用程序开发提供集成的框架。

    948 引用 • 1460 回帖
  • 代码
    467 引用 • 586 回帖 • 9 关注

相关帖子

欢迎来到这里!

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

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