环境准备
主函数
public static void main(String[] args) {
BeanFactory beanFactory=new XmlBeanFactory(new ClassPathResource("application.xml"));
A a= (A) beanFactory.getBean("a");
System.out.println(a);
}
XmlBeanFactory类图
配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="a" class="com.hehe.A">
</bean>
</beans>
构造函数
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory); //调用父类构造方法
//将解析配置文件的事情交给XmlBeanDefinitionReader解决
this.reader.loadBeanDefinitions(resource);
}
}
XmlBeanFactory将自己封装进XmlBeanDefinitionReader中,由loadBeanDefinitions()方法去解析配置文件形成bean定义,这里有点像策略设计模式BeanDefinitionReader为策略接口,XmlBeanDefinitionReader是策略具体接口,XmlBeanFactory是策略调用者
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//对文件进行编码处理
return loadBeanDefinitions(new EncodedResource(resource));
}
主要做了
1将资源放入threadLocal中,标记为正在加载,目的防止资源加载循环依赖加载
2.获取资源的流真正加载资源doLoadBeanDefinitions
3.关闭流,移除threadLocal的元素
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);
}
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 {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//真正加载资源
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();
}
}
}
主要做了将资源解析为Document节点对象,和xml节点类似
解析Document对象
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//将资源解析为Document
Document doc = doLoadDocument(inputSource, resource);
//解析Document
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);
}
}
1本方法主要去解析配置document对象,成为beanDefinitions
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//新建一个BeanDefinitionDocumentReader对象
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//获取BeanDefinitionMap的大小
int countBefore = getRegistry().getBeanDefinitionCount();
//解析document对象
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//统计这次解析了多少个BeanDefinition
return getRegistry().getBeanDefinitionCount() - countBefore;
}
将BeanDefinitionReader封装到XmlReaderContext中,交给BeanDefinitionDocumentReader解析document
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
//设置ReaderContext对象
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
//获取beans标签信息
Element root = doc.getDocumentElement();
//终于开始解析beans标签了
doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
//这里解析beans标签的信息,这里先不关心,我只对只标签感兴趣
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);
//真正解析
parseBeanDefinitions(root, this.delegate);
//后置处理
postProcessXml(root);
this.delegate = parent;
}
终于来到解析beans标签的子标签方法了
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;
if (delegate.isDefaultNamespace(ele)) {
//解析默认标签
parseDefaultElement(ele, delegate);
}
else {
//解析自定义标签
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
流程图