BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanTest.xml"));
首先调用ClasspathResource的构造函数来构造Resource资源文件的实例对象,这样后续的资源处理就可以用Resource提供的各种服务来操作了,当有了Resource后就可以进行XmlBeanFactory的初始化了。
在java中,将不同来源的资源抽象成URL,通过注册不同的handler来处理不同来源的资源读取逻辑,一般handler的类型使用不同前缀来识别,如"file:"、"http:"、"jar:"等,然而URL没有默认定义相对于Classpath或servletContext等资源的handler。
spring对其内部使用到的资源实现了自己的抽象结构:Resource接口来封装底层资源。
public interface InputStreamSource {
InputStream getInputStream() throws IOException;
}
public interface Resource extends InputStreamSource {
boolean exists();
boolean isReadable();
boolean isOpen();
URL getURL() throws IOException;
URI getURI() throws IOException;
File getFile() throws IOException;
long contentLength() throws IOException;
long lastModified() throws IOException;
Resource createRelative(String relativePath) throws IOException;
String getFilename();
String getDescription();
}
InputStreamSource封装任何能返回InputStream的类,如File、Classpath下的资源和Byte Array等。
Resource接口抽象了所有Spring内部使用到的底层资源:File、URL、Classpath等。它定义了3个判断当前资源状态的方法:存在性(exist)、可读性(isReadable)、是否处于打开状态(isOpen),还提供了不同资源到URL、URI、File类型的转换,以及获取lastModified属性、文件名的方法。为了便于操作,Resource还提供了基于当前资源创建一个相对资源的方法:createRelative()。getDescription()方法用于在错误处理中打印信息。
对不同来源的资源文件都有相应的Resource实现:文件(FileSystemResource)、Classpath(ClasspathResource)、URL资源(UrlResource)、InputStream(InputStreamResource)、Byte数组(ByteArrayResource)等。
Resource接口的层级结构:
getInputStream()的实现:
ClasspathResource:使用calss或者classLoader提供的底层方法进行调用
public InputStream getInputStream() throws IOException {
InputStream is;
if (this.clazz != null) {
is = this.clazz.getResourceAsStream(this.path);
}
else {
is = this.classLoader.getResourceAsStream(this.path);
}
if (is == null) {
throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
}
return is;
}
FileSystemResource:直接使用FileInputStream对文件进行实例化
public InputStream getInputStream() throws IOException {
return new FileInputStream(this.file);
}
当Resource相关类完成了对配置文件进行 封装后配置文件的读取工作就全权交给XmlBeanDefinitionReader来处理了。
BeanFactory bf = new XmlBeanFactory(Resource resourec);
XmlBeanFactory.java
public XmlBeanFactory(Resource resource) throws BeansException {
//调用第二个构造方法
this(resource, null);
}
//parentBeanFactory为父类BeanFactory用于factory合并,可以为空
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
this.reader.loadBeanDefinitions(resource)才是资源加载的真正实现。
super(parentBeanFactory),跟踪代码到父类AbstractAutowireCapableBeanFactory
AbstractAutowireCapableBeanFactory
public AbstractAutowireCapableBeanFactory() {
super();
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
ignoreDependencyInterface方法的主要功能是忽略给定接口的自动装配功能。举例来说,当A中有属性B,那么当spring在获取A的bean的时候如果其属性B还没有初始化,那么spring自动初始化B,这也是spring中提供的一个重要特性。但是,某些情况下,B不会被初始化,其中的一种情况是B实现了BeanNameAware接口。spring是这样介绍的:自动装配是忽略给定的依赖接口,典型的应用是通过其他方式解析Application上下文注册依赖,类似于BeanFactory通过BeanFactoryAware进行注入或者ApplicationContext通过ApplicationContextAware进行注入。