Spring啟動過程寫的過於冗雜,如果對於這部分不感興趣可以直接跳到Dubbo和Spring的關係,依然能夠愉快的閱讀。
Spring啟動過程
第一步:
ClassPathXmlApplicationContext的構造方法:
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
private Resource[] configResources;
// 如果已經有 ApplicationContext 並需要配置成父子關係,那麼呼叫這個構造方法
public ClassPathXmlApplicationContext(ApplicationContext parent) {
super(parent);
}
...
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
// 根據提供的路徑,處理成配置檔案陣列(以分號、逗號、空格、tab、換行符分割)
setConfigLocations(configLocations);
if (refresh) {
refresh(); // 核心方法
}
}
...
}
複製程式碼
接下來,就是refresh(),將原來的ApplicationContext銷燬,然後重新執行一次初始化操作。
@Override
public void refresh() throws BeansException, IllegalStateException {
// 來個鎖,不然 refresh() 還沒結束,你又來個啟動或銷燬容器的操作,那不就亂套了嘛
synchronized (this.startupShutdownMonitor) {
// 準備工作,記錄下容器的啟動時間、標記“已啟動”狀態、處理配置檔案中的佔位符
prepareRefresh();
// 這步比較關鍵,這步完成後,配置檔案就會解析成一個個 Bean 定義,註冊到 BeanFactory 中,
// 當然,這裡說的 Bean 還沒有初始化,只是配置資訊都提取出來了,
// 註冊也只是將這些資訊都儲存到了註冊中心(說到底核心是一個 beanName-> beanDefinition 的 map)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 設定 BeanFactory 的類載入器,新增幾個 BeanPostProcessor,手動註冊幾個特殊的 bean
// 這塊待會會展開說
prepareBeanFactory(beanFactory);
try {
// 【這裡需要知道 BeanFactoryPostProcessor 這個知識點,Bean 如果實現了此介面,
// 那麼在容器初始化以後,Spring 會負責呼叫裡面的 postProcessBeanFactory 方法。】
// 這裡是提供給子類的擴充套件點,到這裡的時候,所有的 Bean 都載入、註冊完成了,但是都還沒有初始化
// 具體的子類可以在這步的時候新增一些特殊的 BeanFactoryPostProcessor 的實現類或做點什麼事
postProcessBeanFactory(beanFactory);
// 呼叫 BeanFactoryPostProcessor 各個實現類的 postProcessBeanFactory(factory) 方法
invokeBeanFactoryPostProcessors(beanFactory);
// 註冊 BeanPostProcessor 的實現類,注意看和 BeanFactoryPostProcessor 的區別
// 此介面兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 兩個方法分別在 Bean 初始化之前和初始化之後得到執行。注意,到這裡 Bean 還沒初始化
registerBeanPostProcessors(beanFactory);
// 初始化當前 ApplicationContext 的 MessageSource,國際化這裡就不展開說了,不然沒完沒了了
initMessageSource();
// 初始化當前 ApplicationContext 的事件廣播器,這裡也不展開了
initApplicationEventMulticaster();
// 從方法名就可以知道,典型的模板方法(鉤子方法),
// 具體的子類可以在這裡初始化一些特殊的 Bean(在初始化 singleton beans 之前)
onRefresh();
// 註冊事件監聽器,監聽器需要實現 ApplicationListener 介面。這也不是我們的重點,過
registerListeners();
// 重點,重點,重點
// 初始化所有的 singleton beans
//(lazy-init 的除外)
finishBeanFactoryInitialization(beanFactory);
// 最後,廣播事件,ApplicationContext 初始化完成
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.
// 銷燬已經初始化的 singleton 的 Beans,以免有些 bean 會一直佔用資源
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// 把異常往外拋
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
複製程式碼
建立Bean容器前的準備工作:
protected void prepareRefresh() {
// 記錄啟動時間,
// 將 active 屬性設定為 true,closed 屬性設定為 false,它們都是 AtomicBoolean 型別
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
initPropertySources();
// 校驗 xml 配置檔案
getEnvironment().validateRequiredProperties();
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
複製程式碼
建立Bean容器,載入並註冊Bean
這裡會初始化BeanFactory、載入Bean、註冊Bean等等。
AbstractApplicationContext.java
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//關閉就得BeanFactory,建立新的BeanFactory,載入Bean定義、註冊Bean等等。
this.refreshBeanFactory();
//返回剛剛建立的BeanFactory
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);
}
return 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 覆蓋、是否允許迴圈引用
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);
}
}
複製程式碼
customizeBeanFactory(beanFactory)
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
// 是否允許 Bean 定義覆蓋
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {
// 是否允許 Bean 間的迴圈依賴
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
複製程式碼
AbstractXmlApplicationContext.java 80 loadBeanDefinitions(beanFactory)
/** 我們可以看到,此方法將通過一個 XmlBeanDefinitionReader 例項來載入各個 Bean。*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 給這個 BeanFactory 例項化一個 XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 初始化 BeanDefinitionReader,其實這個是提供給子類覆寫的,
// 我看了一下,沒有類覆寫這個方法,我們姑且當做不重要吧
initBeanDefinitionReader(beanDefinitionReader);
// 重點來了,繼續往下
loadBeanDefinitions(beanDefinitionReader);
}
複製程式碼
現在還在這個類中,接下來用剛剛初始化的 Reader 開始來載入 xml 配置,這塊程式碼讀者可以選擇性跳過,不是很重要。也就是說,下面這個程式碼塊,讀者可以很輕鬆地略過。
// AbstractXmlApplicationContext.java 120
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
// 往下看
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
// 上面雖然有兩個分支,不過第二個分支很快通過解析路徑轉換為 Resource 以後也會進到這裡
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
// 注意這裡是個 for 迴圈,也就是每個檔案是一個 resource
for (Resource resource : resources) {
// 繼續往下看
counter += loadBeanDefinitions(resource);
}
return counter;
}
// XmlBeanDefinitionReader 303
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
// XmlBeanDefinitionReader 314
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());
}
// 用一個 ThreadLocal 來存放所有的配置檔案資源
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(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();
}
}
}
// 還在這個檔案中,第 388 行
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 這裡就不看了
Document doc = doLoadDocument(inputSource, resource);
// 繼續
return registerBeanDefinitions(doc, resource);
}
catch (...
}
// 還在這個檔案中,第 505 行
// 返回從當前配置檔案載入了多少數量的 Bean
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
// DefaultBeanDefinitionDocumentReader 90
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
複製程式碼
經過漫長的鏈路,一個配置檔案終於轉換為一顆DOM樹了,注意,這裡指的是其中一個配置檔案,不是所有。下面從根節點開始解析:
doRegisterBeanDefinitions:
// DefaultBeanDefinitionDocumentReader 116
protected void doRegisterBeanDefinitions(Element root) {
// 我們看名字就知道,BeanDefinitionParserDelegate 必定是一個重要的類,它負責解析 Bean 定義,
// 這裡為什麼要定義一個 parent? 看到後面就知道了,是遞迴問題,
// 因為 <beans /> 內部是可以定義 <beans /> 的,所以這個方法的 root 其實不一定就是 xml 的根節點,也可以是巢狀在裡面的 <beans /> 節點,從原始碼分析的角度,我們當做根節點就好了
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
// 這塊說的是根節點 <beans ... profile="dev" /> 中的 profile 是否是當前環境需要的,
// 如果當前環境配置的 profile 不包含此 profile,那就直接 return 了,不對此 <beans /> 解析
// 不熟悉 profile 為何物,不熟悉怎麼配置 profile 讀者的請移步附錄區
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;
}
複製程式碼
接下來,看核心解析方法parseBeanDefinitions(roo,this.delegate):
// default namespace 涉及到的就四個標籤 <import />、<alias />、<bean /> 和 <beans />,
// 其他的屬於 custom 的
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);
}
}
複製程式碼
從上面的程式碼,我們可以看到,對於每個配置來說,分別進入到 parseDefaultElement(ele, delegate); 和 delegate.parseCustomElement(ele); 這兩個分支了。
parseDefaultElement(ele, delegate) 代表解析的節點是 <import />
、<alias />
、<bean />
、<beans />
這幾個。
這裡的四個標籤之所以是 default 的,是因為它們是處於這個 namespace 下定義的:
http://www.springframework.org/schema/beans
複製程式碼
回過神來,看看處理 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 /> 標籤定義
// <alias name="fromName" alias="toName"/>
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
// 處理 <bean /> 標籤定義,這也算是我們的重點吧
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 如果碰到的是巢狀的 <beans /> 標籤,需要遞迴
doRegisterBeanDefinitions(ele);
}
}
複製程式碼
如果每個標籤都說,那我不吐血,你們都要吐血了。我們挑我們的重點 <bean />
標籤出來說。
processBeanDefinition
下面是 processBeanDefinition 解析 <bean />
標籤:
// DefaultBeanDefinitionDocumentReader 298
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 將 <bean /> 節點中的資訊提取出來,然後封裝到一個 BeanDefinitionHolder 中,細節往下看
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));
}
}
複製程式碼
繼續往下看怎麼解析之前,我們先看下 標籤中可以定義哪些屬性:
Property | |
---|---|
class | 類的全限定名 |
name | 可指定 id、name(用逗號、分號、空格分隔) |
scope | 作用域 |
constructor arguments | 指定構造引數 |
properties | 設定屬性的值 |
autowiring mode | no(預設值)、byName、byType、 constructor |
lazy-initialization mode | 是否懶載入(如果被非懶載入的bean依賴了那麼其實也就不能懶載入了) |
initialization method | bean 屬性設定完成後,會呼叫這個方法 |
destruction method | bean 銷燬後的回撥方法 |
上面表格中的內容我想大家都非常熟悉吧,如果不熟悉,那就是你不夠了解 Spring 的配置了。
簡單地說就是像下面這樣子:
<bean id="exampleBean" name="name1, name2, name3" class="com.javadoop.ExampleBean"
scope="singleton" lazy-init="true" init-method="init" destroy-method="cleanup">
<!-- 可以用下面三種形式指定構造引數 -->
<constructor-arg type="int" value="7500000"/>
<constructor-arg name="years" value="7500000"/>
<constructor-arg index="0" value="7500000"/>
<!-- property 的幾種情況 -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
複製程式碼
當然,除了上面舉例出來的這些,還有 factory-bean、factory-method、<lockup-method />
、<replaced-method />
、<meta />
、<qualifier />
這幾個,大家是不是熟悉呢?
有了以上這些知識以後,我們再繼續往裡看怎麼解析 bean 元素,是怎麼轉換到 BeanDefinitionHolder 的。
// BeanDefinitionParserDelegate 428
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
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 屬性的定義按照 ”逗號、分號、空格“ 切分,形成一個別名列表陣列,
// 當然,如果你不定義的話,就是空的了
// 我在附錄中簡單介紹了一下 id 和 name 的配置,大家可以看一眼,有個20秒就可以了
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 (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
// 根據 <bean ...>...</bean> 中的配置建立 BeanDefinition,然後把配置中的資訊都設定到例項中,
// 細節後面再說
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
// 到這裡,整個 <bean /> 標籤就算解析結束了,一個 BeanDefinition 就形成了。
if (beanDefinition != null) {
// 如果都沒有設定 id 和 name,那麼此時的 beanName 就會為 null,進入下面這塊程式碼產生
// 如果讀者不感興趣的話,我覺得不需要關心這塊程式碼,對本文原始碼分析來說,這些東西不重要
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {// 按照我們的思路,這裡 containingBean 是 null 的
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
// 如果我們不定義 id 和 name,那麼我們引言裡的那個例子:
// 1. beanName 為:com.javadoop.example.MessageServiceImpl#0
// 2. beanClassName 為:com.javadoop.example.MessageServiceImpl
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
// 把 beanClassName 設定為 Bean 的別名
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
// 返回 BeanDefinitionHolder
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
複製程式碼
看看怎麼根據配置建立 BeanDefinition:
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
// 建立 BeanDefinition,然後設定類資訊而已,很簡單,就不貼程式碼了
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;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
複製程式碼
到這裡,我們已經完成了根據 <bean />
配置建立了一個 BeanDefinitionHolder 例項。注意,是一個。
我們回到解析 <bean />
的入口方法:
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);
}
// 註冊完成後,傳送事件,本文不展開說這個
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
複製程式碼
大家再仔細看一下這塊吧,我們後面就不回來說這個了。這裡已經根據一個 <bean />
標籤產生了一個 BeanDefinitionHolder 的例項,這個例項裡面也就是一個 BeanDefinition 的例項和它的 beanName、aliases 這三個資訊,注意,我們的關注點始終在 BeanDefinition 上:
public class BeanDefinitionHolder implements BeanMetadataElement {
private final BeanDefinition beanDefinition;
private final String beanName;
private final String[] aliases;
...
複製程式碼
然後我們準備註冊這個 BeanDefinition,最後,把這個註冊事件傳送出去。
下面,我們開始說註冊 Bean 吧。
註冊 Bean
// BeanDefinitionReaderUtils 143
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
// 註冊這個 Bean
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);
}
}
}
複製程式碼
別名註冊的放一邊,畢竟它很簡單,我們看看怎麼註冊 Bean。
// DefaultListableBeanFactory 793
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(...);
}
}
// old? 還記得 “允許 bean 覆蓋” 這個配置嗎?allowBeanDefinitionOverriding
BeanDefinition oldBeanDefinition;
// 之後會看到,所有的 Bean 註冊後會放入這個 beanDefinitionMap 中
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
// 處理重複名稱的 Bean 定義的情況
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
// 如果不允許覆蓋的話,拋異常
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription()...
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// log...用框架定義的 Bean 覆蓋使用者自定義的 Bean
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
// log...用新的 Bean 覆蓋舊的 Bean
}
else {
// log...用同等的 Bean 覆蓋舊的 Bean,這裡指的是 equals 方法返回 true 的 Bean
}
// 覆蓋
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// 判斷是否已經有其他的 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);
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
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)
// 這不是重點,解釋只是為了不讓大家疑惑。Spring 會在後面"手動"註冊一些 Bean,如 "environment"、"systemProperties" 等 bean
this.manualSingletonNames.remove(beanName);
}
// 這個不重要,在預初始化的時候會用到,不必管它。
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
複製程式碼
Bean 容器例項化完成後
說到這裡,我們回到 refresh() 方法,我重新貼了一遍程式碼,看看我們說到哪了。是的,我們才說完 obtainFreshBeanFactory() 方法。
考慮到篇幅,這裡開始大幅縮減掉沒必要詳細介紹的部分,大家直接看下面的程式碼中的註釋就好了。
@Override
public void refresh() throws BeansException, IllegalStateException {
// 來個鎖,不然 refresh() 還沒結束,你又來個啟動或銷燬容器的操作,那不就亂套了嘛
synchronized (this.startupShutdownMonitor) {
// 準備工作,記錄下容器的啟動時間、標記“已啟動”狀態、處理配置檔案中的佔位符
prepareRefresh();
// 這步比較關鍵,這步完成後,配置檔案就會解析成一個個 Bean 定義,註冊到 BeanFactory 中,
// 當然,這裡說的 Bean 還沒有初始化,只是配置資訊都提取出來了,
// 註冊也只是將這些資訊都儲存到了註冊中心(說到底核心是一個 beanName-> beanDefinition 的 map)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 設定 BeanFactory 的類載入器,新增幾個 BeanPostProcessor,手動註冊幾個特殊的 bean
// 這塊待會會展開說
prepareBeanFactory(beanFactory);
try {
// 【這裡需要知道 BeanFactoryPostProcessor 這個知識點,Bean 如果實現了此介面,
// 那麼在容器初始化以後,Spring 會負責呼叫裡面的 postProcessBeanFactory 方法。】
// 這裡是提供給子類的擴充套件點,到這裡的時候,所有的 Bean 都載入、註冊完成了,但是都還沒有初始化
// 具體的子類可以在這步的時候新增一些特殊的 BeanFactoryPostProcessor 的實現類或做點什麼事
postProcessBeanFactory(beanFactory);
// 呼叫 BeanFactoryPostProcessor 各個實現類的 postProcessBeanFactory(factory) 方法
invokeBeanFactoryPostProcessors(beanFactory);
// 註冊 BeanPostProcessor 的實現類,注意看和 BeanFactoryPostProcessor 的區別
// 此介面兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 兩個方法分別在 Bean 初始化之前和初始化之後得到執行。注意,到這裡 Bean 還沒初始化
registerBeanPostProcessors(beanFactory);
// 初始化當前 ApplicationContext 的 MessageSource,國際化這裡就不展開說了,不然沒完沒了了
initMessageSource();
// 初始化當前 ApplicationContext 的事件廣播器,這裡也不展開了
initApplicationEventMulticaster();
// 從方法名就可以知道,典型的模板方法(鉤子方法),
// 具體的子類可以在這裡初始化一些特殊的 Bean(在初始化 singleton beans 之前)
onRefresh();
// 註冊事件監聽器,監聽器需要實現 ApplicationListener 介面。這也不是我們的重點,過
registerListeners();
// 重點,重點,重點
// 初始化所有的 singleton beans
//(lazy-init 的除外)
finishBeanFactoryInitialization(beanFactory);
// 最後,廣播事件,ApplicationContext 初始化完成
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.
// 銷燬已經初始化的 singleton 的 Beans,以免有些 bean 會一直佔用資源
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// 把異常往外拋
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
複製程式碼
準備 Bean 容器: prepareBeanFactory
這裡簡單介紹下 prepareBeanFactory(factory) 方法:
/**
* Configure the factory's standard context characteristics,
* such as the context's ClassLoader and post-processors.
* @param beanFactory the BeanFactory to configure
*/
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 設定 BeanFactory 的類載入器,我們知道 BeanFactory 需要載入類,也就需要類載入器,
// 這裡設定為當前 ApplicationContext 的類載入器
beanFactory.setBeanClassLoader(getClassLoader());
// 設定 BeanExpressionResolver
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 新增一個 BeanPostProcessor,這個 processor 比較簡單,
// 實現了 Aware 介面的幾個特殊的 beans 在初始化的時候,這個 processor 負責回撥
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 下面幾行的意思就是,如果某個 bean 依賴於以下幾個介面的實現類,在自動裝配的時候忽略它們,
// Spring 會通過其他方式來處理這些依賴。
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
/**
* 下面幾行就是為特殊的幾個 bean 賦值,如果有 bean 依賴了以下幾個,會注入這邊相應的值,
* 之前我們說過,"當前 ApplicationContext 持有一個 BeanFactory",這裡解釋了第一行
* ApplicationContext 繼承了 ResourceLoader、ApplicationEventPublisher、MessageSource
* 所以對於這幾個,可以賦值為 this,注意 this 是一個 ApplicationContext
* 那這裡怎麼沒看到為 MessageSource 賦值呢?那是因為 MessageSource 被註冊成為了一個普通的 bean
*/
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 這個 BeanPostProcessor 也很簡單,在 bean 例項化後,如果是 ApplicationListener 的子類,
// 那麼將其新增到 listener 列表中,可以理解成:註冊事件監聽器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
// 這裡涉及到特殊的 bean,名為:loadTimeWeaver,這不是我們的重點,忽略它
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
/**
* 從下面幾行程式碼我們可以知道,Spring 往往很 "智慧" 就是因為它會幫我們預設註冊一些有用的 bean,
* 我們也可以選擇覆蓋
*/
// 如果沒有定義 "environment" 這個 bean,那麼 Spring 會 "手動" 註冊一個
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
// 如果沒有定義 "systemProperties" 這個 bean,那麼 Spring 會 "手動" 註冊一個
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
// 如果沒有定義 "systemEnvironment" 這個 bean,那麼 Spring 會 "手動" 註冊一個
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
複製程式碼
初始化所有的 singleton beans
我們的重點當然是 finishBeanFactoryInitialization(beanFactory); 這個巨頭了,這裡會負責初始化所有的 singleton beans。
注意,後面的描述中,我都會使用初始化或預初始化來代表這個階段。主要是 Spring 需要在這個階段完成所有的 singleton beans 的例項化。
我們來總結一下,到目前為止,應該說 BeanFactory 已經建立完成,並且所有的實現了 BeanFactoryPostProcessor 介面的 Bean 都已經初始化並且其中的 postProcessBeanFactory(factory) 方法已經得到執行了。所有實現了 BeanPostProcessor 介面的 Bean 也都完成了初始化。
剩下的就是初始化其他還沒被初始化的 singleton beans 了,我們知道它們是單例的,如果沒有設定懶載入,那麼 Spring 會在接下來初始化所有的 singleton beans。
// AbstractApplicationContext.java 834
// 初始化剩餘的 singleton beans
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 什麼,看程式碼這裡沒有初始化 Bean 啊!
// 注意了,初始化的動作包裝在 beanFactory.getBean(...) 中,這裡先不說細節,先往下看吧
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
@Override
public String resolveStringValue(String strVal) {
return getEnvironment().resolvePlaceholders(strVal);
}
});
}
// 先初始化 LoadTimeWeaverAware 型別的 Bean
// 一般用於織入第三方模組,在 class 檔案載入 JVM 的時候動態織入,這裡不展開說
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// 沒什麼別的目的,因為到這一步的時候,Spring 已經開始預初始化 singleton beans 了,
// 肯定不希望這個時候還出現 bean 定義解析、載入、註冊。
beanFactory.freezeConfiguration();
// 開始初始化剩下的
beanFactory.preInstantiateSingletons();
}
複製程式碼
從上面最後一行往裡看,我們又回到 DefaultListableBeanFactory 這個類了,這個類大家應該都不陌生了吧。
preInstantiateSingletons
// DefaultListableBeanFactory 728
@Override
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Pre-instantiating singletons in " + this);
}
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
// 觸發所有的非懶載入的 singleton beans 的初始化操作
for (String beanName : beanNames) {
// 合併父 Bean 中的配置,注意 <bean id="" class="" parent="" /> 中的 parent,用的不多吧,
// 考慮到這可能會影響大家的理解,我在附錄中解釋了一下 "Bean 繼承",請移步
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 非抽象、非懶載入的 singletons。如果配置了 'abstract = true',那是不需要初始化的
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 處理 FactoryBean(讀者如果不熟悉 FactoryBean,請移步附錄區瞭解)
if (isFactoryBean(beanName)) {
// FactoryBean 的話,在 beanName 前面加上 ‘&’ 符號。再呼叫 getBean,getBean 方法別急
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
// 判斷當前 FactoryBean 是否是 SmartFactoryBean 的實現,此處忽略,直接跳過
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
// 對於普通的 Bean,只要呼叫 getBean(beanName) 這個方法就可以進行初始化了
getBean(beanName);
}
}
}
// 到這裡說明所有的非懶載入的 singleton beans 已經完成了初始化
// 如果我們定義的 bean 是實現了 SmartInitializingSingleton 介面的,那麼在這裡得到回撥,忽略
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
smartSingleton.afterSingletonsInstantiated();
return null;
}
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
複製程式碼
接下來,我們就進入到 getBean(beanName) 方法了,這個方法我們經常用來從 BeanFactory 中獲取一個 Bean,而初始化的過程也封裝到了這個方法裡。
getBean
在繼續前進之前,讀者應該具備 FactoryBean 的知識,如果讀者還不熟悉,請移步附錄部分了解 FactoryBean。
// AbstractBeanFactory 196
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
// 我們在剖析初始化 Bean 的過程,但是 getBean 方法我們經常是用來從容器中獲取 Bean 用的,注意切換思路,
// 已經初始化過了就從容器中直接返回,否則就先初始化再返回
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
// 獲取一個 “正統的” beanName,處理兩種情況,一個是前面說的 FactoryBean(前面帶 ‘&’),
// 一個是別名問題,因為這個方法是 getBean,獲取 Bean 用的,你要是傳一個別名進來,是完全可以的
final String beanName = transformedBeanName(name);
// 注意跟著這個,這個是返回值
Object bean;
// 檢查下是不是已經建立過了
Object sharedInstance = getSingleton(beanName);
// 這裡說下 args 唄,雖然看上去一點不重要。前面我們一路進來的時候都是 getBean(beanName),
// 所以 args 其實是 null 的,但是如果 args 不為空的時候,那麼意味著呼叫方不是希望獲取 Bean,而是建立 Bean
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("...");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 下面這個方法:如果是普通 Bean 的話,直接返回 sharedInstance,
// 如果是 FactoryBean 的話,返回它建立的那個例項物件
// (FactoryBean 知識,讀者若不清楚請移步附錄)
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
if (isPrototypeCurrentlyInCreation(beanName)) {
// 當前執行緒已經建立過了此 beanName 的 prototype 型別的 bean,那麼拋異常
throw new BeanCurrentlyInCreationException(beanName);
}
// 檢查一下這個 BeanDefinition 在容器中是否存在
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 如果當前容器不存在這個 BeanDefinition,試試父容器中有沒有
String nameToLookup = originalBeanName(name);
if (args != null) {
// 返回父容器的查詢結果
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
// typeCheckOnly 為 false,將當前 beanName 放入一個 alreadyCreated 的 Set 集合中。
markBeanAsCreated(beanName);
}
/*
* 稍稍總結一下:
* 到這裡的話,要準備建立 Bean 了,對於 singleton 的 Bean 來說,容器中還沒建立過此 Bean;
* 對於 prototype 的 Bean 來說,本來就是要建立一個新的 Bean。
*/
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 先初始化依賴的所有 Bean,這個很好理解。
// 注意,這裡的依賴指的是 depends-on 中定義的依賴
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// 檢查是不是有迴圈依賴,這裡的迴圈依賴和我們前面說的迴圈依賴又不一樣,這裡肯定是不允許出現的,不然要亂套了,讀者想一下就知道了
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 註冊一下依賴關係
registerDependentBean(dep, beanName);
// 先初始化被依賴項
getBean(dep);
}
}
// 建立 singleton 的例項
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
// 執行建立 Bean,詳情後面再說
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 建立 prototype 的例項
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
// 執行建立 Bean
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 如果不是 singleton 和 prototype 的話,需要委託給相應的實現類來處理
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
// 執行建立 Bean
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// 最後,檢查一下型別對不對,不對的話就拋異常,對的話就返回了
if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
複製程式碼
大家應該也猜到了,接下來當然是分析 createBean 方法:
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException;
複製程式碼
第三個引數 args 陣列代表建立例項需要的引數,不就是給構造方法用的引數,或者是工廠 Bean 的引數嘛,不過要注意,在我們的初始化階段,args 是 null。
這回我們要到一個新的類了 AbstractAutowireCapableBeanFactory,看類名,AutowireCapable?類名是不是也說明了點問題了。
主要是為了以下場景,採用 @Autowired 註解注入屬性值:
public class MessageServiceImpl implements MessageService {
@Autowired
private UserService userService;
public String getMessage() {
return userService.getMessage();
}
}
複製程式碼
<bean id="messageService" class="com.javadoop.example.MessageServiceImpl" />
複製程式碼
// AbstractAutowireCapableBeanFactory 447
/**
* Central method of this class: creates a bean instance,
* populates the bean instance, applies post-processors, etc.
* @see #doCreateBean
*/
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// 確保 BeanDefinition 中的 Class 被載入
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// 準備方法覆寫,這裡又涉及到一個概念:MethodOverrides,它來自於 bean 定義中的 <lookup-method />
// 和 <replaced-method />,如果讀者感興趣,回到 bean 解析的地方看看對這兩個標籤的解析。
// 我在附錄中也對這兩個標籤的相關知識點進行了介紹,讀者可以移步去看看
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// 讓 BeanPostProcessor 在這一步有機會返回代理,而不是 bean 例項,
// 要徹底瞭解清楚這個,需要去看 InstantiationAwareBeanPostProcessor 介面,這裡就不展開說了
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
// 重頭戲,建立 bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
複製程式碼
建立 Bean
往裡看 doCreateBean 這個方法:
/**
* Actually create the specified bean. Pre-creation processing has already happened
* at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
* <p>Differentiates between default bean instantiation, use of a
* factory method, and autowiring a constructor.
* @param beanName the name of the bean
* @param mbd the merged bean definition for the bean
* @param args explicit arguments to use for constructor or factory method invocation
* @return a new instance of the bean
* @throws BeanCreationException if the bean could not be created
* @see #instantiateBean
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
*/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 說明不是 FactoryBean,這裡例項化 Bean,這裡非常關鍵,細節之後再說
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 這個就是 Bean 裡面的 我們定義的類 的例項,很多地方我描述成 "bean 例項"
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
// 型別
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;
// 建議跳過吧,涉及介面:MergedBeanDefinitionPostProcessor
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// MergedBeanDefinitionPostProcessor,這個我真不展開說了,直接跳過吧,很少用的
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 下面這塊程式碼是為了解決迴圈依賴的問題,以後有時間,我再對迴圈依賴這個問題進行解析吧
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 這一步也是非常關鍵的,這一步負責屬性裝配,因為前面的例項只是例項化了,並沒有設值,這裡就是設值
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
// 還記得 init-method 嗎?還有 InitializingBean 介面?還有 BeanPostProcessor 介面?
// 這裡就是處理 bean 初始化完成後的各種回撥
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
//
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
複製程式碼
到這裡,我們已經分析完了 doCreateBean 方法,總的來說,我們已經說完了整個初始化流程。
接下來我們挑 doCreateBean 中的三個細節出來說說。一個是建立 Bean 例項的 createBeanInstance 方法,一個是依賴注入的 populateBean 方法,還有就是回撥方法 initializeBean。
注意了,接下來的這三個方法要認真說那也是極其複雜的,很多地方我就點到為止了,感興趣的讀者可以自己往裡看,最好就是碰到不懂的,自己寫程式碼去除錯它。
建立 Bean 例項
我們先看看 createBeanInstance 方法。需要說明的是,這個方法如果每個分支都分析下去,必然也是極其複雜冗長的,我們挑重點說。此方法的目的就是例項化我們指定的類。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// 確保已經載入了此 class
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 校驗一下這個類的訪問許可權
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
if (mbd.getFactoryMethodName() != null) {
// 採用工廠方法例項化,不熟悉這個概念的讀者請看附錄,注意,不是 FactoryBean
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 如果不是第一次建立,比如第二次建立 prototype bean。
// 這種情況下,我們可以從第一次建立知道,採用無參建構函式,還是建構函式依賴注入 來完成例項化
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
// 建構函式依賴注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 無參建構函式
return instantiateBean(beanName, mbd);
}
}
// 判斷是否採用有參建構函式
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 建構函式依賴注入
return autowireConstructor(beanName, mbd, ctors, args);
}
// 呼叫無參建構函式
return instantiateBean(beanName, mbd);
}
複製程式碼
挑個簡單的無參建構函式構造例項來看看:
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
return getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
}, getAccessControlContext());
}
else {
// 例項化
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
// 包裝一下,返回
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
複製程式碼
我們可以看到,關鍵的地方在於:
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
複製程式碼
這裡會進行實際的例項化過程,我們進去看看:
// SimpleInstantiationStrategy 59
@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
// 如果不存在方法覆寫,那就使用 java 反射進行例項化,否則使用 CGLIB,
// 方法覆寫 請參見附錄"方法注入"中對 lookup-method 和 replaced-method 的介紹
if (bd.getMethodOverrides().isEmpty()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
@Override
public Constructor<?> run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
}
});
}
else {
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// 利用構造方法進行例項化
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// 存在方法覆寫,利用 CGLIB 來完成例項化,需要依賴於 CGLIB 生成子類,這裡就不展開了
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
複製程式碼
到這裡,我們就算例項化完成了。我們開始說怎麼進行屬性注入。
bean 屬性注入
// AbstractAutowireCapableBeanFactory 1203
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
// bean 例項的所有屬性都在這裡了
PropertyValues pvs = mbd.getPropertyValues();
if (bw == null) {
if (!pvs.isEmpty()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// 到這步的時候,bean 例項化完成(通過工廠方法或構造方法),但是還沒開始屬性設值,
// InstantiationAwareBeanPostProcessor 的實現類可以在這裡對 bean 進行狀態修改,
// 我也沒找到有實際的使用,所以我們暫且忽略這塊吧
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 如果返回 false,代表不需要進行後續的屬性設值,也不需要再經過其他的 BeanPostProcessor 的處理
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 通過名字找到所有屬性值,如果是 bean 依賴,先初始化依賴的 bean。記錄依賴關係
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 通過型別裝配。複雜一些
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 這裡有個非常有用的 BeanPostProcessor 進到這裡: AutowiredAnnotationBeanPostProcessor
// 對採用 @Autowired、@Value 註解的依賴進行設值,這裡的內容也是非常豐富的,不過本文不會展開說了,感興趣的讀者請自行研究
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
// 設定 bean 例項的屬性值
applyPropertyValues(beanName, mbd, bw, pvs);
}
複製程式碼
initializeBean
屬性注入完成後,這一步其實就是處理各種回撥了。
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
// 如果 bean 實現了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 介面,回撥
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// BeanPostProcessor 的 postProcessBeforeInitialization 回撥
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 處理 bean 中定義的 init-method,
// 或者如果 bean 實現了 InitializingBean 介面,呼叫 afterPropertiesSet() 方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// BeanPostProcessor 的 postProcessAfterInitialization 回撥
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
複製程式碼
大家發現沒有,BeanPostProcessor 的兩個回撥都發生在這邊,只不過中間處理了 init-method,是不是和讀者原來的認知有點不一樣了?
Dubbo啟動和Spring的關係
首先我們來看一下官方demo中給出的Dubbo啟動程式碼:
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-provider.xml"});
context.start();
System.in.read(); // press any key to exit
}
複製程式碼
再看一下配置檔案:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- provider's application name, used for tracing dependency relationship -->
<dubbo:application name="demo-provider"/>
<!-- use multicast registry center to export service -->
<dubbo:registry address="zookeeper://47.107.231.174:2181"/>
<!-- use dubbo protocol to export service on port 20880 -->
<dubbo:protocol name="dubbo" port="20880"/>
<!-- service implementation, as same as regular local bean -->
<bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>
<!-- declare the service interface to be exported -->
<dubbo:service interface="org.apache.dubbo.demo.DemoService" ref="demoService"/>
</beans>
複製程式碼
可以看到Dubbo啟動的程式碼很簡單,只有三行,通過構建ClassPathXmlApplicationContext來啟動Dubbo。那麼Dubbo是如何在ClassPathXmlApplicationContext構建過程中實現自己的相關邏輯的呢?
在Dubbo的官方文件中是這樣寫的:
基於 dubbo.jar 內的
META-INF/spring.handlers
配置,Spring 在遇到 dubbo 名稱空間時,會回撥DubboNamespaceHandler
。所有 dubbo 的標籤,都統一用
DubboBeanDefinitionParser
進行解析,基於一對一屬性對映,將 XML 標籤解析為 Bean 物件。
這裡提到的spring.handlers配置如下:
http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
複製程式碼
這裡的兩個配置對應了Dubbo從阿里開源到捐贈apache的過程。
我們來看一下Spring中是如何解析Dubbo的配置檔案的:
這是在啟動Dubbo過程中解析檔案的呼叫鏈路
可以看到開始啟動之後
執行ClassPathXmlApplicationContext的構造方法,在構造方法中呼叫refresh構造新的ApplicationContext物件,在這裡會載入BeanDefiniton。也就是說會載入我們在Dubbo的配置檔案中的相關配置。
在執行解析對應的Element物件時,會進入BeanDefinitionParserDelegate.class的parseCustomElement方法:
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = this.getNamespaceURI(ele);//首先獲得對應的namespaceUri,這裡對應的namaspaceUri是http://dubbo.apche.org/schema/dubbo
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);//根據namespaceUri獲取對應的Handler
if (handler == null) {
this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
} else {
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));//handler執行相應的解析邏輯,最後跳轉到DubboBeanDefinitionParser執行parse方法。
}
}
複製程式碼
DefaultNamespaceHandlerResolver.class類:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.beans.factory.xml;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.FatalBeanException;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver {
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";//預設的handler配置檔案地址
protected final Log logger;
private final ClassLoader classLoader;
private final String handlerMappingsLocation;
private volatile Map<String, Object> handlerMappings;//namespaceUri和解析器例項的對映關係
public DefaultNamespaceHandlerResolver() {
this((ClassLoader)null, "META-INF/spring.handlers");
}
public DefaultNamespaceHandlerResolver(ClassLoader classLoader) {
this(classLoader, "META-INF/spring.handlers");
}
public DefaultNamespaceHandlerResolver(ClassLoader classLoader, String handlerMappingsLocation) {
this.logger = LogFactory.getLog(this.getClass());
Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null");
this.classLoader = classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader();
this.handlerMappingsLocation = handlerMappingsLocation;
}
public NamespaceHandler resolve(String namespaceUri) {
Map<String, Object> handlerMappings = this.getHandlerMappings();
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
} else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler)handlerOrClassName;
} else {
String className = (String)handlerOrClassName;
try {
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
} else {
NamespaceHandler namespaceHandler = (NamespaceHandler)BeanUtils.instantiateClass(handlerClass);//建立對應Handler的例項
namespaceHandler.init();//建立之後呼叫init方法
handlerMappings.put(namespaceUri, namespaceHandler);//新增到對應map中
return namespaceHandler;
}
} catch (ClassNotFoundException var7) {
throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "] not found", var7);
} catch (LinkageError var8) {
throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]: problem with handler class file or dependent class", var8);
}
}
}
//當需要獲得對應的namespaceUri和handler的對映關係時,使用雙重檢查鎖來構造handlerMapping。
private Map<String, Object> getHandlerMappings() {
if (this.handlerMappings == null) {
synchronized(this) {
if (this.handlerMappings == null) {
try {
Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Loaded NamespaceHandler mappings: " + mappings);
}
Map<String, Object> handlerMappings = new ConcurrentHashMap(mappings.size());
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
this.handlerMappings = handlerMappings;
} catch (IOException var5) {
throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", var5);
}
}
}
}
return this.handlerMappings;
}
public String toString() {
return "NamespaceHandlerResolver using mappings " + this.getHandlerMappings();
}
}
複製程式碼
從上面的類中我們瞭解到handler和namespaceUri的對應關係預設是從META-INF/spring.handlers檔案中讀取,這就是為什麼我們只需要在META-INF/spring.handlers配置對應的解析器,spring就能自動的使用相應的解析去解析對應的名稱空間下的Element物件。
從上面可以看到建立了對應的Handler例項之後,會呼叫該handler的init方法。
DubboNamespaceHandler.java的init方法如下:
@Override
public void init() {
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
複製程式碼
在init方法中,對dubbo中不同的實體註冊了不同的解析器,並指定不同的名稱解析成不同的實體物件。如果後續還需要什麼新的實體新增,只需要在這個地方新增對應的解析器就可以。
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)):這裡會執行DubboBeanDefinitionParser中的parser方法:
private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {
//建立RootBeanDefinition
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(beanClass);
beanDefinition.setLazyInit(false);
//解析配置物件的id。若不存在,則進行生成
String id = element.getAttribute("id");
if ((id == null || id.length() == 0) && required) {
String generatedBeanName = element.getAttribute("name");
if (generatedBeanName == null || generatedBeanName.length() == 0) {
if (ProtocolConfig.class.equals(beanClass)) {
generatedBeanName = "dubbo";
} else {
generatedBeanName = element.getAttribute("interface");
}
}
if (generatedBeanName == null || generatedBeanName.length() == 0) {
generatedBeanName = beanClass.getName();
}
id = generatedBeanName;
//若id已存在,通過自增序列,解決重複
int counter = 2;
while (parserContext.getRegistry().containsBeanDefinition(id)) {
id = generatedBeanName + (counter++);
}
}
if (id != null && id.length() > 0) {
if (parserContext.getRegistry().containsBeanDefinition(id)) {
throw new IllegalStateException("Duplicate spring bean id " + id);
}
//新增到Spring的登錄檔
parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
//設定Bean的'id'屬性值
beanDefinition.getPropertyValues().addPropertyValue("id", id);
}
//處理<dubbo:protocol/>特殊情況
if (ProtocolConfig.class.equals(beanClass)) {
for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
if (property != null) {
Object value = property.getValue();
if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) {
definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
}
}
}
//處理<dubbo:service/>的class的屬性
} else if (ServiceBean.class.equals(beanClass)) {
String className = element.getAttribute("class");
if (className != null && className.length() > 0) {
RootBeanDefinition classDefinition = new RootBeanDefinition();
classDefinition.setBeanClass(ReflectUtils.forName(className));
classDefinition.setLazyInit(false);
parseProperties(element.getChildNodes(), classDefinition);
beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
}
//解析<dubbo:provider/>的內嵌子元素<dubbo:service/>
} else if (ProviderConfig.class.equals(beanClass)) {
parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);
//解析<dubbo:consumer/>的內嵌子元素<dubbo:reference>
} else if (ConsumerConfig.class.equals(beanClass)) {
parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);
}
Set<String> props = new HashSet<String>();
ManagedMap parameters = null;
//迴圈Bean物件的setting方法,將屬性賦值到Bean物件
for (Method setter : beanClass.getMethods()) {
String name = setter.getName();
//判斷是否是set方法
if (name.length() > 3 && name.startsWith("set")
&& Modifier.isPublic(setter.getModifiers())
&& setter.getParameterTypes().length == 1) {
Class<?> type = setter.getParameterTypes()[0];
//新增'props'
String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), "-");
props.add(property);
Method getter = null;
//getting&&public&&屬性值型別統一
try {
getter = beanClass.getMethod("get" + name.substring(3), new Class<?>[0]);
} catch (NoSuchMethodException e) {
try {
getter = beanClass.getMethod("is" + name.substring(3), new Class<?>[0]);
} catch (NoSuchMethodException e2) {
}
}
if (getter == null
|| !Modifier.isPublic(getter.getModifiers())
|| !type.equals(getter.getReturnType())) {
continue;
}
//解析'<dubbo:parameters/>'
if ("parameters".equals(property)) {
parameters = parseParameters(element.getChildNodes(), beanDefinition);
//解析<dubbo:method>
} else if ("methods".equals(property)) {
parseMethods(id, element.getChildNodes(), beanDefinition, parserContext);
//解析'<dubbo:argument>'
} else if ("arguments".equals(property)) {
parseArguments(id, element.getChildNodes(), beanDefinition, parserContext);
} else {
String value = element.getAttribute(property);
if (value != null) {
value = value.trim();
if (value.length() > 0) {
//不想註冊到註冊中心的情況
if ("registry".equals(property) && RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(value)) {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress(RegistryConfig.NO_AVAILABLE);
beanDefinition.getPropertyValues().addPropertyValue(property, registryConfig);
} else if ("registry".equals(property) && value.indexOf(',') != -1) {
//多註冊中心的情況
parseMultiRef("registries", value, beanDefinition, parserContext);
} else if ("provider".equals(property) && value.indexOf(',') != -1) {
//多服務提供者的情況
parseMultiRef("providers", value, beanDefinition, parserContext);
} else if ("protocol".equals(property) && value.indexOf(',') != -1) {
//多協議的情況
parseMultiRef("protocols", value, beanDefinition, parserContext);
} else {
Object reference;
//處理屬性為基本屬性的情況
if (isPrimitive(type)) {
//相容性處理
if ("async".equals(property) && "false".equals(value)
|| "timeout".equals(property) && "0".equals(value)
|| "delay".equals(property) && "0".equals(value)
|| "version".equals(property) && "0.0.0".equals(value)
|| "stat".equals(property) && "-1".equals(value)
|| "reliable".equals(property) && "false".equals(value)) {
// backward compatibility for the default value in old version's xsd
value = null;
}
reference = value;
//處理在'<dubbo:provider/>'或者<dubbo:service/>上定義了'protocol'屬性的相容性
} else if ("protocol".equals(property)
&& ExtensionLoader.getExtensionLoader(Protocol.class).hasExtension(value)
&& (!parserContext.getRegistry().containsBeanDefinition(value)//存在該登錄檔的實現
|| !ProtocolConfig.class.getName().equals(parserContext.getRegistry().getBeanDefinition(value).getBeanClassName()))) {
//目前,<dubbo:provider protocol=""/>推薦獨立成<dubbo:protocol/>
if ("dubbo:provider".equals(element.getTagName())) {
logger.warn("Recommended replace <dubbo:provider protocol=\"" + value + "\" ... /> to <dubbo:protocol name=\"" + value + "\" ... />");
}
// backward compatibility
ProtocolConfig protocol = new ProtocolConfig();
protocol.setName(value);
reference = protocol;
//處理onreturn屬性
} else if ("onreturn".equals(property)) {
//按照'.'拆分
int index = value.lastIndexOf(".");
String returnRef = value.substring(0, index);
String returnMethod = value.substring(index + 1);
//建立RuntimeBeanReference,指向回撥物件
reference = new RuntimeBeanReference(returnRef);
//設定'onreturnMethod'到BeanDefinition的屬性值
beanDefinition.getPropertyValues().addPropertyValue("onreturnMethod", returnMethod);
//處理onthrow屬性
} else if ("onthrow".equals(property)) {
//按照'.'拆分
int index = value.lastIndexOf(".");
String throwRef = value.substring(0, index);
String throwMethod = value.substring(index + 1);
//建立RuntimeBeanReference指向回撥物件
reference = new RuntimeBeanReference(throwRef);
//設定’onthrowMethod‘到BeanDefinition的屬性值
beanDefinition.getPropertyValues().addPropertyValue("onthrowMethod", throwMethod);
} else if ("oninvoke".equals(property)) {
int index = value.lastIndexOf(".");
String invokeRef = value.substring(0, index);
String invokeRefMethod = value.substring(index + 1);
reference = new RuntimeBeanReference(invokeRef);
beanDefinition.getPropertyValues().addPropertyValue("oninvokeMethod", invokeRefMethod);
} else {
//指向Service的bean物件,必須是單例
if ("ref".equals(property) && parserContext.getRegistry().containsBeanDefinition(value)) {
BeanDefinition refBean = parserContext.getRegistry().getBeanDefinition(value);
if (!refBean.isSingleton()) {
throw new IllegalStateException("The exported service ref " + value + " must be singleton! Please set the " + value + " bean scope to singleton, eg: <bean id=\"" + value + "\" scope=\"singleton\" ...>");
}
}
//建立RuntimeBeanReference,指向service的Bean物件
reference = new RuntimeBeanReference(value);
}
//設定BeanDefinition的屬性值
beanDefinition.getPropertyValues().addPropertyValue(property, reference);
}
}
}
}
}
}
//將XML元素,未在上面遍歷到的屬性新增到'parameters'集合中。
NamedNodeMap attributes = element.getAttributes();
int len = attributes.getLength();
for (int i = 0; i < len; i++) {
Node node = attributes.item(i);
String name = node.getLocalName();
if (!props.contains(name)) {
if (parameters == null) {
parameters = new ManagedMap();
}
String value = node.getNodeValue();
parameters.put(name, new TypedStringValue(value, String.class));
}
}
if (parameters != null) {
beanDefinition.getPropertyValues().addPropertyValue("parameters", parameters);
}
return beanDefinition;
}
複製程式碼
這裡Dubbo的配置檔案解析就告一段落。
最後就是如何實現在Dubbo啟動的時候講服務註冊到註冊中心上去,這裡就需要用到前面解析的物件。在前面我們提到DubboBeanDefinitionParser會將service解析為ServiceBean物件。
我們先看看ServiceBean類的實現:
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.spring;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ModuleConfig;
import org.apache.dubbo.config.MonitorConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.ProviderConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.config.spring.extension.SpringExtensionFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.support.AbstractApplicationContext;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* ServiceFactoryBean
*
* @export
*/
public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware {
private static final long serialVersionUID = 213195494150089726L;
private final transient Service service;
private transient ApplicationContext applicationContext;
private transient String beanName;
private transient boolean supportedApplicationListener;
public ServiceBean() {
super();
this.service = null;
}
public ServiceBean(Service service) {
super(service);
this.service = service;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
SpringExtensionFactory.addApplicationContext(applicationContext);
try {
Method method = applicationContext.getClass().getMethod("addApplicationListener", ApplicationListener.class); // backward compatibility to spring 2.0.1
method.invoke(applicationContext, this);
supportedApplicationListener = true;
} catch (Throwable t) {
if (applicationContext instanceof AbstractApplicationContext) {
try {
Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", ApplicationListener.class); // backward compatibility to spring 2.0.1
if (!method.isAccessible()) {
method.setAccessible(true);
}
method.invoke(applicationContext, this);
supportedApplicationListener = true;
} catch (Throwable t2) {
}
}
}
}
@Override
public void setBeanName(String name) {
this.beanName = name;
}
/**
* Gets associated {@link Service}
*
* @return associated {@link Service}
*/
public Service getService() {
return service;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (isDelay() && !isExported() && !isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
export();
}
}
private boolean isDelay() {
Integer delay = getDelay();
ProviderConfig provider = getProvider();
if (delay == null && provider != null) {
delay = provider.getDelay();
}
return supportedApplicationListener && (delay == null || delay == -1);
}
@Override
@SuppressWarnings({"unchecked", "deprecation"})
public void afterPropertiesSet() throws Exception {
if (getProvider() == null) {
Map<String, ProviderConfig> providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false);
if (providerConfigMap != null && providerConfigMap.size() > 0) {
Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false);
if ((protocolConfigMap == null || protocolConfigMap.size() == 0)
&& providerConfigMap.size() > 1) { // backward compatibility
List<ProviderConfig> providerConfigs = new ArrayList<ProviderConfig>();
for (ProviderConfig config : providerConfigMap.values()) {
if (config.isDefault() != null && config.isDefault()) {
providerConfigs.add(config);
}
}
if (!providerConfigs.isEmpty()) {
setProviders(providerConfigs);
}
} else {
ProviderConfig providerConfig = null;
for (ProviderConfig config : providerConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
if (providerConfig != null) {
throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config);
}
providerConfig = config;
}
}
if (providerConfig != null) {
setProvider(providerConfig);
}
}
}
}
if (getApplication() == null
&& (getProvider() == null || getProvider().getApplication() == null)) {
Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false);
if (applicationConfigMap != null && applicationConfigMap.size() > 0) {
ApplicationConfig applicationConfig = null;
for (ApplicationConfig config : applicationConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
if (applicationConfig != null) {
throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
}
applicationConfig = config;
}
}
if (applicationConfig != null) {
setApplication(applicationConfig);
}
}
}
if (getModule() == null
&& (getProvider() == null || getProvider().getModule() == null)) {
Map<String, ModuleConfig> moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false);
if (moduleConfigMap != null && moduleConfigMap.size() > 0) {
ModuleConfig moduleConfig = null;
for (ModuleConfig config : moduleConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
if (moduleConfig != null) {
throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config);
}
moduleConfig = config;
}
}
if (moduleConfig != null) {
setModule(moduleConfig);
}
}
}
if ((getRegistries() == null || getRegistries().isEmpty())
&& (getProvider() == null || getProvider().getRegistries() == null || getProvider().getRegistries().isEmpty())
&& (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().isEmpty())) {
Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false);
if (registryConfigMap != null && registryConfigMap.size() > 0) {
List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
for (RegistryConfig config : registryConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
registryConfigs.add(config);
}
}
if (!registryConfigs.isEmpty()) {
super.setRegistries(registryConfigs);
}
}
}
if (getMonitor() == null
&& (getProvider() == null || getProvider().getMonitor() == null)
&& (getApplication() == null || getApplication().getMonitor() == null)) {
Map<String, MonitorConfig> monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false);
if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
MonitorConfig monitorConfig = null;
for (MonitorConfig config : monitorConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
if (monitorConfig != null) {
throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config);
}
monitorConfig = config;
}
}
if (monitorConfig != null) {
setMonitor(monitorConfig);
}
}
}
if ((getProtocols() == null || getProtocols().isEmpty())
&& (getProvider() == null || getProvider().getProtocols() == null || getProvider().getProtocols().isEmpty())) {
Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false);
if (protocolConfigMap != null && protocolConfigMap.size() > 0) {
List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>();
for (ProtocolConfig config : protocolConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
protocolConfigs.add(config);
}
}
if (!protocolConfigs.isEmpty()) {
super.setProtocols(protocolConfigs);
}
}
}
if (getPath() == null || getPath().length() == 0) {
if (beanName != null && beanName.length() > 0
&& getInterface() != null && getInterface().length() > 0
&& beanName.startsWith(getInterface())) {
setPath(beanName);
}
}
if (!isDelay()) {
export();
}
}
@Override
public void destroy() throws Exception {
// This will only be called for singleton scope bean, and expected to be called by spring shutdown hook when BeanFactory/ApplicationContext destroys.
// We will guarantee dubbo related resources being released with dubbo shutdown hook.
//unexport();
}
// merged from dubbox
@Override
protected Class getServiceClass(T ref) {
if (AopUtils.isAopProxy(ref)) {
return AopUtils.getTargetClass(ref);
}
return super.getServiceClass(ref);
}
}
複製程式碼
可以看到ServiceBean繼承了ServiceConfig類,實現了InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware。
InitializingBean
只包括afterPropertiesSet()方法,繼承該介面的類,在初始化bean的時候會執行該方法。在構造方法之後呼叫。
DisposableBean
DisposableBean也是一個介面,提供了一個唯一的方法destory()。在Bean生命週期結束前呼叫destory()方法做一些收尾工作.
init-method destory-method
@PostConstruct 和 @PreDestroy
Constructor >> @Autowired >> @PostConstruct
ApplicationContextAware
Spring容器會檢測容器中的所有Bean,如果發現某個Bean實現了ApplicationContextAware介面,Spring容器會在建立該Bean之後,自動呼叫該Bean的setApplicationContextAware()方法,呼叫該方法時,會將容器本身作為引數傳給該方法
ApplicationListener
當Spring容器初始化完成之後,會釋出一個ContextRefreshedEvent事件,實現ApplicationListener介面的類,會呼叫*onApplicationEvent(E event)*方法。
BeanNameAware
public void setBeanName(String beanName) {
this.beanName = beanName;
}
獲得自己的名字
BeanFactoryAware
讓Bean獲取配置他們的BeanFactory的引用。
在Spring註冊完成之後會呼叫finishRefresh方法,在該方法中會呼叫實現了ApplicationListenner類的onApplicationEvent方法。
public void onApplicationEvent(ContextRefreshedEvent event) {
if (isDelay() && !isExported() && !isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
export();
}
}
複製程式碼
ServiceBean的OnApplicationEvent方法如上,可以看到在該方法中呼叫了export實現了服務的註冊。
再看一看ReferenceBean的實現:
public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {
private static final long serialVersionUID = 213195494150089726L;
private transient ApplicationContext applicationContext;
public ReferenceBean() {
super();
}
public ReferenceBean(Reference reference) {
super(reference);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
SpringExtensionFactory.addApplicationContext(applicationContext);
}
@Override
public Object getObject() {
return get();
}
@Override
public Class<?> getObjectType() {
return getInterfaceClass();
}
@Override
@Parameter(excluded = true)
public boolean isSingleton() {
return true;
}
@Override
@SuppressWarnings({"unchecked"})
public void afterPropertiesSet() throws Exception {
if (getConsumer() == null) {
Map<String, ConsumerConfig> consumerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConsumerConfig.class, false, false);
if (consumerConfigMap != null && consumerConfigMap.size() > 0) {
ConsumerConfig consumerConfig = null;
for (ConsumerConfig config : consumerConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
if (consumerConfig != null) {
throw new IllegalStateException("Duplicate consumer configs: " + consumerConfig + " and " + config);
}
consumerConfig = config;
}
}
if (consumerConfig != null) {
setConsumer(consumerConfig);
}
}
}
if (getApplication() == null
&& (getConsumer() == null || getConsumer().getApplication() == null)) {
Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false);
if (applicationConfigMap != null && applicationConfigMap.size() > 0) {
ApplicationConfig applicationConfig = null;
for (ApplicationConfig config : applicationConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
if (applicationConfig != null) {
throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
}
applicationConfig = config;
}
}
if (applicationConfig != null) {
setApplication(applicationConfig);
}
}
}
if (getModule() == null
&& (getConsumer() == null || getConsumer().getModule() == null)) {
Map<String, ModuleConfig> moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false);
if (moduleConfigMap != null && moduleConfigMap.size() > 0) {
ModuleConfig moduleConfig = null;
for (ModuleConfig config : moduleConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
if (moduleConfig != null) {
throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config);
}
moduleConfig = config;
}
}
if (moduleConfig != null) {
setModule(moduleConfig);
}
}
}
if ((getRegistries() == null || getRegistries().isEmpty())
&& (getConsumer() == null || getConsumer().getRegistries() == null || getConsumer().getRegistries().isEmpty())
&& (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().isEmpty())) {
Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false);
if (registryConfigMap != null && registryConfigMap.size() > 0) {
List<RegistryConfig> registryConfigs = new ArrayList<>();
for (RegistryConfig config : registryConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
registryConfigs.add(config);
}
}
if (!registryConfigs.isEmpty()) {
super.setRegistries(registryConfigs);
}
}
}
if (getMonitor() == null
&& (getConsumer() == null || getConsumer().getMonitor() == null)
&& (getApplication() == null || getApplication().getMonitor() == null)) {
Map<String, MonitorConfig> monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false);
if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
MonitorConfig monitorConfig = null;
for (MonitorConfig config : monitorConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
if (monitorConfig != null) {
throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config);
}
monitorConfig = config;
}
}
if (monitorConfig != null) {
setMonitor(monitorConfig);
}
}
}
Boolean b = isInit();
if (b == null && getConsumer() != null) {
b = getConsumer().isInit();
}
if (b != null && b) {
getObject();
}
}
@Override
public void destroy() {
// do nothing
}
}
複製程式碼
在ReferenceBean中是通過FactoryBean來實現消費服務去註冊中心拉取相應的服務,建立對應的proxy的。