Spring源码解析—— ClassPathResource类

  一,简单介绍Spring中资源处理相关类

BeanFactory beanFactory=new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));

在Spring中,定义了接口InputStreamSource,这个类中只包含一个方法:

public interface InputStreamSource {

	/**
	 * Return an {@link InputStream}.
	 * <p>It is expected that each call creates a <i>fresh</i> stream.
	 * <p>This requirement is particularly important when you consider an API such
	 * as JavaMail, which needs to be able to read the stream multiple times when
	 * creating mail attachments. For such a use case, it is <i>required</i>
	 * that each {@code getInputStream()} call returns a fresh stream.
	 * @return the input stream for the underlying resource (must not be {@code null})
	 * @throws IOException if the stream could not be opened
	 * @see org.springframework.mail.javamail.MimeMessageHelper#addAttachment(String, InputStreamSource)
	 */
	InputStream getInputStream() throws IOException;

}

    用来返回一个基本的InputStream文件。

    之后,使用Resource接口来规定对文件的一些基本的操作。对于不同来源的件:classpath,file,url,byte,inputstream...进行处理。在我们的应用程序里面,比较常用的就是对我们classpath下的xml文件进行解析的ClassPathResource。

二,ClassPathResource的构造函数

         利用ClassPathResource读取xml配置的基本思路就是通过构造函数传入的文件路径,接着交给class或者classLoader,调用getResourceAsStream获取到InputStream。

       所以,我们的private成员变量是这样子定义的:

public class ClassPathResource extends AbstractFileResolvingResource {

	private final String path;

	private ClassLoader classLoader;

	private Class<?> clazz;

    主要构造函数(存在多个构造函数,但是都差不多啦):

public ClassPathResource(String path, ClassLoader classLoader) {
		Assert.notNull(path, "Path must not be null");
		String pathToUse = StringUtils.cleanPath(path);
		if (pathToUse.startsWith("/")) {
			pathToUse = pathToUse.substring(1);
		}
		this.path = pathToUse;
		this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
	}

    Assert类是spring的一个校验类,比如,如果path为空的话,则会抛出一个异常,异常信息为后面的"Path must not be null"。其实就是封装了一个判断是否为null的操作,查看Assert,发现还有很多类似函数,例如,判断为trueorfalse这种。

     之后处理你自己传入的路径。。。。因为这里默认使用ClassLoader来加载资源,所以,路径开头要去掉“/”。但是如果你不传入classLoader,则classLoader按照如下规则获取:

   

public static ClassLoader getDefaultClassLoader() {
		ClassLoader cl = null;
		try {
			cl = Thread.currentThread().getContextClassLoader();
		}
		catch (Throwable ex) {
			// Cannot access thread context ClassLoader - falling back to system class loader...
		}
		if (cl == null) {
			// No thread context class loader -> use class loader of this class.
			cl = ClassUtils.class.getClassLoader();
		}
		return cl;
	}

     首选我们安全的从当前线程获取类加载器的方法,但是这个方法在 某些情况下会返回null值(可以百度下Thread.currentThread().getContextClassLoader()获取classloader跟使用**Class.getClassLoader()方法有什么不同,如果懒的话,可以看看下面的代码),这个跟JVM的类加载器的层级关系有关。。。

 

/* 测试利用class或者classloader读取文件classpath下的文件 */
	public static void getResourceByClassOrClassLoader() {
		/*
		 * Classloader是从classpath中读取资源的一个类,
		 * 一般我们用classloader来加载class,实际上,但凡是处在classpath中的文件,
		 * 我们称之为资源,都可以用classloader来读取。
		 * 注意,使用classloader来加载资源的时候,目录前面不加“/”
		 */
		System.out.println(TestResource.class.getClassLoader().getResource(
				"applicationContext.xml"));

		/* 这个API的起始路径是当前类的路径,如果要正确的读到资源,目标资源必须和当前class在同一级,或子目录里,可以用相对路径读取到。 */
		System.out.println(TestResource.class
				.getResource("/applicationContext.xml"));

		/*安全用法---提倡使用  From:http://www.cnblogs.com/gaoxing/p/4703412.html*/
		System.out.println( Thread.currentThread().getContextClassLoader().getResource(
				"applicationContext.xml"));

		/*读取到InputStream*/
		InputStream inputStream = TestResource.class.getClassLoader()
				.getSystemResourceAsStream("applicationContext.xml");
		System.out.println(inputStream);

	}

   区分下使用class 还有classLoader 这两种方式getResource在写法跟实现上有什么不同。

   这之后,构造函数完成, XML文件加载完毕。

三,其他方法

   1,示例:exists

@Override
	public boolean exists() {
		URL url;
		if (this.clazz != null) {
			url = this.clazz.getResource(this.path);
		}
		else {
			url = this.classLoader.getResource(this.path);
		}
		return (url != null);
	}

       在对资源文件文件进行操作的时候,我们的首选还是使用Class类来进行操作,因为资源和我类文件的位置是相对固定的,可能这是一种潜规则+默认的写法吧。如果执行构造函数的时候没有传入class来进行初始化,则使用classLoader来判断文件。最 后return (url != null);写法挺简洁!

