Resource resource = new ClassPathResource("applicationContext.xml");
XmlBeanFactory beanFactory = new XmlBeanFactory(resource);
Object bean = beanFactory.getBean("beanName");
以上是很简单的一段代码,只完成了3个Spring的基本操作:
上述代码完成了Spring容器的基本功能,看似简单,但是背后却封装了复杂的逻辑。下面我们结合源码看下Spring到底做了哪些处理。
public interface InputStreamSource {
//返回一个新的InputStream对象
InputStream getInputStream() throws IOException;
}
public interface Resource extends InputStreamSource {
boolean exists();
default boolean isReadable() {
return true;
}
default boolean isOpen() {
return false;
}
default boolean isFile() {
return false;
}
URL getURL() throws IOException;
URI getURI() throws IOException;
File getFile() throws IOException;
default ReadableByteChannel readableChannel() throws IOException {
return Channels.newChannel(getInputStream());
}
long contentLength() throws IOException;
long lastModified() throws IOException;
Resource createRelative(String relativePath) throws IOException;
@Nullable
String getFilename();
String getDescription();
}
public interface BeanDefinitionReader {
BeanDefinitionRegistry getRegistry();
@Nullable
ResourceLoader getResourceLoader();
@Nullable
ClassLoader getBeanClassLoader();
BeanNameGenerator getBeanNameGenerator();
int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}
Spring的Bean是何时被加载的呢?看示例代码:
new XmlBeanFactory(resource);
创建了XmlBeanFactory实例,并传入Resource对象,Resource就在这里被加载解析:
public class XmlBeanFactory extends DefaultListableBeanFactory {
//XmlBeanFactory内部维护了一个XmlBeanDefinitionReader对象,用来解析以Xml方式描述的配置文件
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);
//构造XmlBeanFactory后,即调用XmlBeanDefinitionReader的方法解析配置文件
this.reader.loadBeanDefinitions(resource);
}
}
XmlBeanFactory调用了XmlBeanDefinitionReader的loadBeanDefinitions()方法解析配置文件,加载Bean定义。具体如下:
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.getResource());
}
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 {
//从Resource中获取InputStream并构造InputSource
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//调用doLoadBeanDefinitions()进行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();
}
}
}
可以看到,loadBeanDefinitions()方法只是做了一些准备工作,核心的加载逻辑是在doLoadBeanDefinitions()方法中的:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//将封装了Spring配置文件的Resource对象解析成Document文档对象
Document doc = doLoadDocument(inputSource, resource);
//向Spring容器中注册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);
}
}
不考虑异常处理,doLoadBeanDefinitions()方法其实只完成了两件事:
Document是w3c规范定义的文档对象,doLoadDocument(inputSource, resource)方法的作用就是将Spring的配置文件Resource对象解析成Document对象,具体的逻辑涉及到dom解析相关处理,这里就不再展开了。
下面重点关注registerBeanDefinitions方法:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//创建DefaultBeanDefinitionDocumentReader实例,用来解析Document文件
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//本次注册BeanDefinition前,容器中BeanDefinition的数量
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//返回本次成功注册的BeanDefinition的数量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
注册BeanDefinition的核心逻辑在DefaultBeanDefinitionDocumentReader的doRegisterBeanDefinitions()方法中:
protected void doRegisterBeanDefinitions(Element root) {
//创建BeanDefinitionParserDelegate代理对象专门处理解析
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.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;
}
最后,解析和注册BeanDefinition的处理在parseBeanDefinitions()方法中
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//解析<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>标签
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
//处理自定义标签
else {
delegate.parseCustomElement(root);
}
}