spring-framework源码——配置文件的读取
我们的配置文件很简单,只定义了一个简单java bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myTestBean" class="org.springframework.MyTestBean"></bean>
</beans>
这个bean的内容是这样的
public class MyTestBean {
private String testStr = "testStr";
public String getTestStr() {
return testStr;
}
public void setTestStr(String testStr) {
this.testStr = testStr;
}
}
测试类
ClassPathResource classPathResource = new ClassPathResource("beanFactoryTest.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(classPathResource);
总结一下这个代码做了什么,其实主要方法在reader.loadBeanDefinitions(classPathResource)中。先读取配置类,生成BeanDefinition。然后去注册这个BeanDefinition。注册其实就是在map里面加上当前这个BeanDefinition。
先看第一行new ClassPathResource("beanFactoryTest.xml")
,这里就是简单得把配置文件封装成一个resource。
第二行创建一个factory对象,这里会依次去初始化他的父类对象,也没什么好说的,值得一提的是代码跟踪的父类的一个构造方法中
public AbstractAutowireCapableBeanFactory() {
super();
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
ignoreDependencyInterface方法的说明是
* Ignore the given dependency interface for autowiring. * <p>This will typically be used by application contexts to register * dependencies that are resolved in other ways, like BeanFactory through * BeanFactoryAware or ApplicationContext through ApplicationContextAware. * <p>By default, only the BeanFactoryAware interface is ignored. * For further types to ignore, invoke this method for each type.
大意就是忽略给定接口的自动装配功能,上面的三个接口都会被忽略。
第三行new XmlBeanDefinitionReader(factory)
为给定的工厂创建XmlBeanDefinitionReader对象。
接下来进入重头戏,看看最后一行代码
reader.loadBeanDefinitions(classPathResource);
这行代码其实就可以看出做了什么,通过reader从resource中加载bean的定义。reader就是前面创建的XmlBeanDefinitionReader对象,classPathResource就是我们配置文件的封装。
首先进入loadBeanDefinitions方法
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
这里对我们传入的resource进行了一层封装,变成了EncodedResource,其实就多了encoding和charset属性。但是我们没有指定这两个属性,所以都为空。
进入这个方法,我省略了一些不重要的代码
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
......
try {
//inputStrean和下面的inputSource都不属性spring,来自org.xml.sax
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//主要逻辑实现
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
......
}
finally {
......
}
}
}
这里最重要的就是doLoadBeanDefinitions方法了,spring中以do开头的都是真正做事的。我们来看一下这个方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//获取Document,不做详细介绍,感兴趣可以自己去看代码
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
......
//后面还有各种异常
这里重点就是registerBeanDefinitions方法
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//BeanDefinitionDocumentReader是一个接口,实际实例化为DefaultBeanDefinitionDocumentReader对象
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//记录之前BeanDefinition的数量
int countBefore = getRegistry().getBeanDefinitionCount();
//主要逻辑实现,加载和注册bean
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//返回本次加载的BeanDefinition的数量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
registerBeanDefinitions方法里面主要就是doRegisterBeanDefinitions方法,
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
protected void doRegisterBeanDefinitions(Element root) {
//解析xml中bean的定义(因为在配置文件中可能引用其他配置文件,
//就会有beans中嵌套beans的情况出现,所以使用两个delegate来处理这个问题
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
//处理profile属性
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.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
//解析前处理,留给子类实现
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
//解析后处理,留给子类实现
postProcessXml(root);
this.delegate = parent;
}
这里preProcessXml和postProcessXml中都是空的,其实是一种模板方法模式。
主要来看看parseBeanDefinitions(root, this.delegate)方法。
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
//根据是否是默认的标签,选择对bean解析的方法
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
由于在配置文件中可以自定义标签,所以这里需要判断标签是默认的标签,比如<bean>,还是自己定义的标签,从而选择对应的解析方法。
这里我们只探讨一下默认的标签解析
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//对import标签的处理
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//对alias标签的处理
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//对bean标签的处理
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//对beans标签的处理
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
这里我们只看一下bean标签的处理
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//持有BeanDefinition对象,包括名字和别名
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//自定义标签进行解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
这个方法主要做了四件事情(注释的四个方法)
- 委托BeanDefinitionParserDelegate进行元素解析,保存在BeanDefinitionHolder中。
- bdHolder不为空的情况,如果标签下的子节点有自定义标签,还需要对自定义标签进行解析
- 对bdHolder进行注册
- 发出注册事件,通知相关的监听器
其中1和3是重点,1先通过解析文件生成beanDefinition,然后再进行注册。
先来看看第一步中的parseBeanDefinitionElement方法
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
//id属性
String id = ele.getAttribute(ID_ATTRIBUTE);
//name属性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
//分割name属性(代码省略)
......
String beanName = id;
//在没有指定beanName时使用别名
......
//确保bean的名字没有重复
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
//如果不存在beanName,那么根据spring中的命名规则为当前bean生成对应的bean
...
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
//返回BeanDefinitionHolder
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
这个函数最后返回了一个BeanDefinitionHolder,里面有我们需要的beanDefinition等信息。我们来看一下beanDefinition是如何解析的。记住这里返回了一个BeanDefinitionHolder,等一下我们还要回来。
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
//用来记录状态
this.parseState.push(new BeanEntry(beanName));
String className = null;
//解析class属性
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
//解析parent属性
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
//生成bean definition
//将信息保存在AbstractBeanDefinition的子类-GenericBeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//硬编码解析默认bean的各种属性,可能有十多种吧
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//解析元数据
parseMetaElements(ele, bd);
//解析lookup-method属性
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//解析replace-method属性
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析构造函数参数
parseConstructorArgElements(ele, bd);
//解析property子元素
parsePropertyElements(ele, bd);
//解析qualifier子元素
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
//省略各种异常
}
finally {
this.parseState.pop();
}
return null;
}
通过createBeanDefinition()生成AbstractBeanDefinition,然后对这个对象进一步解析,来看看createBeanDefinition方法
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
throws ClassNotFoundException {
return BeanDefinitionReaderUtils.createBeanDefinition(
parentName, className, this.readerContext.getBeanClassLoader());
}
BeanDefinitionReaderUtils
public static AbstractBeanDefinition createBeanDefinition(
@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setParentName(parentName);
if (className != null) {
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
bd.setBeanClassName(className);
}
}
return bd;
}
GenericBeanDefinition里面定义了parentName的成员变量,在我们的例子中,parentName为null,程序会执行bd.setBeanClassName(className),这里className是我们配置文件定义的class全限定名。
至此,我们拿到了一个简单的AbstractBeanDefinition,后面根据各个属性对AbstractBeanDefinition进行完善,这里就不详细讲了。
我们回到前面的代码
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//持有BeanDefinition对象,包括名字和别名
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//自定义标签进行解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
前面说了这个函数主要做了四件事,我们刚才解析了BeanDefinitionHolder的获得过程,先获得AbstractBeanDefinition,然后用BeanDefinitionHolder封装这个BeanDefinition,得到了这个BeanDefinitionHolder。
第二步,对自定义标签的解析这里就不看了,其实就是对BeanDefinition进行更进一步的封装。
第三步,注册BeanDefinition,我们来看看代码
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
解析出来的BeanDefinition会注册到BeanDefinitionRegistry类型的实例registry中,可以看到这里有两个部分,注册BeanDefinition和注册别名。先看一下BeanDefinition的注册。
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
//主要对于AbstractBeanDefinition属性中的methodOverrides校验,
//校验methodOverrides是否与工厂方法并存或者methodOverrides对应的方法根本不存在
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
//处理bean已经注册的情况
//beanName已经注册,但是配置中设置不允许覆盖,则抛出异常
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
//覆盖bean
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//bean没有注册过
//检查这个工厂的bean是不是已经开始创建了,如果是,则要考虑并发的情况
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
//这里其实就是做了三个操作,只是需要考虑并发,所以都是先复制,再进行增加或删除操作
//三个操作其实就是下面else部分里的三个操作
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
//如果之前beanName已经注册了或者存在singleton的beanName,则重置这个bean对应的缓存
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
这个方法在DefaultListableBeanFactory这个类中,可见这是一个比较重要的类。
在spring4.2.x或者之前的代码中,后面对bean的注册的整段代码都是放在synchronized内的。在后面的版本中对其进行了优化,提高了效率。上面的bean注册主要进行了几个步骤:
-
对AbstractBeanDefinition进行校验,主要针对AbstractBeanDefinition的methodOverrides属性。
-
对beanName已经注册情况的处理。如果设置了不允许bean的覆盖,则抛出异常,否则覆盖,并根据具体情况显示日志。
-
bean不存在的话
3.1 如果还处在启动阶段,那很简单,更新beanDefinitionMap,beanDefinitionNames和manualSingletonNames即可
3.2 如果这个工厂的bean是不是已经开始创建了,则要考虑并发,对beanDefinitionNames和manualSingletonNames的增加和删除操作也要注意。
-
如果之前beanName已经注册了或者存在singleton的beanName,则重置这个bean对应的缓存。
然后我们再来看一下别名的注册。由于在这个例子里面没有别名,所以没法跟踪。我们就看一下SimpleAliasRegistry这个类中的方法,我把一些log相关的代码删掉了。
@Override
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
synchronized (this.aliasMap) {
if (alias.equals(name)) {
this.aliasMap.remove(alias);
}
else {
String registeredName = this.aliasMap.get(alias);
//如果registeredName有值,则说明之前存在了。
if (registeredName != null) {
if (registeredName.equals(name)) {
// An existing alias - no need to re-register
return;
}
if (!allowAliasOverriding()) {
throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
}
//alias循环检测
checkForAliasCircle(name, alias);
//注册alias
this.aliasMap.put(alias, name);
}
}
}
}
其实注册最终就是在aliasMap中添加一个数据,但是在添加之前要经过一系列的验证:
- 如果beanName和aliasName一样,则把这个aliasName删掉。
- 别名已经注册过的情况。如果注册的aliasName指向的beanName和当前的beanName一样,则说明这个bean已经注册过了,直接返回;如果aliasName指向另一个beanName,则看是否设置可以覆盖,不能的话抛出异常,否则就覆盖。
- alias循环检测.
- 注册alias
完成了beanDefinition的注册,算是完成了前面四部曲的前三步,还记得第四步吗?发送注册事件。
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
public void fireComponentRegistered(ComponentDefinition componentDefinition) {
this.eventListener.componentRegistered(componentDefinition);
}
继续跟踪进去发现是空的。
这个实现其实只是为了扩展,如果开发人员需要对注册BeanDefinition事件进行监听的话,可以将处理逻辑写到监听器中,目前spring中并没有对此事件进行处理。