      这个类里面的getInputStream,getURL,getDescription都是类似的。

       希望没丢掉什么重点。求补充!

 

时间: 2024-11-03 02:03:34

Spring源码解析—— ClassPathResource类的相关文章

Spring源码解析——如何阅读源码(转)

  最近没什么实质性的工作,正好有点时间,就想学学别人的代码.也看过一点源码,算是有了点阅读的经验,于是下定决心看下spring这种大型的项目的源码,学学它的设计思想. 手码不易,转载请注明:xingoo 这篇博文你可以了解到: 1 Spring jar包以及源码使用 2 简单的spring运行示例 3 利用断点调试程序,如何快速的阅读程序[快捷键等的使用] 这次阅读的源码比较老了,是3.0.5版本的,由于正好手头有这个版本的源码,而且平时基本上也是用的这个版本Spring,因此后文的分析也都是

Spring源码解析——配置文件读取相关的类

一,整体结构图       在Spring中,定义了如下类来处理经过经过验证的Document对象,并且对文档元素及属性进行解析. 二,各个类基本介绍            1,ResourceLoader                      public interface ResourceLoader { /** Pseudo URL prefix for loading from the class path: "classpath:" */ String CLASSPAT

Spring源码剖析——Bean的配置与启动

IOC介绍   相信大多数人在学习Spring时 IOC 和 Bean 算得上是最常听到的两个名词,IOC在学习Spring当中出现频率如此之高必然有其原因.如果我们做一个比喻的话,把Bean说成Spring中主角的话,那么IOC便是这个主角进行演出的舞台,没有IOC作为Bean的承载,那么Bean便不会在编程中大放异彩.作为Spring核心组件的重要一员,了解其内部实现对我们编程和窥探Spring内幕是相当有帮助的,下面一步步从源码的角度来剖析IOC究竟是怎样实现的. 接口设计   首先我们先

死磕Spring系列之一:准备阅读Spring源码环境

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://dba10g.blog.51cto.com/764602/1726509 死磕Spring系列前言 死磕spring系列博客,是对Spring进行源码级阅读.工作以来,一直接触spring框架,可以说对spring框架的配置使用已经非常熟练了.个人感觉:Spring技术非常强大,简单的xml标签配置,就可以开启非常强大的支持功能,囊括J2EE企业应用的方方面面.使用归使用,但是却

Spring源码整体架构

前言 Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的.框架的主要优势之一就是其分层架构,分层架构允许您选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架. 从这篇文章开始,我讲开始阅读并介绍 Spring 源码的设计思想,希望能改对 Spring 框架有一个初步的全面的认识,并且学习其架构设计方面的一些理念和方法. Spring 源码地址:https://github.com/spring-projects/spring-framework 概述 Sprin

Spring源码学习之:FactoryBean的使用

转载:http://book.51cto.com/art/201311/419081.htm ==========个人理解========================= FactoryBean和BeanFactory的关系[1]FactoryBean:是一个接口,是一个用户自定义实现类实现该接口的A类.当ioc容器初始化完成后.BeanFactory(ioc容器)调用getBean("beanname")的时候,返回的bean不是A类对应的实例,而是A类getObject()方法返

activiti源码解析重磅来袭

activiti源码解析视频课程大概80课,会一直更新...,目前录制完毕的视频如下: 第2课:Activiti源码获取以及编译第3课:流程引擎配置类的作用,配置方式.开关属性技巧.手动构建.Activiti配置风格.spring配置风格以及使用注意事项.第4课:Activiti配置风格流程引擎配置类以及流程引擎类的初始化过程.ProcessEngines类职责.Activiti使用Spring框架管理这些定义的bean原理.DTD与XSD的区别.获取Spring容器bean第5课:Spring

Java集合学习(十七) TreeSet详细介绍(源码解析)和使用示例

这一章,我们对TreeSet进行学习. 我们先对TreeSet有个整体认识,然后再学习它的源码,最后再通过实例来学会使用TreeSet. 第1部分 TreeSet介绍 TreeSet简介 TreeSet 是一个有序的集合,它的作用是提供有序的Set集合.它继承于AbstractSet抽象类,实现了NavigableSet<E>, Cloneable, java.io.Serializable接口. TreeSet 继承于AbstractSet,所以它是一个Set集合,具有Set的属性和方法.

Java集合学习(十二) TreeMap详细介绍(源码解析)和使用示例

这一章,我们对TreeMap进行学习. 第1部分 TreeMap介绍 TreeMap 简介 TreeMap 是一个有序的key-value集合,它是通过红黑树实现的. TreeMap继承于AbstractMap,所以它是一个Map,即一个key-value集合. TreeMap 实现了NavigableMap接口,意味着它支持一系列的导航方法.比如返回有序的key集合. TreeMap 实现了Cloneable接口,意味着它能被克隆. TreeMap 实现了java.io.Serializabl