Spring是每個java程式員都必須要掌握的技能,很多人都想通過閱讀源碼來提升自己的技術深度,這裡分享一下我讀源碼的方法。
我覺得看源碼應該先大概的讀,知道主脈絡,然後再去讀細節,這樣才不會亂,先放上我畫的圖(不怎麼會畫,大概看看就好,最大的正方形就是ioc容器)
然後我們來看一下照着圖來走一下代碼
在springboot啟動類打斷點
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
經過SpringApplication構造函數完成一些初始化操作後來到
SringApplication這個類的ConfigurableApplicationContext 方法,
這個方法我們主要看 this.refreshContext(context); 這一行,這是建立ioc容器的方法,其他的可以等熟悉了主要脈絡再去細看
public ConfigurableApplicationContext run(String... args) {
//計時器執行個體,并設定計時器id,name和開始時間
StopWatch stopWatch = new StopWatch();
stopWatch.start();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
//系統屬性設定 一般是在程式開始激活headless模式,告訴程式,現在你要工作在Headless mode下,就不要指望硬體幫忙了,你得自力更生,依靠系統的計算能力模拟出這些特性來
configureHeadlessProperty();
//初始化監聽器 META-INF/spring.factories檔案中擷取SpringApplicationRunListener接口的實作類。
SpringApplicationRunListeners listeners = getRunListeners(args);
//啟動已經準備好的監聽器 getSpringFactoriesInstances
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
//裝配環境參數 儲存args參數
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 準備環境變量, 讀取 bootstrapContext application.properties檔案中的環境變量
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 系統配置忽略标志spring.beaninfo.ignore
configureIgnoreBeanInfo(environment);
//列印banner圖案
Banner printedBanner = printBanner(environment);
//建立ConfigurableApplicationContext(應用配置上下文)
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
//将listeners、environment、applicationArguments、banner等重要元件與上下文對象關聯
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//這個方法很重要 ioc容器的建立
refreshContext(context);
//ioc容器建立後
afterRefresh(context, applicationArguments);
//計時結束
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
一路進去AbstractApplicationContext這個實作類的refresh()方法
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
//初始化工作,記錄下容器的啟動時間、标記“已啟動”狀态、處理配置檔案中的占位符
this.prepareRefresh();
//這個是建立bean工廠的方法主要是createBeanFactory():建立BeanFactory和loadBeanDefinitions() :加載BeanDefinination兩個方法
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//填充beanFactory屬性
this.prepareBeanFactory(beanFactory);
try {
//這是一個擴充點
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
//執行個體化并調用所有注冊的BeanFactoryPostProcessors
this.invokeBeanFactoryPostProcessors(beanFactory);
// 注冊 BeanPostProcessor 的實作類,注意看和 BeanFactoryPostProcessor 的差別
// 此接口兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 兩個方法分别在 Bean 初始化之前和初始化之後得到執行。注意,到這裡 Bean 還沒初始化
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
//國際化相關
this.initMessageSource();
// 初始化目前 ApplicationContext 的事件廣播器
this.initApplicationEventMulticaster();
// 從方法名就可以知道,典型的模闆方法(鈎子方法),
// 具體的子類可以在這裡初始化一些特殊的 Bean(在初始化 singleton beans 之前)
this.onRefresh();
// 注冊事件監聽器,監聽器需要實作 ApplicationListener 接口
this.registerListeners();
// 重點,重點,重點
// 初始化所有的 singleton beans
//(lazy-init 的除外)
this.finishBeanFactoryInitialization(beanFactory);
// 最後,廣播事件,ApplicationContext 初始化完成
this.finishRefresh();
} catch (BeansException var10) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
}
// 銷毀已經初始化的 singleton 的 Beans,以免有些 bean 會一直占用資源
this.destroyBeans();
// Reset 'active' flag.
this.cancelRefresh(var10);
throw var10;
} finally {
this.resetCommonCaches();
contextRefresh.end();
}
}
}
對于上面大家不知道BeanFactoryPostProcessor和BeanPostProcessor是幹嘛的。大家可以看看這篇文章
https://blog.csdn.net/caihaijiang/article/details/35552859
然後這裡給大家說一下具體每個方法做了什麼
- prepareRefresh
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
// ①在上下文環境中初始化任何占位符屬性源。
initPropertySources();
// ②驗證所有标記為required的屬性都是可解析的:
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}
ApplicationContext重新整理前的準備工作,比如設定啟動時間(startupDate),激活标志(active & closed),以及執行屬性源的初始化(見闡釋)
闡釋:
①initPropertySources()是模闆抽象方法,使用者可以根據需要進行重寫。 Warn見WebApplicationContext解析
protected void initPropertySources() {
// For subclasses: do nothing by default.
}
我們可以覆寫該方法,進行自定義的屬性處理以及設定。比如如果項目的啟動必須依賴于目前機器的環境變量ENV,那麼我們可以這樣寫:
protected void initPropertySources() {
// For subclasses: do nothing by default.
getEnvironment().setRequiredProperties("ENV")
}
②getEnvironment().validateRequiredProperties(),對所有被标記為required的屬性進行驗證
在前面我們知道,這裡的envirmonent是一個StandardEnvironment,它是ConfigurablePropertyResolver的子類,故而它可以執行validateRequiredProperties()方法(因為該方法是由ConfigurablePropertyResolver接口聲明的)。
我們還知道AbstractEnvironment中聲明了一個類型為ConfigurablePropertyResolver的propertyResolver屬性,并寫死其值為PropertySourcesPropertyResolver對象。在這裡的驗證required屬性的工作也是交給了這個PropertyResolver來處理!!
具體的驗證邏輯讀者可以自行閱讀源碼,其實:
- setRequiredProperties()是将字元串加入到一個由AbstractPropertyResolver維護的一個名為requiredProperties的Set集合中
- validateRequiredProperties()僅僅是循環requiredProperties并驗證存在罷了。
private final ConfigurablePropertyResolver propertyResolver =
new PropertySourcesPropertyResolver(this.propertySources);
@Override
public void validateRequiredProperties() throws MissingRequiredPropertiesException {
this.propertyResolver.validateRequiredProperties();
}
- obtainFreshBeanFactory
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
protected final void refreshBeanFactory() throws BeansException {
//如果目前存在beanFactory,則先銷毀掉
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(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);
}
}
}
概述:refreshBeanFactory()方法對ApplicationContext上下文的底層beanFactory執行真正的重新整理,先關閉之前的beanFactory(如果有的話),并為目前的ApplicationContext上下文生命周期的下一階段初始化一個新的beanFactory。
refreshBeanFactory()方法中的核心方法調用分别是:
- createBeanFactory():建立BeanFactory
- loadBeanDefinitions() :加載BeanDefinination
createBeanFactory
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
下面是DefaultListableBeanFactory的建立曆程
該過程僅僅是BeanFactory的執行個體化,并設定一些比較公共的配置,不予講解,感興趣的可以自己Debug看看
loadBeanDefinitions
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 為給定的BeanFactory建立一個XmlBeanDefinitionReader
// XmlBeanDefinitionReader用于讀取XML并解析為BeanDefinition,并進行注冊
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 為BeanDefinition的讀取器,配置資源加載器,環境變量,以及EntityResolver(用于判斷)
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
Ⅰ.首先,使用給定的BeanFactory類型的入參,建立一個XmlBeanDefinitionReader
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
//提供了對Document的解析能力,并将解析後的BeanDefinition注冊到BeanDefintionRegistry對象上
private Class<? extends BeanDefinitionDocumentReader> documentReaderClass =
DefaultBeanDefinitionDocumentReader.class;
@Nullable
//處理自定義标簽時候需要使用,它可以通路我們注冊的自定義标簽解析器,完成對自定義标簽的解析
//預設的實作是DefaultNamespaceHandlerResolver
private NamespaceHandlerResolver namespaceHandlerResolver;
//将Resource轉為Document的加載器,純技術SAX技術,無需關心
private DocumentLoader documentLoader = new DefaultDocumentLoader();
@Nullable
private EntityResolver entityResolver;
private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded =
new NamedThreadLocal<>("XML bean definition resources currently being loaded");
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
//直接調用方父類構造器
super(registry);
}
}
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {
//用于注冊解析的BeanDefinition(說白了,就是将解析出的BeanDefinition,放到registry裡儲存,以用于bean執行個體化)
private final BeanDefinitionRegistry registry;
@Nullable
//用于加載配置檔案的處理器,它可以将配置及檔案解析為Resourced對象,以用于後面将Resource通過SAX轉為Document對象
private ResourceLoader resourceLoader;
@Nullable
//ApplicationContext的類加載器
private ClassLoader beanClassLoader;
//環境變量
private Environment environment;
//XmlBeanDefinitionReader的父類AbstractBeanDefinitionReader
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
// 根據傳入的registry,決定ResourceLoader(它是用于加載配置檔案的加載器)
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
}
else {
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
// 如果可能的話,繼承Environment
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
this.environment = new StandardEnvironment();
}
}
}
注:從XmlBeanDefinitionReader的構造器參數簽名中,我們發現其實XmlBeanDefinitionReader需要的是一個BeanDefinitionRegistry對象,但是因為我們剛才生成的BeanFactory實作了該接口,故而可以作為入參。
闡釋:真實的構造邏輯在AbstractBeanDefinitionReader中實作的,它将我們傳入的registry,指派給自己的registry屬性上
驗證傳入的這個registry(本例中指的是beanFactory)是否是一個ResourceLoader接口的實作:
- 如果是:直接将該其指派給resourceLoader屬性
-
如果否:建立一個PathMatchingResourcePatternResolver對象,然後指派給resourceLoader屬性。本例中的beanFactory是DefaultListableBeanFactory,它并沒有實作ResourceLoader。PathMatchingResourcePatternResolver是對DefaultResourceLoader(它是ResourceLoader的預設實作)的二次封裝,它額外添加了對classpath*:
或者 war: 或者 */ 等路徑文法的支援!!!
然後驗證傳入的這個registry(即該beanFactory)是否是一個EnvironmentCapable接口的實作:
- 如果是:則将其指派給environment屬性
- 如果否:則建立一個StandardEnvironment并指派給environment屬性
PS:ResourceLoader是用于加載資源檔案為Resource對象的,故而對XmlBeanDefinitionReader很重要
Ⅱ. 執行個體化完XmlBeanDefinitionReader,對其進行配置
// 使用該上下文的資源加載環境,來配置XmlBeanDefinitionReader
beanDefinitionReader.setEnvironment(this.getEnvironment());
//請注意,這裡對ResourceLoader進行了重新指派,即将this,即ClassPathXmlApplicationContext指派給它
//ClassPathXmlApplicationContext的父類繼承自DefaultResourceLoader(它是ResourceLoader的預設實作),是以它是一個有效的ResourceLoader
//多嘴一句,ClassPathXmlApplicationContext并不是直接複用DefaultResourceLoader,而是在其内部初始化了一個PathMatchingResourcePatternResolver類型的resourcePatternResolver變量,在真正加載檔案時,全權交給他,如果是模式比對的,那麼它就處理了,如果并模式比對,那麼再複用這個DefaultResourceLoader。
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 允許子類提供Reader的自定義初始化(保留給子類使用的)
initBeanDefinitionReader(beanDefinitionReader);
Ⅲ .loadBeanDefinitions(beanDefinitionReader)
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);
}
}
概述:對ApplicationConext的configLoacations進行for循環,分别交給XmlBeanDefinitionReader單解析
闡述:需要注意的是,我們在最前面講了,ApplicationContext将配置檔案的路徑,存儲在configLocations屬性中。是以在解析BeanDefinition之前,需要先将該配置檔案提取出來,然後交給XmlBeanDefinitionReader去操作(因為XmlBeanDefinitionReader與ApplicationmContext并沒有直接關系,是以無法在運作時擷取到這些配置檔案的資訊)。
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int count = 0;
for (String location : locations) {
count += loadBeanDefinitions(location);
}
return count;
}
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
//還記得為XmlBeanDefinitionReader單獨配置的ResourceLoader嗎??
//這裡需要使用它,将configLocation裡的配置檔案路徑,加載解析為Resource資源
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// 資源的模式比對功能可用.本例子中的resourceLoader是ClassPathXmlApplicationContext,它所實作的ResolveLoader是具有資源模式比對的能力的
try {
//将資源加載的工作委托給resourceLoader
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
}
return count;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// 資源的模式比對功能不可用,隻可以通過絕對URL加載單一資源
Resource resource = resourceLoader.getResource(location);
int count = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
}
return count;
}
}
}
注:XmlBeanDefinitionReader是AbstractBeanDefinitionReader的子類
配置檔案資源的加載比較簡單,看上面的注釋即可,接下來着重講解loadBeanDefinitions方法調用
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
@Override
//對Resource進行編碼
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
//resourcesCurrentlyBeingLoaded中存儲了目前正在被解析的Resource的Set集合,防止同一Resource被多次解析
//檔案被解析完後,會從Set集合中删除掉
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
//擷取編碼後的Resource的檔案流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
//使用InputSourece對InputStream進行封裝(因為SAX值隻識别IputSouce)
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//BeanDefinition加載
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//使用XmlBeanDefinitionReader的類型為DefaultDocumentLoader的documentLoader變量,來将Resource解析為Document
//純SAX技術,無需care
Document doc = doLoadDocument(inputSource, resource);
//
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
}
//提供了對Document的解析能力,并将解析後的BeanDefinition注冊到BeanDefintionRegistry對象上
private Class<? extends BeanDefinitionDocumentReader> documentReaderClass =
DefaultBeanDefinitionDocumentReader.class;
@Nullable
//處理自定義标簽時候需要使用,它可以通路我們注冊的自定義标簽解析器,完成對自定義标簽的解析
//預設的實作是DefaultNamespaceHandlerResolver
private NamespaceHandlerResolver namespaceHandlerResolver;
//将Resource轉為Document的加載器,純技術SAX技術,無需關心
private DocumentLoader documentLoader = new DefaultDocumentLoader();
@Nullable
private EntityResolver entityResolver;
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
return BeanUtils.instantiateClass(this.documentReaderClass);
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//建立一個可以解析Doument的解析器
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
//使用documentReader完成BeanDefinition的提取,構造和注冊(注冊到BeanDefinitionRegistry上)
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
}
這一塊代碼體量較大,但是工作内容很簡單,讀者可以參考我的注釋,腦海裡勾勒粗Spring的處理過程,為了簡答起見,我以直白的表述,闡釋這個過程.:
在前面,我們通過XmlBeanDefinitionReader中的ResourceLoader,将配置檔案解析為Resource,我們先對該Resource做編碼(比如UTF-8等格式的編碼),然後提取該資源的InputStream,最終将其轉換為可以為SAX解析器所識别的InputSource對象。
XmlBeanDefinitionReader中定義了一個類型為DefaultDocumentLoader的documentLoader變量,通過該加載器,可以将InputSource解析為Document對象。
XmlBeanDefinitionReader還定義了一個專門負責解析Document的讀取器,即DefaultBeanDefinitionDocumentReader,我們将前面DocumentLoader解析生成的Document對象傳遞給它,并附帶一個XmlReaderContext對象。
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
//建立一個XmlReaderContext,即Xml配置檔案讀取的上下文,用于承載一些讀取、解析Xml配置檔案時
//所需要使用的一些工具處理器,比如配置檔案的Resource、NamespaceHandlerResolver等
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
public NamespaceHandlerResolver getNamespaceHandlerResolver() {
if (this.namespaceHandlerResolver == null) {
//初始化XmlBeanDefinitionReader時并未設定namespaceHandlerResolver屬性,是以
//會建立一個NamespaceHandlerResolver的預設實作類:DefaultNamespaceHandlerResolver的執行個體
this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
}
return this.namespaceHandlerResolver;
}
}
注:XmlReaderContext,是Per-Resource的,即一個Resource對應一個Document,而每個Docunent則對用唯一的專用ReaderContext對象。該對象提供了對NamespaceHandlerResolver的通路,使用的是DefaultNamespaceHandlerResolver這個預設實作,當然,這是XmlBeanDefinitionReader在構造它時,為其裝載的)。
具體的BeanDefinition解析邏輯,完全的委托給了DefaultBeanDefinitionDocumentReader,注目觀看:
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
protected void doRegisterBeanDefinitions(Element root) {
//入參是Document的根元素
//DefaultBeanDefinitionDocumentReader将Element元素的解析工作,委托給了BeanDefinitionParserDelegate來負責
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
//profile驗證
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
//模闆方法,實作是空的,由使用者自定義,在真正處理XML解析之前做什麼...
preProcessXml(root);
//BeanDefinition核心解析方法
parseBeanDefinitions(root, this.delegate);
//模闆方法,實作是空的,由使用者自定義,在真正處理XML解析之前做什麼...
postProcessXml(root);
this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//注意:這裡的元素是根節點Element
//如果delegate判斷該Element是屬于預設命名空間的,那麼取出子節點,循環解析
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);
}
}
protected BeanDefinitionParserDelegate createDelegate(
XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) {
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
delegate.initDefaults(root, parentDelegate);
return delegate;
}
}
概述:DefaultBeanDefinitionDocumentReader将Element解析的重任,委托給了BeanDefinitionParserDelegate對象,而它則負責Document中Element的拆解,元素識别以及調用delegate的适當方法做元素的解析,最終生成BeanDefinition對象。
闡釋:DefaultBeanDefinitionDocumentReader在這裡的作用,更像是一個裝備勞工,它購買一個BeanDefinitionParserDelegate機器(該機器可以将Element解析為一個BeanDefinition),然後使用它判斷原料(即Document的根元素)是否是Spring原廠(即Spring預設命名空間)的:
-
如果該Element是原廠的,那說明是使用Spring的标準配置的配置檔案,那麼先拆解該根元素,取出所有的子元素,for疊代,然後在交給BeanDefinitionParserDelegate來判斷該子元素是否是Spring原廠的(比如Spring所支援的<
bean />
元素),如果是原廠支援的,那麼調用parseDefaultElement(element,delegate)做二次解析,畢竟各種元素的處理方法是不一樣的,比如<
bean />,以及< import
/>等。如果子元素并非Spring原廠支援的,亦即自定義的,那麼完全委托給BeanDefinitionParserDelegate的parseCustomElement()方法去處理
- 如果子元素并非原廠的,那麼完全委托給BeanDefinitionParserDelegate的parseCustomElement()方法去處理
先看如何加工Spring原廠的Element:
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
//如果該子元素是<import>,那麼先對import内檔案位址解析,即替換掉${...},然後進行beanDefinition的解析工作,這個過程與我們傳給ClassPathXmlApplicationContext的配置檔案的解析過程一毛一樣,也建議讀者自行閱讀源碼
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
//如果該子元素是<alias>,那麼直接在readerContext中的registry上注冊該别名即可
//實作比較簡單,建議讀者自行閱讀源碼
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
//如果蓋子元素是一個<bean>,那麼完全委托給deleaget去解析
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 如果該子元素是一個<beans>,那麼遞歸調用doRegisterBeanDefinitions
doRegisterBeanDefinitions(ele);
}
}
}
概述:方法很簡單,根據Element的節點名稱,調用不同的方法去解析及注冊
最重要的就是< bean />元素的處理,下面着重描述:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//委托給delegate全權處理element的解析,傳回一個BeanDefinitionHolder
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//若可以,對BeanDefinitionHolder進行包裝,也是很重要的
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 将最終包裝過的BeanDefinitionHolder,注冊到BeanDefinitionRegistry上
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));
}
}
最重要的三個步驟:
- delegate.parseBeanDefinitionElement(ele);
- elegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
-
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,
getReaderContext().getRegistry());
public class BeanDefinitionParserDelegate {
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
//提取element的id、name 屬性,需要提到的一點是,name屬性也被成為别名,name是支援多值得,格式類似于name="piemon,anokata"
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<>();
//将name屬性按照分隔符分割開來,并添加到alias清單中
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
//将id指派給beanName,校驗:beanNaame不能為空與alias為空不可同時存在
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
//beanName唯一性校驗,前面說過,BeanDefinitionParserDelegate是一個有狀态的對象,
//它使用一個Set<String>類型的usedNames,其中儲存beanName和别名(别名也參與一緻性校驗)
//實作個很簡單,Set中查找beanName,查到就不滿足唯一性,異常!否則通過
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
//解析Element元素,生成一個ASbstractBeanDefinition對象(其實真實類型是GenericBeanDefinition,它是AbstractBeanDefinition的子類)
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("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包裝BeanDefinition
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
//該方法存在無法解析Element的情況,是以傳回null
return null;
}
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
//parseState中儲存目前正在被解析的beanName,它是一個棧結構,push/pop
this.parseState.push(new BeanEntry(beanName));
String className = null;
//判斷<bean>中是否有class屬性,如 <bean class="">
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
//判斷<bean>中是否有parent屬性 <bean parent="">
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
//根據className和parent屬性的值,建構AbstractBeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//解析<bean>中的attribute
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
//給BeanDefinition設定一個用于展示的好看的名字,沒啥鳥用
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//解析<bean>中的<meta>子标簽,也被成為元屬性
parseMetaElements(ele, bd);
//這兩兩個解析比較重要,分别下列兩種子元素:
// <lookup-method name="createCommand" bean="myCommand"/>
// <replaced-method name="computeValue" replacer="replacementComputeValue" />
//這兩個特别有用,用于方法注入,并非setter注入喲~~
//典型場景:Singleton Bean種使用短周期的Bean(比如Proto/Request/Session等Scope的Bean)
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析構造器參數,即<bean>中的<construct-arg>子元素
parseConstructorArgElements(ele, bd);
//解析<bean>中的<property name="" value="">
parsePropertyElements(ele, bd);
//<bean class="example.SimpleMovieCatalog">
< // <qualifier value="main"/>
//</bean> 多用于同類型多Bean的情況
parseQualifierElements(ele, bd);
//為BeanDefinition設定Resource,就是此Element所存在于的配置檔案的Resource表現形式
bd.setResource(this.readerContext.getResource());
//功能主要是由SourceExtractor負責的,但是我也不知道幹嘛的~~希望讀者有懂得,下面留言指點下
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 {
//彈出壓入得beanName,表示已經解析完成
this.parseState.pop();
}
return null;
}
//new一個BeanDefinition
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
throws ClassNotFoundException {
//将建立BeanDefinition的任務,交給了BeanDefinitionReaderUtils,并設定其parent屬性以及beanClassName屬性,這些屬性都是參數傳來的!
return BeanDefinitionReaderUtils.createBeanDefinition(
parentName, className, this.readerContext.getBeanClassLoader());
}
}
概述:BeanDefinitionParserDelegate是一個有狀态的委托類,用于解析XML格式的配置檔案。parseBeanDefinitionElement(…)方法的作用,是将一個Element,解析成一個BeanDefinition,然後用BeanDefinitionHolder包裝一下。
闡述:看注釋,更清楚
繼續回到Spring原廠元素的解析上,将Element解析為BeanDefinition後,可能還需要包裝它,下面講decorateBeanDefinitionIfRequired:
PS:先看完下面的自定義元素解析(parseCustomerElement),再回頭看這裡的包裝,否則本末倒置了!!!
public class BeanDefinitionParserDelegate {
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef) {
//交給重載的方法處理
return decorateBeanDefinitionIfRequired(ele, originalDef, null);
}
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
BeanDefinitionHolder finalDefinition = originalDef;
// 首先根據自定義的attribute,進行包裝
NamedNodeMap attributes = ele.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
// 然後根據内嵌的自定義子元素,進行包裝
// 需要交代一下,我們前面講過,自定義的元素會交給ddelegate的parseCustomerElemenmt方法解析
NodeList children = ele.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
}
return finalDefinition;
}
public BeanDefinitionHolder decorateIfRequired(
Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
//首先擷取元素的命名空間
String namespaceUri = getNamespaceURI(node);
//判斷是否是預設的命名空間,Spring的預設命名空進是beans,其他的都不是
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
//如果是自定義的元素,那麼很可能會需要包裝,我們首先解析出該命名空間的NamespaceHandler
//該NamespaceHandler的具體類型的父類型是一個NamespaceHandlerSupport,它是NamespaceHandler子類
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler != null) {
//每個命名空間都有一個自己的專屬NamespaceHandler,當然這是規範,可以不遵守的
//每個NamespaceHandler裡都維護着BeanDefinitionParser的Map:parsers和BeanDefinitionDecorator的map:decorators、map:attributeDecorators(不知道怎麼解釋,直白一點,前者包裝<aop:scope-proxy>,即元素級的包裝标簽,後者包裝的是Attribute級的屬性),
//顧名思義,BeanDefinitionParser是用來解析自定義的元素為BeanDefinition的,
//而BeanDefinitionDecorator則用來包裝
BeanDefinitionHolder decorated =
handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
if (decorated != null) {
return decorated;
}
}
else if (namespaceUri.startsWith("http://www.springframework.org/")) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
}
else {
// A custom namespace, not to be handled by Spring - maybe "xml:...".
if (logger.isDebugEnabled()) {
logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
}
}
}
return originalDef;
}
}
概述:根據Element的命名空間,找到注冊的NamespaceHandlerSupport(他是NamespaceHandler接口的子類),然後找出其上注冊的BeanDefinitionDecorator,用于對BeanDefinition進行包裝。
BeanDefinition的注冊:
public abstract class BeanDefinitionReaderUtils {
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
//首先在beanName下注冊BeanDefinition
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 然後注冊别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
}
概述:該工具方法先在beanName之下注冊BeanDefinition,然後在想registry注冊其别名嗎,使得對别名的引用亦可以指向所屬的Bean
闡釋:BeanDefinitionRegistry是一個接口,具體的實作是在DefaultListableBeanFactory中實作。
DefaultListableBeanFactory中聲明了一堆的Map,因為他實作了BenaDefinitionRegistry接口,是以他需要具有BeanDefinition的注冊能力,而下面這些Map就是做這個注冊的:
- beanDefinitionMap:Map<String, BeanDefinition>類型,存儲BeanDefinition
- beanDefinitionNames:List<String,>類型,存儲beanName
- frozenBeanDefinitionNames:String[]類型,當機的beanName數組
-
aliasMap:Map<String, String>類型,存儲别名與beanName的映射
其實可以将BeanDefinitionRegistry,看做是一個記憶體資料庫,所有的BeanDefinition資訊都會記錄在其中,用于Bean執行個體化。
至此,解析并注冊了BeanDefinition~~
parseCustomerElement
Spring預設的命名空間僅包括beans.xsd所支援的配置項,而像aop、tx、context等命名空間,是屬于自定義的!!!
在我們的配置項中,添加了對于< context annotation-config >,在< bean />中添加了< aop:scoped-proxy/>,這都是自定義的,為此我們着重解釋一下
public class BeanDefinitionParserDelegate {
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
//有了Element所歸屬的命名空間(更直白一點,就是我們知道<context annotation-config>是由哪個命名空間定義的)
//我們就是提取出readerContext(就是XMLReaderContext,我們在上面講過),然後用readerContext中的mamespaceHandlerResolver
//來對這個命名空間URI進行解析,找出該命名空間的處理器,即NamespaceHandler。
//此處得到NamespaceHandlerResolver是DefaultNamespaceHandlerResolver類型的,它内部維護這一個handlerMapping,
//Map<String, Object> handlerMappings;,鍵是命名空間URI,而值則是NamespaceHander或者是class全類名字元串(可以反射生成處理器對象)
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
//将Element交給該NamespaceHandler解析處理
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
public String getNamespaceURI(Node node) {
//Element是Node的子類,Node中聲明了getNamespaceURI()方法,擷取目前節點的命名空間URI
//對于<context:annotation-config>,他的命名空間URI就是http://www.springframework.org/schema/context,細心的讀者會發現,這是我們在XML上引入的
return node.getNamespaceURI();
}
}
擷取命名空間URI,然後使用NamespaceHandlerResolver對象,根據命名空間URI,檢出對應的命名空間處理器(NamespaceHandelr),最後将Element委托給該handler解析。
注:NamespaceHandler還要負責注冊解析的BeanDefinition到BeanDefinitionRegistry上
自定義命名空間比較重要,我先解釋一下命名空間、命名空間處理器(NamespaceHandelr)、命名空間URI,不要略過,很簡單的:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
1.命名空間:xmlns,就是xml命名空間,全稱xml-namespace,對于xmlns:context,他對應的命名空間就是“http://www.springframework.org/schema/context”,但是這個名字太長了,我們就給他一個短小精悍的别名,即context,官方的解釋是,給命名空間提供一個獨一無二的名字。
2.命名空間URI:其實亦可以稱其為命名空間,我麼可以看一下spring-context.xsd定義(Ctrl就能點進去):
<xsd:schema xmlns="http://www.springframework.org/schema/context"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tool="http://www.springframework.org/schema/tool"
##這就是我們context的命名空間
targetNamespace="http://www.springframework.org/schema/context"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
</xsd:schema>
3.NamespaceHandler:xsd中定義了規範,但是規範沒法将這一個個的Element解析成BeanDefinition,這就需要NamespaceHandler登場了,NamespaceHandlerResolver根據命名空間URI,找出其對應的NamespaceHandler,然後讓它去幫我們将Element解析成BeanDefinition
下面我就以spring-context來舉個栗子!!!
衆所周知,< context annotation-config>使得注解變得可能,那麼它是如何實作的呢??我們一步步的看:
- 首先是spring-context.xsd,他定義了context命名空間的配置規範,使得我們可以在配置檔案中使用< context annotation-config> < context conponent-scan> < context load-time-weaver>等等。spring-context.xsd隻是一個配置規範,用于限制使用者,大家完全可以把它類比成API接口,公共出服務協定。
- 我們最終的目标,是需要解析這些XML配置中的Element,而解析的任務,則是由BeanDefinitionParser接口定義的,Spring的Coder自定義一個AnnotationConfigBeanDefinitionParser類,實作BeanDefinitionParser接口,并在其中添加了對Element的解析邏輯
public class AnnotationConfigBeanDefinitionParser implements BeanDefinitionParser {
@Override
@Nullable
/**
* parse方法解析Element,并将解析後的BeanDefinition,通過parserContext.getRegistry()傳回的
* BeanDefinitionRegistry進行注冊。
* 如果解析後的BanDefinition需要以内嵌的形式被使用,比如被ref屬性引用,那麼傳回必須不能為null
* 如果解析後的BeanDefinition并不需要以内嵌的形式被使用,那麼可以傳回null
*
* 不得不提的一點是,parserContext是解析上下文,可以與XML配置檔案讀取的XmlReaderContext類比,parserContext引用了readerContext,而readerContext引用了beanfactory(beanFacory可以注冊BeanDefinition,因為他實作了BeanDefinitionRegistry)
* 和environment(他提供了環境變量和${..}解析)。
*/
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
// 擷取與該注解相關的BeanPostProcessor的beanDefinition
Set<BeanDefinitionHolder> processorDefinitions =
AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source);
// 為<context:annotation-config> 建立一個CompositeComponentDefinition對象來表示
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
parserContext.pushContainingComponent(compDefinition);
// 将上面得到的BeanPostProcessor集合,定義為BeanComponentDefinition,并作為該标簽的CompositeComponentDefinition的内嵌屬性元件,等于聲明了一個元件層級關系
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
parserContext.registerComponent(new BeanComponentDefinition(processorDefinition));
}
parserContext.popAndRegisterContainingComponent();
//因為該注解是屬于配置型的,并沒有Bean會依賴它,是以傳回null
return null;
}
}
public abstract class AnnotationConfigUtils {
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
/**
* 向BeanDefinitionRegistry注冊了一堆BeanPostProcessor和BeanFactoryPostProcessor,
* 當然并不是通過調用registerBeanPostProcessor來注冊,而是注冊為BeanDefinition,這樣就成為了配置型的BeanPostProcessor
* 需要提醒的一點是,Spring将beanPostProcessor/beanFactoryPostFactory分成了兩類,
* 一類是寫死注冊的,即通過ApplicationContext的addBeanPostProcessor/addBeanFactoryPostFactory,
* 第二類則是通過配置配置的,即将BeanPostProcess/BeanFactoryPostProcess注冊為BeanDefinition
* 寫死的優先級,大于任何配置方式的!!!
*/
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
//注冊一個beanName = internalConfigurationAnnotationProcessor的BeanDefinition
//他的原始類型是ConfigurationClassPostProcessor類
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
private static BeanDefinitionHolder registerPostProcessor(
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(beanName, definition);
return new BeanDefinitionHolder(definition, beanName);
}
}
- NamespaceHandelr:AnnotationConfigBeanDefinitionParser更像是建築勞工,而NamespaceHandler則是包工頭。
//一步了然
//當遇見context命名空間中的annotation-config時候,使用AnnotationConfigBeanDefinitionParser來解析
//當遇到context命名空間中的component-scan時候,使用ComponentScanBeanDefinitionParser來解析
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
-
注冊NamespaceHandler,META-INF檔案夾下,編寫spring.handlers和spring.schemas檔案
spring.handelrs
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler
spring.schemas
http\://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context.xsd
http\://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee.xsd
http\://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang.xsd
http\://www.springframework.org/schema/task/spring-task.xsd=org/springframework/scheduling/config/spring-task.xsd
http\://www.springframework.org/schema/cache/spring-cache.xsd=org/springframework/cache/config/spring-cache.xsd
//
https\://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context.xsd
https\://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee.xsd
https\://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang.xsd
https\://www.springframework.org/schema/task/spring-task.xsd=org/springframework/scheduling/config/spring-task.xsd
https\://www.springframework.org/schema/cache/spring-cache.xsd=org/springframework/cache/config/spring-cache.xsd
Spring遇到自定義的命名空間,比如context,他會首先解析出他的NamespaceURI,也就是http://www.springframework.org/schema/context,然後讓NamespaceHandlerResolver去查找該命名空間的NamespaceHandler,他去查找spring.handlers檔案,就可以找到ContextNamespaceHandler,繼而可以找到annotation-config的BeanDefinitionParser:AnnotationConfigBeanDefinitionParser
- 使用,有了這些基礎工作,我們就可以在XML中使用context上下文:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:contexts="http://www.springframework.org/schema/context" ##為該命名空間起一個别名contexts(注意,我們沒有用context,這個名字可以随意改變)
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context ##contexts命名空間的schema位址
http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
自定義的Element也解析完畢,聽懂了嗎??
prepareBeanFactory
填充BeanFactory屬性
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 告知BeanFactory使用與ApplicationContext一樣的類加載器
beanFactory.setBeanClassLoader(getClassLoader());
//配置SPEL表達式的支援,即#{beanName.field}用法
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//配置屬性編輯器,我們為什麼可以在配置Bean的時候,用字元串表達數值等的意思??因為PropertyEditor幫我們轉換了
//<property name="age" value="99"> 這裡的99是個int,但是我們依然可以用字元串配置它
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
/**
* 配置BeanPostProcessor,BeanPostProcessor會在執行個體化Bean的init-method方法之前前後分别
* 調用其postProcessBeforeInitialization和postProcessAfterInitialization方法
* 我們可以深入看下ApplicationContextAwareProcessor源碼,截取最重要的片段:
* if (bean instanceof Aware) {
* if (bean instanceof EnvironmentAware) {
* ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
* }
* ..類比..
* }
* 其實ApplicationContextAwareProcessor會幫我把幾個特定類型做後置處理,填補上他們需要Aware的東西,
* 比如上面的EnvironmentAware所想感覺到的Environent
* 我需要提醒一下,這是寫死的BeanPostProcess,applicationContext維護了一個 beanPostProcessors:List<BeanPostProcessor>,他儲存這些寫死的BeanPostProcessor
*/
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
//設定Bean執行個體化時所需要忽略的自動裝配的類型,即在依賴注入時,忽略他們
//結合上面的這個ApplicationContextAwareProcessor,應該知道為什麼了吧??
beanFactory.ignoreDependencyInterface(EnvironmentAware.class); ##Look Here
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
//當注冊了依賴解析後,當你在Bean中,注入了BeanFactory類型的值,或者ApplicationEventPublisher類型的值
//那麼,便會直接将beanFactory或者this給他注入進去
//class servier{
// @Autowired
// private ApplicationEventPublisher publisher;
//}
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
//如果需要的話,添加AOP
//<contexts:load-time-weaver />
//containsBean擷取查找是否有beanName為LOAD_TIME_WEAVER_BEAN_NAME的singleton或者beanDefinition
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// 為類型比對設定一個臨時的類加載器
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注冊三個單例的Environment Bean,并設定beanName為environment/systemProperties/systemEnvironment
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
postProcessBeanFactory
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
抽象模闆方法,交給子類去覆寫,到此時,ApplicationContext中的beanFactory已經完全的初始化完,這時候所有的BeanDefinition已經注冊完,但是還沒有執行個體化任何的Bean。此時允許自定義的子類中(就是你自己實作的ApplicationContext類中)去注冊一些特定的BeanPostProcessors。
invokeBeanFactoryPostProcessors
/**
* 執行個體化并調用所有注冊的BeanFactoryPostProcessors,
* 如果BeanFactoryPostProcessor又顯式的優先級,那麼必須care
* 一定要在singleton的bean執行個體化前執行它
*/
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//将執行個體化和調用的邏輯,委托給PostProcessorRegistrationDelegate
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// 檢測LoadTimeWeaver并為編織做準備,算是有點備援,前面prepareBeanFactory步驟中其實都做了,但是不影響
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
//擷取寫死的BeanFactoryPostProcessor,y一定要與配置的BeanFactoryPostProcessor區分開來
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}
下面先看PostProcessorRegistrationDelegate到底是如何做的:
final class PostProcessorRegistrationDelegate {
//代碼題很長,但是邏輯很簡單,查找,filter,排序,invoke
//該方法入參有兩個:
//beanFactory:不多講了
//beanFactoryPostProcessors:注意喲,它的值是在AbstractApplicationContext中通過getBeanFactoryPostProcessors()方法
//擷取的,而beanFactoryPostProcessors是寫死的BeanFactoryPostProcssor的清單(即通過AbstractApplicationContext.addBeanFactoryPostProcessor方法添加進去的)
//寫死的BeanFactoryPostFacry的優先級是最高的,比任何配置的BeanFactoryPostProcessor要高
//您可能會問,那配置的寫死的BeanFactoryPostProcessor在哪呢,他在我們的BeanDefinitionRegistry上注冊着呢
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// BanFactoryPostProcessor接口是頂級接口,他的子接口BeanDefinitionRegistryPostProcessors在其上聲明了一個額外的方法
//即void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
//我們要先執行BeanDefinitionRegistryPostProcessors的postProcessBeanDefinitionRegistry這個方法
//然後在調用這些BanFactoryPostProcessor的postProcessBeanFactory方法
//但是呢,Spring允許BeanDefinitionRegistryPostProcessors和postProcessBeanFactory的實作具有優先級(即實作Ordered或者PriorityOrdered),其中PriorityOrdered的又要比Ordered優先級高一點,優先級最低的是無序的BeanFactoryPostProcessor
Set<String> processedBeans = new HashSet<>();
//如果傳入的BeanFactory執行個體是實作了BeanDefinitionRegistry的話
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
//聲明兩個臨時清單:
//regularPostProcessors用于存儲正常的BeanFactoryPostProcessor
//registryProcessors則用于存儲實作自BeanDefinitionRegistryPostProcessor的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//beanFactoryPostProcessors指的是寫死的BeanFactoryPostProcessor,它的優先級是最高的,故而先執行
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
//如果此寫死的BeanFactoryPostProcessor是實作自BeanDefinitionRegistryPostProcessor,則将其加入到registryProcessors,并執行其特殊的
//postProcessBeanDefinitionRegistry方法,否則,加入到regularPostProcessors中,并不執行任何方法,等最後再統一執行
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, 調用實作了PriorityOrdered的BeanDefinitionRegistryPostProcessors
//beanFactory.getBeanNamesForType,根據類型,擷取該類型的beanMame
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//如果實作了PriorityOrdered,則将其add到currentRegistryProcessors,等待一會的排序和執行
//并将beanName加入到processedBeans,以防止同一個bean,被調用多次
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
//對currentRegistryProcessors排序,然後将其add到registryProcessors
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
//調用currentRegistryProcessors中的BeanDefinitionRegistryPostProcessors的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//清空currentRegistryProcessors,本人覺得是一種不好的設計
currentRegistryProcessors.clear();
// Next, 調用實作了Ordered接口的BeanDefinitionRegistryPostProcessors.
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Finally, 調用所有其他BeanDefinitionRegistryPostProcessors,知道沒有任何一個BeanDefinitionRegistryPostProcessors出現為止.
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// Now, 調用到目前為止出現的所有BeanFactoryPostProcessor 的postProcessBeanFactory方法.
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// 調用用上下文執行個體注冊的工廠處理器。即寫死的BeanFactoryPostProcessor
//因為程式走到這裡,也說明BeanFactory執行個體并非BeanDefinitionRegistry類型,是以優先級什麼的也不care了
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// 分割BeanFactoryPostProcessors,按照PriorityOrdered > Ordered > 其他的順序
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
//跳過,因為這表示該BeanFactoryPostProcessor也是一個BeanDefinitionRegistryPostProcessor,而他已經在前面被處理過了
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, 調用實作了PriorityOrdered接口的 BeanFactoryPostProcessors .
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, 調用實作了Ordered接口的 BeanFactoryPostProcessors .
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, 調用剩下下的 BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
//清理緩存的merged Bean定義,因為post-processors可能修改了原始中繼資料,例如替換值中的占位符……
beanFactory.clearMetadataCache();
}
}
概述:在執行個體化singleton的Bean之前,先調用BeanFactoryPostProcessor,以修改BenDifinition。ApplicationContext存在兩種BeanFactoryPostProcessor,一種是寫死的(即通過ApplicationContext的addBeanFactoryPostProcessor方法注冊的),一種是配置的(即通過xml配置的)。先執行寫死的BeanFactoryPostProcessor,Spring允許優先級,同時BeanDefinitionRegistryPostProcessor作為BeanFactoryPostProcessor的子接口,也擁有比純BeanFactoryPostProcessor類型的執行個體更高的優先級。排序與執行,看注釋即可。
registerBeanPostProcessors
//執行個體化并注冊所有BeanPostProcessor的Bean執行個體
//優先級敏感
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
final class PostProcessorRegistrationDelegate {
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// 在BeanPostPorocessor的鍊最開始,注冊一個BeanPostProcessorChecker,他的作用是
//在bean執行個體窗前的時候,列印日志,比如當:a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// 将實作了PriorityOrdered、Ordered還有其他的 BeanPostProcessors分隔開來
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First,注冊實作了 PriorityOrdered 的 BeanPostProcessors.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, 注冊實作了Ordered接口的BeanPostProcessors.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now,注冊所有的正常BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// Finally, 重新注冊所有的内置BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// 重新注冊後置處理器ApplicationListenerDetector,該處理器會檢測實作了ApplicationListener接口的bean,
// 将其移動到處理器鍊的最後(用于擷取代理等)
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
}
概述:代碼較長,但是幹的工作也很簡單,擷取所有配置的BeanPostProcssor,然後按照PriorityOrdered > Ordered > 其他的順序,調用beanFactory.addBeanPostProcessor(postProcessor)方法進行注冊。因為BeanPostProcessor并不在此時執行,是以這裡做的工作隻是執行個體化、注冊。
BeanPostProcessor是在執行個體化Bean時候init-method執行前後才會被調用喲,詳細見Bean加載的講解。
initMessageSource()
國際化相關
initApplicationEventMulticaster()
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
//注冊監聽者
protected void registerListeners() {
// 首先注冊靜态指定的監聽者。
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 這裡不初始化FactoryBean:我們需要不初始化所有正常bean,而是讓後置處理程式應用于它們!
//這裡隻是将beanName注冊到了廣播器上,即注冊配置方式注冊的監聽者的beanName
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 釋出事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
}
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
//廣播事件
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
}
概述:如果使用者自定義了事件廣播器,那麼使用使用者定義的,否則使用SimpleApplicationEventMulticaster這個ApplicationEventMulticaster預設實作,來作為applicationEventMulticaster變量的值,并将其注冊到beanFactory的單例緩存中。
onRefresh()
對Web的ApplicationContext至關重要,在特定上下文子類中初始化其他特殊bean。
registerListeners()
protected void registerListeners() {
// 注冊靜态(寫死)的特定監聽器.
for (ApplicationListener<?> listener : getApplicationListeners()) {
//注冊
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 注冊配置的監聽者的BeanName,先不執行個體化他們
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
//注冊
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 發射一個earlyEvent
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
finishBeanFactoryInitialization(beanFactory)
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 我目前上下文環境初始化轉換服務,ConversionService
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));
}
//如果此時沒有注冊任何一個解析屬性值的後置處理器, 那麼就注冊一個預設的内嵌屬性值解析器。
//此時,隻要用于解析注解中的值
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// 盡早初始化LoadTimeWeaverAware bean,以便盡早注冊它們的轉換器。
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
//停止使用臨時類加載器進行類型比對。
beanFactory.setTempClassLoader(null);
// 緩存bean的定義(BanDefinition),不會再修改他們了
beanFactory.freezeConfiguration();
// 執行個體化所有剩餘的(非lazy-init的)單例。
beanFactory.preInstantiateSingletons();
}
概述:在該方法中完成BeanFactory的初始化工作,
-
首先檢查ConversionService,那段是否有名字
為"conversionService"或者ConversionService類型的BeanDefinition存在,如果存在,則設定為beanFactory的conversionService變量的值。
- 判斷目前的beanFactory是否有内嵌屬性值解析器,如果不存在,則賦一個預設的解析器
- 盡早初始化LoadTimeWeaverAware bean,以便盡早注冊它們的轉換器。
- 停止對臨時類加載器的使用
- 當機所有的beanDefinition,暗示以後不會再修改它們了
- 執行個體化所有的單例Bean(排除lazy-init)
finishRefresh()
protected void finishRefresh() {
// 清理上下文級别的Rsource資源 (such as ASM metadata from scanning).
clearResourceCaches();
// 為目前上下文初始化生命周期處理器
initLifecycleProcessor();
// 首先将refresh傳播到生命周期處理器上.
getLifecycleProcessor().onRefresh();
//發送終極事件.
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
protected void initLifecycleProcessor() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//判斷上下文是否存在“lifecycleProcessor”的BanDefinition
if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
this.lifecycleProcessor =
beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
if (logger.isTraceEnabled()) {
logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
}
}
else {
//執行個體化一個預設的生命周期處理器
DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
defaultProcessor.setBeanFactory(beanFactory);
this.lifecycleProcessor = defaultProcessor;
beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
if (logger.isTraceEnabled()) {
logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +
"[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");
}
}
}
public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactoryAware {
public void onRefresh() {
startBeans(true);
this.running = true;
}
private void startBeans(boolean autoStartupOnly) {
//擷取所有實作了Lifecycle的Ban
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<>();
//循環啟動重新整理
lifecycleBeans.forEach((beanName, bean) -> {
if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
int phase = getPhase(bean);
LifecycleGroup group = phases.get(phase);
if (group == null) {
group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
phases.put(phase, group);
}
group.add(beanName, bean);
}
});
if (!phases.isEmpty()) {
List<Integer> keys = new ArrayList<>(phases.keySet());
Collections.sort(keys);
for (Integer key : keys) {
phases.get(key).start();
}
}
}
//從目前上下文的底層BeanFactory中擷取所有實作了Lifecycle的Bean
protected Map<String, Lifecycle> getLifecycleBeans() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
Map<String, Lifecycle> beans = new LinkedHashMap<>();
String[] beanNames = beanFactory.getBeanNamesForType(Lifecycle.class, false, false);
for (String beanName : beanNames) {
String beanNameToRegister = BeanFactoryUtils.transformedBeanName(beanName);
boolean isFactoryBean = beanFactory.isFactoryBean(beanNameToRegister);
String beanNameToCheck = (isFactoryBean ? BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);
if ((beanFactory.containsSingleton(beanNameToRegister) &&
(!isFactoryBean || matchesBeanType(Lifecycle.class, beanNameToCheck, beanFactory))) ||
matchesBeanType(SmartLifecycle.class, beanNameToCheck, beanFactory)) {
Object bean = beanFactory.getBean(beanNameToCheck);
if (bean != this && bean instanceof Lifecycle) {
beans.put(beanNameToRegister, (Lifecycle) bean);
}
}
}
return beans;
}
}
概述:Spring中提供了lifecycle接口,而該接口聲明了start/stop方法,實作此接口的Bean,Spring會在啟動時調用其start方法,在Sring關閉時調用stop方法,以開啟和關閉生命周期。
好了,ioc容器的建立過程就是這個樣子,後面再詳細的寫一下aop的原理與bean的生命周期完善一下就差不多了。其他的細節就需要自己慢慢細看了
參考:
https://blog.csdn.net/qq_31179577/article/details/100693282
https://blog.csdn.net/nuomizhende45/article/details/81158383/