1,說明
spring 的源碼包括了很龐大的知識,我們通常說的spring指的是spring framework, 裏面包含了AOP,容器等等,本章開始講解xml的解析,
先看測試用例,使用 spring-5.0.15 版本:
public class MainTest {
public static void main(String[] args) {
// 傳入配置文件,獲取 ApplicationContext
ClassPathXmlApplicationContext ioc = new
ClassPathXmlApplicationContext("classpath:spring.xml");
// 通過getBean 獲取bean
System.out.println(ioc.getBean("car"));
}
spring.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.mystudy">
</context:component-scan>
<bean id = "xmlBean" class="com.mystudy.entity.XmlBean"></bean>
</beans>
2,方法預覽
1,查看 ClassPathXmlApplicationContext 源碼,類構造方法
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
// 省略其他方法,
// 調用構造方法,並調用字方法
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
// 主要看refresh 方法
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
/**
* 初始化,父類各個資源,
*/
super(parent);
//格式化資源路徑中特殊字符,
setConfigLocations(configLocations);
if (refresh) {
//整個spring 比較核心的方法,
refresh();
}
}
}
2,點開refresh方法, 裏面有9個方法,可以看一個大概的意思,前面幾個方法着重是初始化資源文件,做一些校驗,finishBeanFactoryInitialization纔是真正初始化bean
這裏需要強調一點,java bean 和spring bean 有區別, 只要new一個對象都可以稱爲java bean但不是spring bean。spring bean從bean實例化,屬性的賦值,到初始化,一個完整的生命週期,
其中可以着重看的方法 1,obtainFreshBeanFactory (獲取 BeanFactory),2,finishBeanFactoryInitialization(實例化單例bean, 後面單獨寫一篇)
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 前期準備工作, 初始化一些變量,
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//初始化 beanFactory,
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 初始化 bean factory 需要用到的上下文
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 預留用戶自定義方法
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// bean工廠後置處理器,修改bean工廠裏面的值
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//bean的後置處理器,干預bean的創建
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 國際化語言
initMessageSource();
// Initialize event multicaster for this context.
// 創建事件的監聽器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//留給子類實現
onRefresh();
// Check for listener beans and register them.
// 把時間監聽器註冊到監聽器上
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 實例化剩餘的單利bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 容器刷新,發佈容器刷新時間(spring cloud 也是在這裏啓動)
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
3,obtainFreshBeanFactory 方法講解
點進 obtainFreshBeanFactory方法,可以看到主要乾了兩件事 :
- 調用子類方法,
- 獲取子類方法初始化的BeanFactory
而子類方法 refreshBeanFactory
- 初始化了一個 DefaultListableBeanFactory對象,
- 調用 AbstractXmlApplicationContext#loadBeanDefinitions方法,初始化一個XmlBeanDefinitionReader對象,並初始化環境變量和資源文件,調用本類方法loadBeanDefinitions,獲取資源文件路徑,並開始解析
// 去掉其他沒有調用的方法
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 加載並初始化 beanFacotry,進入子方法
refreshBeanFactory();
//獲取上面初始化的BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
// 如果beanFactory已經被初始化,銷燬
destroyBeans();
closeBeanFactory();
}
try {
// 初始化一個 DefaultListAbleBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
//加載beanDefinition
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
往下走會到 AbstractBeanDefinitionReader#loadBeanDefinitions (String location, @Nullable Set<Resource> actualResources) 方法
- 將資源文件轉化爲Resource
- XmlBeanDefinitionReader#loadBeanDefinitions 方法 將Resource 轉成InputStream
- 進入子方法 doLoadBeanDefinitions 將InputStream 轉Document
- 創建對象BeanDefinitionDocumentReader對象,調用registerBeanDefinitions方法, 獲取root節點,並開始真正解析,調用doRegisterBeanDefinitions方法
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
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;
}
}
}
//預留前置解析xml接口, 用戶可自定義實現
preProcessXml(root);
// 開始解析 標籤
parseBeanDefinitions(root, this.delegate);
//預留後置解析xml接口, 用戶可自定義實現
postProcessXml(root);
this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//解析整個xml,首先解析最外層document對象, 對應前面XML文件 Beans標籤
//判斷是否是系統標籤
if (delegate.isDefaultNamespace(root)) {
// 獲取第二層系統標籤 對應前面XML文件, beans和context:component-scan
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 {
// 用戶自定義Xml
delegate.parseCustomElement(root);
}
}
4,標籤解析
1,系統標籤解析
可以看到,系統標籤 包含,import, alias, bean, beans,看看bean標籤主要做的事
- 解析id, name 確定BeanDefinition 的name
- 解析 className, parent, 創建AbstractBeanDefinition對象,真實創建的是GenericBeanDefinition對象
- 解析標籤裏面各個屬性值,保存到GenericBeanDefinition 對象,包括,是否單例,抽象,懶加載,作用域,依賴,是否私有等等,方便後面在初始化bean的時候用到
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 標籤
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// beans 標籤
doRegisterBeanDefinitions(ele);
}
}
// 子方法
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析各個屬性
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
//省略代碼
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 解析屬性值 id,name
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
// 將name,存儲別名list中
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
// 如果id,name 同時存在,優先取id的值
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
// 傳的值是null,主要用來檢測beanName的唯一性,是否和其他beanName重名
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
// 創建AbstractBeanDefinition對象,並解析class ,parent等等,各種屬性值,
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
// 省略代碼
}