一.XmlBeanFactory

入口代码:

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

1.配置文件封装

在java中,可以将不同来源的资源文件抽象成URL;

**补:URL和URI的区别:
		 1.URI包含URL,URL定义了资源路径
			2.URL不仅定义了资源路径,还定义了资源的获取方式,比如:**
				http://file.zip
				ftp://file.zip

所以可以通过注册不同的handler来实现不同的文件读取逻辑,比如 http:ftp等等

但是URL并没有定义类似classpath或者ServletContext等URL的handler,虽然可以通过注册自己的URLStreamHandler来读取,但是还需要了解Java中URL的底层实现机制,而且URL接口没有定义我们需要的一些方法,比如文件是否存在、。当前文件是否可读等等,所以还是自己定义一组读取URL的抽象组件,也就是下面的Resource底层资源封装接口。

public interface InputStreamSource {
...
}
public interface Resource extends InputStreamSource {
...
}

InputStreamSource只封装了一个方法:

InputStream getInputStream();

这个方法封装任何返回InputStream的类,比如File、ClassPath等等。

Resource接口封装了很多关于文件的逻辑方法:

/**
文件状态方法
*/
boolean exists();
boolean isReadable();
boolean isOpen();

/**
文件类型转换
*/
URL getURL();
File getFile();
URI getURI();
/**
文件信息
*/
long lastModified();
String getFileName();
String getDescription();

//创建相对资源
Resource createRelative();

对于不同的文件,Resource接口有着不同的实现类,比如ClassPathResource,FileResource,UrlResource等等。

Resource resource = new ClassPathResource("applicationContext");
InputStream is = resource.getInputStream();

对于Resource是怎么实现的,如果是ClassPathResource,是利用ClassLoader提供的底层方法实现的,FileResource是根据File类直接创建FileInputStream类。

//ClassPathResource
if(this.clazz != null){
	inputStream = this.clazz.getResourceAsStream(this.path);
}

ClassLoader加载类路径资源详解:
ClassLoader详解

将配置文件封装好后,其读取工作就交给XmlBeanDefinitionReader来处理了。

public XmlBeanFactory(Resource resource){
	this(resource,null);
}

public  XmlBeanFactory(Resource resource,BeanFactory parentBeanFactory){
	super(parentBeanFactory);
	//真正加载数据的地方
	this.reader.loadBeanDefinitions(resource);
}

在真正加载配置文件之前,会调用父类的构造器,其代码片段如下:

public AbstractAutowireCapableBeanFactory(){
	super();
	ignoreDependencyInterface(BeanNameAware.class);
	ignoreDependencyInterface(BeanFactoryAware.class);
	ignoreDependencyInterface(BeanClassLoaderAware.calss);
}

这里对ignoreDependencyInterface方法进行一下特别说明:其功能主要是忽略给定的接口的自动装配功能。

ignoreDependencyInterface和ignoreDependencyType

这两个方法都是在spring装配bean时需要忽略装配某些属性时使用的,但是还是有区别;

ignoreDependencyType

比如ignoreDependencyInterface(A.class);

class B{
	private A a;+set、get方法
}

注意:这里使用bean标签进行依赖注入,用autowire注解不适用此方式。
如果在初始化B的时候还未初始化A,会忽略A属性并置为null;

ignoreDependencyInterface

这个方法比较复杂,并不是指实现该接口的类不会被自动装配到某个类的属性当中,而这个方法的真正意思是忽略该接口的实现类中和接口中setter方法入参类型相同的依赖。举个例子:

public interface A{
	void setB(B b);
	void setC(C c)
}
//使用bean标签装备AImpl
public class AImpl implements A{
	private B b;
	private C c;
	public void setB(B b){
		this.b = b;
	}
	public void setC(C c){
		this.c = c;
	}
}

这样ignoreDependencyInterface(A.class)后,就会忽略掉AImpl中的b、c属性装配。

2.加载Bean

入口方法:

//reader是XmlBeanDefinitionReader
this.reader.loadBeanDefinition(resource);

第一步:对Resource对象进行进一步封装;

使用EncodedResource类对Resource进行进一步封装。
EncodedResource主要作用是Resource进行编码的,其中最主要的方法时:

public Reader getReader(){
	if(this.encoding != null){
		return new InputStreamReader(this.resource.getInputStream(),this.encoding);
	}
}

说白了这个类就是用于返回带编码的Reader实现类InputStreamReader。
然后转到了可以复用的loadBeanDefinitions(new EncodedResource())方法
这次才是真正的数据准备阶段

第二步:获取输入流并构造InputSource;

InputSource是SAX解析中的类,用于解析xml文档

InputStream inputStream = encodedResource.getReader().getInputStream();
InputSource inputSource = new InputSource(inputStream);
//设置inputSource的编码
inputSource.setEncoding(encodedResource.getEncoding());

第三步:继续调用doLoadBeanDefinitions;

doLoadBeanDefinitions(inputSource,resource);

这里只做了三件事:

1.获取xml验证模式
2.加载xml,获取Document
3.通过Document注册Bean

猜你喜欢

转载自blog.csdn.net/xkshihaoren/article/details/87871097