public class DemoApplication {
public static void main(String[] args) {
// 通过XmlBeanFactory加载bean.xml文件。
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("BeanFactoryTest.xml"));
// 读取bean的对象。
Person person = (Person) factory.getBean("person");
System.out.println(person);
}
}
上面时序图的第2步就是完成将配置文件BeanFactoryTest.xml封装为Resource的实例。
Resource接口抽象了所有Spring内部使用到的底层资源:File、URL、ClassPath等。
下面是Resource接口的实现类。
ContextResource (org.springframework.core.io)
HeadMethodResource in ResourceHandlerFunction (org.springframework.web.servlet.function)
HttpResource (org.springframework.web.servlet.resource)
WritableResource (org.springframework.core.io)
AbstractResource (org.springframework.core.io)
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);// 初始化1
this.reader = new XmlBeanDefinitionReader(this);//初始化2
this.reader.loadBeanDefinitions(resource);
}
SimpleAliasRegistry (org.springframework.core)
DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
FactoryBeanRegistrySupport (org.springframework.beans.factory.support)
AbstractBeanFactory (org.springframework.beans.factory.support)
AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
DefaultListableBeanFactory (org.springframework.beans.factory.support)
XmlBeanFactory (org.springframework.beans.factoy.xml)
此处的beanDefinitionMap就是存放bena的容器。
public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
super(parentBeanFactory);
this.autowireCandidateResolver = SimpleAutowireCandidateResolver.INSTANCE;
this.resolvableDependencies = new ConcurrentHashMap(16);
this.beanDefinitionMap = new ConcurrentHashMap(256);
this.mergedBeanDefinitionHolders = new ConcurrentHashMap(256);
this.allBeanNamesByType = new ConcurrentHashMap(64);
this.singletonBeanNamesByType = new ConcurrentHashMap(64);
this.beanDefinitionNames = new ArrayList(256);
this.manualSingletonNames = new LinkedHashSet(16);
}
(简单点:doLoadBeanDefinitions(inputSource, encodedResource.getResource());方法进行加载操作。)
此处进行的操作主要有三个:
// 1.封装资源文件。 此处将Resource实现进行再次封装为EncodedResource实现,进行编码设置。
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (this.logger.isTraceEnabled()) {
this.logger.trace("Loading XML bean definitions from " + encodedResource);
}
// 将当前加载的所有Resource实现都放到一个Set容器中。并且该Set是一个ThreadLocal对象。
// private final ThreadLocal> resourcesCurrentlyBeingLoaded;
Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
if (!currentResources.add(encodedResource)) {//当该set中以存在该encodedResource,则说明其已被加载,存在循环加载的错误。
throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
} else {
int var6;
try {
// 2. 获取输入流。从EncodedResource中获取封装的Resource对象得到输入流,构造下面的InputSource。
InputStream inputStream = encodedResource.getResource().getInputStream();
Throwable var4 = null;
try {
doLoadBeanDefinitions inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//3. 此处是加载Bean的真正的方法。
var6 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
} catch (Throwable var24) {
var4 = var24;
throw var24;
} finally {
if (inputStream != null) {
if (var4 != null) {
try {
inputStream.close();
} catch (Throwable var23) {
var4.addSuppressed(var23);
}
} else {
inputStream.close();
}
}
}
} catch (IOException var26) {
throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var26);
} finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
return var6;
}
}
主要操作步骤:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
// 1. 验证并获取Document对象
Document doc = this.doLoadDocument(inputSource, resource);
// 2. 注册xml对象到BeanDefinitionMap容器中。
int count = this.registerBeanDefinitions(doc, resource);
return count;
}
xml的验证模式分为DTD和XSD。
DTD主要校验文档的格式,使用规则,标签,元素使用是否正确。XSD主要校验文档的内容和结果是否正确。
<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">
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, this.getEntityResolver(), this.errorHandler, this.getValidationModeForResource(resource), this.isNamespaceAware());
}
// 获取资源的验证模式
protected int getValidationModeForResource(Resource resource) {
int validationModeToUse = this.getValidationMode();
if (validationModeToUse != 1) {// 检测是否手动指定了验证模式
return validationModeToUse;
} else {
int detectedMode = this.detectValidationMode(resource);
return detectedMode != 1 ? detectedMode : 3;
}
}
// Spring默认的验证模式。
protected int detectValidationMode(Resource resource) {
if (resource.isOpen()) {
throw new BeanDefinitionStoreException("Passed-in Resource [" + resource + "] contains an open stream: cannot determine validation mode automatically. Either pass in a Resource that is able to create fresh streams, or explicitly specify the validationMode on your XmlBeanDefinitionReader instance.");
} else {
InputStream inputStream;
try {
inputStream = resource.getInputStream();
} catch (IOException var5) {
throw new BeanDefinitionStoreException("Unable to determine validation mode for [" + resource + "]: cannot open InputStream. Did you attempt to load directly from a SAX InputSource without specifying the validationMode on your XmlBeanDefinitionReader instance?", var5);
}
try {
//该方法会获xml文件的头部进行校验。
return this.validationModeDetector.detectValidationMode(inputStream);
} catch (IOException var4) {
throw new BeanDefinitionStoreException("Unable to determine validation mode for [" + resource + "]: an error occurred whilst reading from the InputStream.", var4);
}
}
}
获取XML文档的校验模式,包含DOCTYPE就是DTD,不包含就是XSD.
// 返回 3 代表XSD模式,2代表DTD模式。
public int detectValidationMode(InputStream inputStream) throws IOException {
// 读取xml文档的读取器。
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
byte var4;
try {
boolean isDtdValidated = false;
while(true) {
String content;
// 读取一行文本=》
if ((content = reader.readLine()) != null) {
content = this.consumeCommentTokens(content);
if (this.inComment || !StringUtils.hasText(content)) {//如果读取的行是注释或空则跳过。
continue;
}
// 对比是否包含校验字符。
if (this.hasDoctype(content)) {
isDtdValidated = true;
} else if (!this.hasOpeningTag(content)) {
continue;
}
}
int var5 = isDtdValidated ? 2 : 3;
return var5;
}
} catch (CharConversionException var9) {
var4 = 1;
} finally {
reader.close();
}
return var4;
}
// 对比是否包含校验字符。
private boolean hasDoctype(String content) {
return content.contains("DOCTYPE");
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
int countBefore = this.getRegistry().getBeanDefinitionCount();
// 注册bean
documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
return this.getRegistry().getBeanDefinitionCount() - countBefore;
}
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
// 注册bean的具体方法
this.doRegisterBeanDefinitions(doc.getDocumentElement());
}
protected void doRegisterBeanDefinitions(Element root) {
//专门处理解析
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute("profile");
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
if (!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
}
return;
}
}
}
// 解析前处理,留给子类实现
this.preProcessXml(root);
// 解析当前bean对象的方法。
this.parseBeanDefinitions(root, this.delegate);
// 解析后处理,留给子类实现
this.postProcessXml(root);
this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// Spring默认命名空间的xml进行解析。对beans处理
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;
if (delegate.isDefaultNamespace(ele)) {
// 对bean处理
this.parseDefaultElement(ele, delegate);
} else {
delegate.parseCustomElement(ele);//对自定义命名空间进行解析
}
}
}
} else {
delegate.parseCustomElement(root);
}
}
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// 对不同的标签进行解析
if (delegate.nodeNameEquals(ele, "import")) {
this.importBeanDefinitionResource(ele);
} else if (delegate.nodeNameEquals(ele, "alias")) {
this.processAliasRegistration(ele);
} else if (delegate.nodeNameEquals(ele, "bean")) {
this.processBeanDefinition(ele, delegate);// 主要看对bean的解析
} else if (delegate.nodeNameEquals(ele, "beans")) {
this.doRegisterBeanDefinitions(ele);
}
}
//解析bean标签
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 将注册bean的任务委托给BeanDefinitionReaderUtils。
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
} catch (BeanDefinitionStoreException var5) {
this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
}
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
BeanDefinitionHolder创建的BeanDefinition是xml中标签属性对象。
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
// 执行注册的方法 将bean封装为可以
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
String[] var4 = aliases;
int var5 = aliases.length;
for(int var6 = 0; var6 < var5; ++var6) {
String alias = var4[var6];
registry.registerAlias(beanName, alias);
}
}
}
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)beanDefinition).validate();
} catch (BeanDefinitionValidationException var8) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8);
}
}
BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!this.isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
if (existingDefinition.getRole() < beanDefinition.getRole()) {
if (this.logger.isInfoEnabled()) {
this.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 (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
}
} else if (this.logger.isTraceEnabled()) {
this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
}
// 终点:将bean放入Spring容器中。此处
this.beanDefinitionMap.put(beanName, beanDefinition);
} else {
if (this.hasBeanCreationStarted()) {
synchronized(this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
this.removeManualSingletonName(beanName);
}
} else {
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition == null && !this.containsSingleton(beanName)) {
if (this.isConfigurationFrozen()) {
this.clearByTypeCache();
}
} else {
this.resetBeanDefinition(beanName);
}
}
<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="person" class="com.mt.domain.Person">
<property name="name" value="毛桃"/>
<property name="age" value="18"/>
bean>
beans>
Spring加载xml文件就通过一系列的准备工作,将xml中个标签对象封装为一个BeanDefinition对象,以beanName为key放入到Spring的beanDefinitionMap容器中。
BeanDefinition对象具有id、class等属性。