标签:rtc err roc pat 方法 override display 需要 ref
Spring通过ResourceLoader来处理得到的Resource。我们先看下前面提到的ClassPathXmlApplicationContext 类定义:
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
private Resource[] configResources;
public ClassPathXmlApplicationContext(String[] paths, Class clazz, ApplicationContext parent) throws BeansException {
super(parent);
Assert.notNull(paths, "Path array must not be null");
Assert.notNull(clazz, "Class argument must not be null");
this.configResources = new Resource[paths.length];
for (int i = 0; i < paths.length; i++) {
this.configResources[i] = new ClassPathResource(paths[i], clazz);
}
refresh();
}
//这是应用于类路径上的Resource实现,这个getResource是在BeanDefinitionReader类(AbstractXmlApplicationContext)的loadBeanDefinition方法中调用的,
//loadBeanDefinition采用了模板方法设计模式,具体的实现实际是由各个子类来实现的。
@Override
protected Resource[] getConfigResources() {
return this.configResources;
}
}
refresh()方法会开始初始化容器,在refresh()方法中,准备好上下文之后通过obtainFreshBeanFactory()方法获取beanFactory,
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
进入AbstractRefreshableApplicationContext类的refreshBeanFactory()方法:
protected final void refreshBeanFactory() throws BeansException {
//如果已经存在beanfactory则先销毁之后再重新创建
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//通过createBeanFactory()方法创建一个Ioc容器供容器使用,可以看到这个容器的类型是DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
// 启动loadBeanDifinitions来载入BeanDifinition,因为有多种载入方式,这里通过一个抽象函数把具体的实现委托给子类来完成
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
那么ClassPathXmlApplicationContext在哪里如何调用BeanDefinitionLoader来完成对BeanDefinition的读入的呢? Spring设计的时候解耦的非常好,实际上BeanDefinition的定位,读入,注册过程是分开进行的。通过eclipse工具观察调用栈可以看到在ClassPathXmlApplicationContext的父类AbstractXmlApplicationContext的loadBeanDefinitions(XmlBeanDefinitionReader reader)方法中完成了资源文件的获取与读入。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
BeanDefinition的具体载入过程委托给了AbstractRefreshableApplicationContext的子类完成,这里的实现就是在子类AbstartactXmlApplication类中的loadBeanDefinition()方法中完成:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 为指定的BeanFactory创建一个XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 使用此上下文的资源加载环境配置BeanDefinitionReader,由于AbstartactXmlApplication继承了DefaultResourceLoader,所以这里的ResourceLoader传的是this
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader, then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
具体的实现在AbstartctBeanDefinitionReader中:
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//这里的ResourceLoader使用的DefaultResourceLoader
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
//这里对ResourceLoader的路径模式进行解析,比如我们设定的各种Ant格式的路径定义,得到需要的resource集合,即我们已经定义好的BeanDefinition信息,可以是多个文件
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
//调用DefaultResourceLoader的getResource完成具体的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;
}
}
我们看下DefaultResourceLoader类中getReource()方法:
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
//处理带有classpath标识的resource
if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
else {
try {
// 处理带有url标识的resource
URL url = new URL(location);
return new UrlResource(url);
}
catch (MalformedURLException ex) {
//如果既不是classpath也不是url则交给getResourceByPath()方法完成资源加载,这个一般由子类实现
return getResourceByPath(location);
}
}
}
前面我们看到getResourceByPath()会被子类ClassPathXMLApplicationContext实现,这个方法返回的是一个FileSystemResource对象,通过这个对象Spring就可以进行相关的IO操作,完成BeanDefinition的定位。分析到这里我们已经可以得出它实现的就是一个对path进行解析然后生成个FileSystemResource对象返回的过程。到这里就已经完成了Resource的定位过程,在BeanDefinition定位完成的基础上我们就可以通过返回的Resource对象进行BeanDefinition的载入了。
Spring-IOC源码解读2.1-BeanDefinition的Resource定位
标签:rtc err roc pat 方法 override display 需要 ref
原文地址:http://www.cnblogs.com/pepper7/p/7670913.html