spring源码深度解析—容器的基本实现,你知多少?( 三 )


public interface InputStreamSource { InputStream getInputStream() throws IOException;}public interface Resource extends InputStreamSource { boolean exists(); default boolean isReadable() { return true; } default boolean isOpen() { return false; } default boolean isFile() { return false; } URL getURL() throws IOException; URI getURI() throws IOException; File getFile() throws IOException; default ReadableByteChannel readableChannel() throws IOException { return Channels.newChannel(getInputStream()); } long contentLength() throws IOException; long lastModified() throws IOException; Resource createRelative(String relativePath) throws IOException; String getFilename(); String getDescription();}【spring源码深度解析—容器的基本实现,你知多少?】通过源码我们了解到InputStreamSource封装任何能返回InputStream的类 , 比如File、Classpath下的资源和Byte Array等 ,  它只有一个方法定义:getInputStream() , 该方法返回一个新的InputStream对象 
Resource接口抽象了所有Spring内部使用到的底层资源:File、URL、Classpath等 。首先 , 它定义了3个判断当前资源状态的方法:存在性(exists)、可读性(isReadable)、是否处于打开状态(isOpen) 。另外 , Resource接口还提供了不同资源到URL、URI、File类型的转换 , 以及获取lastModified属性、文件名(不带路径信息的文件名 , getFilename())的方法 , 为了便于操作 , Resource还提供了基于当前资源创建一个相对资源的方法:createRelative() , 还提供了getDescription()方法用于在错误处理中的打印信息 。 
对不同来源的资源文件都有相应的Resource实现:文件(FileSystemResource)、Classpath资源(ClassPathResource)、URL资源(UrlResource)、InputStream资源(InputStreamResource)、Byte数组(ByteArrayResource)等 , 相关类图如下所示: 

spring源码深度解析—容器的基本实现,你知多少?

文章插图
 
在日常开发中我们可以直接使用spring提供的类来加载资源文件 , 比如在希望加载资源文件时可以使用下面的代码:
Resource resource = new ClassPathResource("spring-bean.xml");InputStream is = resource.getInputStream();当通过Resource相关类完成了对配置文件进行封装后 , 配置文件的读取工作就全权交给XmlBeanDefinitionReader来处理了 。 
接下来就进入到XmlBeanFactory的初始化过程了 , XmlBeanFactory的初始化有若干办法 , Spring提供了很多的构造函数 , 在这里分析的是使用Resource实例作为构造函数参数的办法 , 代码如下:
public XmlBeanFactory(Resource resource) throws BeansException { this(resource, null); } public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { super(parentBeanFactory); this.reader.loadBeanDefinitions(resource);}上面函数中的代码this.reader.loadBeanDefinitions(resource)才是资源加载的真正实现 , 时序图中提到的XmlBeanDefinitionReader加载数据就是在这里完成的 , 但是在XmlBeanDefinitionReader加载数据前还有一个调用父类构造函数初始化的过程:super(parentBeanFactory) , 我们按照代码层级进行跟踪 , 首先跟踪到如下父类代码:
public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) { super(parentBeanFactory);}然后继续跟踪 , 跟踪代码到父类AbstractAutowireCapableBeanFactory的构造函数中:
public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) { this(); setParentBeanFactory(parentBeanFactory);}public AbstractAutowireCapableBeanFactory() { super(); ignoreDependencyInterface(BeanNameAware.class); ignoreDependencyInterface(BeanFactoryAware.class); ignoreDependencyInterface(BeanClassLoaderAware.class);}这里要提及一下ignoreDependencyInterface方法 , 此方法的主要功能是忽略给定接口的自动装配功能 , 目的是:实现了BeanNameAware接口的属性 , 不会被Spring自动初始化 。自动装配时忽略给定的依赖接口 , 典型应用是通过其他方式解析Application上下文注册依赖 , 类似于BeanFactory通过BeanFactoryAware进行注入或者ApplicationContext通过ApplicationContextAware进行注入 。 
5.2 bean加载 
在之前XmlBeanFactory构造函数中调用了XmlBeanDefinitionReader类型的reader属性提供的方法this.reader.loadBeanDefinitions(resource) , 而这句代码则是整个资源加载的切入点 , 这个方法的时序图如下: 
spring源码深度解析—容器的基本实现,你知多少?


推荐阅读