在对refreshBeanFactory()详细解析之前,先来看看spring的applicationContext的继承树:
BeanFactory 简介
ResourceLoader简介
ResourceLoader并不能将其看成是Spring独有的功能,spring Ioc只是借助于ResourceLoader来实现资源加载。也提供了各种各样的资源加载方式:
-
DefaultResourceLoader 首先检查资源路径是否以classpath:前缀打头,如果是,则尝试构造ClassPathResource类 型资源并返回。否则, 尝试通过URL,根据资源路径来定位资源
-
FileSystemResourceLoader 它继承自Default-ResourceLoader,但覆写了getResourceByPath(String)方法,使之从文件系统加载资源并以 FileSystemResource类型返回
- ResourcePatternResolver 批量查找的ResourceLoader
- ResourcePatternResolver 批量查找的ResourceLoader
spring与ResourceLoader之间的关系
所有ApplicationContext的具体实现类都会直接或者间接地实现AbstractApplicationContext,AbstactApplicationContext 依赖了了DeffaultResourceLoader, ApplicationContext 继承了ResourcePatternResolver,所到头来ApplicationContext的具体实现类都会具有DefaultResourceLoader 和 PathMatchingResourcePatterResolver的功能。这也就是会什么ApplicationContext可以实现统一资源定位。
接下来进入正题: refreshBeanFactory() 刷新beanfactory // AbstractRefreshableApplicationContext.java - 120
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果 ApplicationContext 中已经加载过 BeanFactory 了,销毁所有 Bean,关闭 BeanFactory
// 注意,应用中 BeanFactory本来就是可以多个的,这里可不是说应用全局是否有 BeanFactory,而是当前ApplicationContext 是否有 BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 初始化一个 DefaultListableBeanFactory,为什么用这个,我们马上说。
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 用于 BeanFactory 的序列化
beanFactory.setSerializationId(getId());
// 设置 BeanFactory 的两个配置属性:是否允许 Bean定义覆盖、是否允许bean之间的循环引用
//bean定义覆盖的属性默认是true,重复了会直接覆盖
customizeBeanFactory(beanFactory);
// 加载 Bean 到 BeanFactory 中
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
整个过程主要分为了三个步骤:
1.resource定位
2.beanDefinition的载入。
3.向注册中心注册beanDefinition的过程(将beanDefinition放入缓存)。
resource定位
AbstractXmlApplicationContext#loadBeanDefinitions(beanFactory) 加载 Bean:
// AbstractXmlApplicationContext.java L80
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 给这个 BeanFactory 实例化一个 XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 初始化 BeanDefinitionReader,其实这个是提供给子类覆写的,
initBeanDefinitionReader(beanDefinitionReader);
// 重点来了,继续往下
loadBeanDefinitions(beanDefinitionReader);
}
读取配置的操作在 XmlBeanDefinitionReader 中,其负责加载配置、解析。
// AbstractXmlApplicationContext.java 120
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//如果调用的构造器是new ClassPathXmlApplicationContext(String path, Class<?> clazz),获取其路径下的资源
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
//如果构造器调用的的是 new ClassPathXmlApplicationContext(String configLocation),获取其资源
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
这里两个分支都是在加载bean实例,过程类似,只分析reader.loadBeanDefinitions(configResources);
// AbstractBeanDefinitionReader.java L177
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
for (Resource resource : resources) {
//这里用了典型的模板模式,实际调用的是XmlBeanDefinitionReader#loadBeanDefinitions
counter += loadBeanDefinitions(resource);
}
return counter;
}
XmlBeanDefinitionReader
// XmlBeanDefinitionReader.java L314
/**
* Load bean definitions from the specified XML file.
* 从xml里加载bean实例
*/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
...
//从threadlocal中获取资源set
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
//将resource放入set中
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());
}
//此处调用388行的doLoadBeanDefinitions()
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
//此处省略处理异常、清楚链表和threadload相关代码
...
}
接下来继续看//XmlBeanDefinitionReader.java L388的实现
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//校验xml文件的是xsd 还是 dtd格式的,然后调用 DefaultDocumentLoader#doLoadDocument将流解析成document对象
Document doc = doLoadDocument(inputSource, resource);
//将document和资源封装成bean实例
return registerBeanDefinitions(doc, resource);
}
//省略若干异常处理
...
}
// XmlBeanDefinitionReader.java L505
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//构建DefaultBeanDefinitionDocumentReader的实例由documentReader负责解析xml并封装到beandefinition里
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//BeanDefinitionRegistry 负责将bean实例注册到bean工厂
int countBefore = getRegistry().getBeanDefinitionCount();
//下面会详细展开说明
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
经过艰难险阻,磕磕绊绊,我们终于到了核心逻辑的底部doRegisterBeanD巳finitions(root) , 至少我们在这个方法中看到了希望。 如果说以前一直是XML 加载解析的准备阶段,那么doRegisterBeanDefinitions 算是真正地 开始进行解析了,我们期待的核心部分真正开始了:
==DefaultBeanDefinitionDocumentReader==
//DefaultBeanDefinitionDocumentReader.java L116
protected void doRegisterBeanDefinitions(Element root) {
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)) {
return;
}
}
}
//模板方法模式,让子类去实现,利于用户自己拓展
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
//模板方法模式,让子类去实现,利于用户自己拓展
postProcessXml(root);
this.delegate = parent;
}
继续跟踪parseBeanDefinitions(root, this.delegate); //DefaultBeanDefinitionDocumentReader.java L157
/**
* Parse the elements at the root level in the document:
* "import", "alias", "bean".
* @param root the DOM root element of the document
*/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//判断当前元素是否是beans节点
if (delegate.isDefaultNamespace(root)) {
//beans
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
//循环beans下面的节点
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);
}
}
从上面的代码,我们可以看到,对于每个配置来说,分别进入到 parseDefaultElement(ele, delegate); 和 delegate.parseCustomElement(ele); 这两个分支了。
parseDefaultElement(ele, delegate) 代表解析的节点是 、、、 这几个。 这里的四个标签之所以是 default 的,是因为它们是处于这个 namespace 下定义的:www.springframework.org/schema/bean…
而对于其他的标签,将进入到 delegate.parseCustomElement(element) 这个分支。如我们经常会使用到的 、、、等。
回过神来,看看处理 default 标签的方法:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
//import
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
//alias
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
//bean 创建bean的入口
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// beans
doRegisterBeanDefinitions(ele);
}
}
这里我们不会对每一个标签进行解析,仅仅对最重要的进行跟踪 解析的入口: //DefaultBeanDefinitionDocumentReader.java L294
/**
* Process the given bean element, parsing the bean definition
* and registering it with the registry.
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 将 <bean /> 节点中的信息提取出来,然后封装到一个 BeanDefinitionHolder 中,细节往下看
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//对自定义属性进行解析。忽略
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 注册bean
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// bean注册完成后发送事件,但是这里是空实现,留给用户扩展
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
将xml信息载入到beanDefinition中。
==BeanDefinitionParserDelegate==
// BeanDefinitionParserDelegate L437
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<String>();
//将 name 属性的定义按照 ”逗号、分号、空格“切分,形成一个别名列表数组,
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
//// 如果没有指定id, 那么用别名列表的第一个名字作为beanName
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
// 根据 <bean ...>...</bean> 中的配置创建 BeanDefinition,然后把配置中的信息都设置到实例中,
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
// 到这里,整个 <bean /> 标签就算解析结束了,一个 BeanDefinition 就形成了。
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
// 如果都没有设置 id 和 name,那么此时的 beanName 就会为 null,进入下面这块代码产生生成相应的别名,可以忽略
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
// 返回 BeanDefinitionHolder
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
==// BeanDefinitionParserDelegate.java#parseBeanDefinitionElement L522==
/**
* Parse the bean definition itself, without regard to name or aliases. May return
* {@code null} if problems occurred during the parsing of the bean definition.
*/
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
//parseState里维护了一个栈,保证先进后出
this.parseState.push(new BeanEntry(beanName));
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
//取出class属性
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
//取出parent属性
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
//用class 和parent创建一个GenericBeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 设置 BeanDefinition 的一堆属性,这些属性定义在 AbstractBeanDefinition 中
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
/**
* 下面的一堆是解析 <bean>......</bean> 内部的子元素,
* 解析出来以后的信息都放到 bd 的属性中
*/
// 解析 <meta />
parseMetaElements(ele, bd);
// 解析 <lookup-method />
parseLookupOverrideSubElements(ele,bd.getMethodOverrides());
// 解析 <replaced-method />
parseReplacedMethodSubElements(ele,bd.getMethodOverrides());
// 解析 <constructor-arg />
parseConstructorArgElements(ele, bd);
// 解析 <property />
parsePropertyElements(ele, bd);
// 解析 <qualifier />
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
finally {
this.parseState.pop();
}
return null;
}
到这里,我们已经完成了根据 配置创建了一个 BeanDefinitionHolder 实例。 我们回到解析的入口: //DefaultBeanDefinitionDocumentReader.java L294
/**
* Process the given bean element, parsing the bean definition
* and registering it with the registry.
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 将 <bean /> 节点中的信息提取出来,然后封装到一个 BeanDefinitionHolder 中,细节往下看
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//对自定义属性进行解析。忽略
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 注册bean
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// bean注册完成后发送事件,但是这里是空实现,留给用户扩展
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
接下来是注册bean实例的过程——
注册bean到缓存中
//BeanDefinitionReaderUtils#registerBeanDefinition L143
/**
* Register the given bean definition with the given bean factory.
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
//调用BeanDefinitionRegistry实现类注册以beanName为key,bean实例作为value存入缓存中
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 如果还有别名的话,也要根据别名统统注册一遍,不然根据别名就找不到 Bean 了
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
// alias -> beanName 保存它们的别名信息,这个很简单,用一个 map 保存一下就可以了,
// 获取的时候,会先将 alias 转换为 beanName,然后再查找
registry.registerAlias(beanName, alias);
}
}
}
这里BeanDefinitionRegistry的实现类用DefaultListableBeanFactory 方法比较长,为了便于阅读,我将一些异常处理等非核心方法省略 //DefaultListableBeanFactory#registerBeanDefinition L793
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
...
BeanDefinition oldBeanDefinition;
// 从beanDefinitionMap缓存中取,之后会看到,所有的 Bean 注册后会放入这个 beanDefinitionMap 中
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
//allowBeanDefinitionOverriding customizeBeanFactory(beanFactory) 里可以设置这个属性,默认是true,
if (!isAllowBeanDefinitionOverriding()) {
//不允许覆盖,抛异常
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
...打印相关日志
//将beanName作为key,beanDefinition作为value放入map中,覆盖旧值
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//该beanName未被创建
//判断alreadyCreated链表是否为空===判断是否已经有其他的 Bean 开始初始化
// 注意,"注册Bean" 这个动作结束,Bean 依然还没有初始化,我们后面会有大篇幅说初始化过程,
// 在 Spring 容器启动的最后,会 预初始化 所有的 singleton beans
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
//为了集合迭代的稳定性,不能直接操作元集合(不能增加和删除元素个数)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
//新建一个临时集合来实现新增的beanname
//beanDefinitionNames 预注册的bean实例的beanName集合
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
//manualSingletonNames 手动注册单例的beanName集合
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// 这是正常的开始
// 将 BeanDefinition 放到这个 map 中,这个 map 保存了所有的 BeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
// 这是个 ArrayList,所以会按照 bean 配置的顺序保存每一个注册的 Bean 的名字
this.beanDefinitionNames.add(beanName);
// 这是个 LinkedHashSet,代表的是手动注册的 singleton bean,
// 注意这里是 remove 方法,到这里的 Bean 当然不是手动注册的
// 手动指的是通过调用以下方法注册的 bean :registerSingleton(String beanName, Object singletonObject)
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
总结一下,到这里已经初始化了 Bean 容器, 配置也相应的转换为了一个个 BeanDefinition,然后注册了各个 BeanDefinition 到了注册中心