一、Spring的几个类说明
1.1 BeanDefinition
Spring框架在各大框架中相当于管理员的角色,而管理员调度的单位是Bean,然后BeanDefinition就是框架内部对Bean的定义,BeanDefinition描述和定义了创建一个Bean需要的所有信息,属性,构造函数参数以及访问它们的方法。还有其他一些信息,比如这些定义来源自哪个类等等信息;
1.2 Resource
Resource 接口是 Spring 资源访问策略的抽象,它本身并不提供任何资源访问实现,具体的资源访问由该接口的实现类完成——每个实现类代表一种资源访问策略。
Resource一般包括这些实现类:UrlResource、ClassPathResource、FileSystemResource、ServletContextResource、InputStreamResource、ByteArrayResource
1.3 BeanFactory
BeanFactory,以Factory结尾,表示它是一个工厂类(接口),用于管理Bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
Spring为我们提供了许多易用的BeanFactory实现,XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。
1.4 ApplicationListener
是一个接口,里面只有一个onApplicationEvent方法。如果在上下文中部署一个实现了ApplicationListener接口的bean,那么每当在一个ApplicationEvent发布到 ApplicationContext时,调用ApplicationContext.publishEvent()方法,这个bean得到通知。类似于Oberver设计模式。
1.5 BeanFactory的主要继承关系
二、BeanDefinition的创建过程
2.1 加载BeanDefiniton的入口
// 从spring-loy-bean.xml文件中加载资源
Resource classPathResource = new ClassPathResource("spring-loy-beans.xml");
// 创建bean工厂,用于处理beanDefinition信息
BeanFactory factory = new DefaultListableBeanFactory();
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) factory;
// 使用BeanDefinitonReader将信息加载到registry中
BeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
// 通过reader加载真正的xml文件中的Bean信息
reader.loadBeanDefinitions(classPathResource);
这里的入口即为reader.loadBeanDefinitons(classPathResoure);
2.2 进入源码分析加载过程
2.2.1 首先会进入XmlBeanDefinitionReader类的loadBeanDefinitions方法
该实现类是reader的实现类,因为我们解析的是xml文件,所以自然实现类为XmlBeanDefinitionReader.
/**
* 从指定的xml文件中加载bean definitions信息
* Load bean definitions from the specified XML file.
*/
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
2.2.2 继续进入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.getResource());
}
// 为了线程能使用同一个 currentResources
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
// 这里其实就是为了避免循环加载,如果重复加载了相同的文件就会抛出异常
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected recursive loading of " + encodedResource + " - check your import definitions!");
}
try {
// 获取到文件输入流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 从资源文件中加载beanDefinitons信息
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.set(null);
}
}
}
其实这个方法的关键方法就是doLoadBeanDefinitions(inputSource, encodedResource.getResource()),真正开始进入读取文件。
2.2.3 进入doLoadBeanDefinitions(inputSource, encodedResource.getResource())方法
/**
* 真正从指定的XML文件加载beanDefinition信息的方法
* Actually load bean definitions from the specified XML file.
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 将xml文件信息读取到document类中
Document doc = doLoadDocument(inputSource, resource);
// 注册DOM文档中包含的beanDefinition
return registerBeanDefinitions(doc, resource);
}
// 省略异常处理代码
...
}
2.2.4 进入registerBeanDefinitions方法
在这个方法里创建了BeanDefinitionDocumentReader,解析、注册BeanDefinition的工作又委托给了它
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(getEnvironment());
//获取BeanDefinition的registry对象,DefaultListableBeanFactory,初始化XmlBeanDefinitionReader时进行的设置
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
//BeanDefinition读取过程中传递的上下文,封装相关的的配置和状态
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
继续解析
/**
* 根据给定的root中注册每个beanDefinition
*/
protected void doRegisterBeanDefinitions(Element root) {
//beans标签的profile属性
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getEnvironment().acceptsProfiles(specifiedProfiles)) {
return;
}
}
// 创建一个代理类,用于解析xml文件
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(this.readerContext, root, parent);
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
方法开始判断是否包含profile属性,如果存在校验环境变量是进行了设置。profile的作用类似maven的profile,可以做到开发、测试、生产环境的切换。