上一章看到了BeanFactory的创建过程,只剩下加载配置文件没有看了。现在我们接着this.loadBeanDefinitions(beanDefinitionReader);这行代码继续~
友情提示:方法观看顺序,从上往下看
1、加载配置文件
AbstractXmlApplicationContext类
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
this.initBeanDefinitionReader(beanDefinitionReader);
// 上次讲到这里,去加载配文件~
this.loadBeanDefinitions(beanDefinitionReader);
}
//接着上面的代码
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//xml版的Resource是为空的,所以这里不会有值。不信的话看下面那个方法。
Resource[] configResources = this.getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
//获取ConfigLocations,这里只有ApplicationContext.xml
String[] configLocations = this.getConfigLocations();
if (configLocations != null) {
//这里调用了AbstractBeanDefinitionReader的loadBeanDefinitions方法
reader.loadBeanDefinitions(configLocations);
}
}
protected Resource[] getConfigResources() {
return null;
}
AbstractBeanDefinitionReader类
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
// 循环读取配置文件
for (String location : locations) {
counter += loadBeanDefinitions(location);
}
return counter;
}
//接着上面那个方法的~
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
//接着上面那个方法的~
public int loadBeanDefinitions(String location, [@Nullable](https://my.oschina.net/u/2896689) Set<Resource> actualResources) throws BeanDefinitionStoreException {
// 获取资源加载器
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
// 这里判断了一下资源加载器的类型,但是不管怎么样,都会进loadBeanDefinitions(resources)方法
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
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 {
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;
}
}
// 接着上面那个方法
// 这是一个重载的方法,细心的已经发现和上面第一个方法是一样的,只是参数不一样。
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
for (Resource resource : resources) {
// 实际调用了XmlBeanDefinitionReader的loadBeanDefinitions方法
counter += loadBeanDefinitions(resource);
}
return counter;
}
XmlBeanDefinitionReader类
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
// 这里把resource封装了下
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource);
}
// 看看当前线程中有没有在解析的EncodedResource,没有的话就保存进去,这里是没有的。
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
// 获取文件流,真正的拿到文件信息了~
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
// 解析成xml的文件资源
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 真正将配置文件装换成beanDefinition的方法
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
//接着上面的方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 拿到xml的Document对象,这个大家应该很熟悉了把。。。
Document doc = doLoadDocument(inputSource, resource);
// 注册beanDefinition
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
// 接着上面的方法
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 获取BeanDefinition文档解析器。
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
// 用文档解析器注册BeanDefinition
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
DefaultBeanDefinitionDocumentReader类
// 上一步创建的BeanDefinitionDocumentReader实际上是DefaultBeanDefinitionDocumentReader
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
// 保存一下xml文档
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
// 拿到root节点
Element root = doc.getDocumentElement();
// 真正注册的地方
doRegisterBeanDefinitions(root);
}
// 接着上面的方法
protected void doRegisterBeanDefinitions(Element root) {
// 先将当前的delegate保存起来,因为有可能是递归调用。
BeanDefinitionParserDelegate parent = this.delegate;
// 解析xml并创建Delegate,并保存Delegate的子父关系
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root);
// 真正将xml节点保存进BeanDefinition的方法,具体就是讲xml对应的属性放到BeanDefinition里面去,这里大家有兴趣的话可以点进去看(其实是太复杂了,笔者都绕晕了~)
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
2、BeanDefinition介绍
BeanDefinition保存的就是xml里面的所有配置项,也就是bean的定义,这里随意列举几个
public class AbstractBeanDefinition{
// bean对象
private volatile Object beanClass;
// 作用域,默认单例,可以配成其他的
private String scope = SCOPE_DEFAULT;
// 是否抽象类
private boolean abstractFlag = false;
// 是否懒加载,默认不是
private boolean lazyInit = false;
// 自动加载策略
private int autowireMode = AUTOWIRE_NO;
// 初始化方法名
private String initMethodName;
// 销毁方法名
private String destroyMethodName;
}
小结
Spring启动流程的资源定位和加载已经说完了,真的是各种调用(⊙o⊙)…还发现真正调用方法的地方都加了前缀do,果然是很规范~