Spring系列一之容器初始化
一、spring的基础模块包含core、beans
-
core模块为其他组件提供各种工具
-
beans模块其中Bean的载体就是BeanDefinition了,我们所说的控制反转指的就是这了, 我们配置的类信息及spring内部的一些配置信息都被BeanDefinition管理着
-
由图可以看出提供了新增BeanDefinition的入口,到此我们可以想到容器有新增入口,是否有查看、删除、修改入口呢,这让我们想到了工作当中熟悉的CRUD了,对的其实和我们工作的内容是息息相关的。
-
其中registerBeanDefinition()方法就是新增操作的入口了,只不过该入口是不对外开放的。说到新增入口不得不说下我们注册的bean是以什么样的形式注册到容器中呢,就以XML配置方式举例,比如一个Dog类配置如下:
<bean id="dog" class="com.strugglesnail.factory.Dog"></bean>
这样的标签我们不可能直接放入容器中的,这时我们就用到了Java核心的特性了,一切事物皆对象,将标签的各个属性封装在一个对象中,这个对象就是上图的BeanDefinition。现在我们知道BeanDefinition是什么了,接下来让我们探究它如何被加载的。
①、首先配置的各种bean都会以流的形式封装在Reources资源类型中
②、然后进行资源解析(BeanDefinitionReader)
③、其次会把解析的结果(BeanDefinition)存放到容器(beanDefinitionMap)
以上就是BeanDefinition加载的大概流程。BeanDefinition是在哪加载的呢?
首先我们先了解下BeanFactory,顾名思义就是一个Bean的工厂,工厂里会有流水线工人、各种机器及生产出的零件等。没错BeanDefinition就是在BeanFactory中解析并生产的。我们可以把配置文件看作是工厂的原材料,各种解析器可以看成工人或机器,生产出的零件可以看作BeanDefinition,仓库可以看成容器(beanDefinitionMap),这样我们就把原材料制作成了零件。
-
下面我们就借助代码来还原一下BeanDefinition创建的流程:
①、首先是加载xml配置Resource resource = new ClassPathResource("test.xml", getClass())
②、然后使用XmlBeanDefinitionReader解析器进行解析
// new EncodedResource(resource):对步骤1的resource进行封装
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
// 将EncodedResource转换为数据流
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
// ...部分代码省略
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);
}
}
// 根据文档信息注册beanDefinition
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
} catch (BeanDefinitionStoreException ex) {
throw ex;
}
// ...省略其他catch
}
// bean定义文档解析器注册beanDefinition
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 解析器初始化的时候传进来的:getRegistry()
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
跳转到BeanDefinitionDocumentReader解析器的registerBeanDefinitions方法:
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
// 通过beanDefinitionParserDelegate解析器委托来解析文档
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
// 默认封装的有beanFactory、Element
this.delegate = createDelegate(getReaderContext(), root, parent);
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
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
// 遍历<beans>
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>转换成beanDefinition
parseDefaultElement(ele, delegate);
}
else {
// 解析自定义标签的元素(aop的配置)
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
// 通过beanDefinition解析器委托类解析Element生成BeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
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));
}
}
我们来看一下BeanDefinitionReaderUtils这个类的registerBeanDefinition方法:
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());
// 每个bean都可以设置多个别名,而这些别名需要存储起来
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
通过上图我们就能看到我们熟悉的registry.registerBeanDefinition()插入入口了,不过这个方法是由DefaultListableBeanFactory实现的,其实我们能想象的到它是如何实现的,无非是把BeanDefinition放到BeanDefinitionMap这个容器里面。下面我就用一个测试代码来注册一个bean
// 创建bean工厂
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// xml类型的bean定义解析器
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
// xml解析、生成beanDefinition及
reader.loadBeanDefinitions(new ClassPathResource("test.xml"));
这就是spring容器的初始化过程,下节我们讲下spring如何获取bean实例。