前言
說到Spring,似乎IOC、DI成為了我們的共鳴。工作中,Spring無處不在,如影随形,Spring給我們開發者帶來了一個春天。這麼優秀而美麗的架構,我想,源碼是值得我們去深入學習的。
入口準備
我使用的是spring-framework5.0.x版本,建立一個子產品,作為自己的代碼編寫使用,需要在項目中已有的build.gradle檔案引入一些配置和依賴,如下
plugins {
id 'java'
}
group 'org.springframework'
version '5.0.16.BUILD-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
//引入本次所需依賴子產品 context子產品包括了beans、aop、core、expression等
compile(project(":spring-context"))
}
//如果建立的子產品沒有java及resources使用如下進行建立
task 'create-dirs' {
doLast {
sourceSets*.java.srcDirs*.each {
it.mkdirs()
}
sourceSets*.resources.srcDirs*.each {
it.mkdirs()
}
}
}
appliationContent.xml
<bean id="messageService" name="m1,m2,m3" class="com.whp.service.impl.MessageServiceImpl">
<!--引入下面id為message的bean-->
<property name="message" ref="message"/>
</bean>
<bean id="message" class="com.whp.bean.Message"/>
Message.java
/**
* @author wanghp
* @version 1.0
* @date 2020/7/8 23:19
*/
public class Message {
public Message() {
//待會MessageServiceImpl注入Message會列印
System.out.println("instance Message Bean");
}
}
MessageServiceImpl.java
/**
* @author wanghp
* @version 1.0
* @date 2020/7/8 23:41
*/
public class MessageServiceImpl implements MessageService, BeanNameAware {
private Message message;
public MessageServiceImpl() {
//執行個體化MessageServiceImpl Bean會列印
System.out.println(" instance MessageServiceImpl Bean");
}
public void setMessage(Message message) {
this.message = message;
}
@Override
public String speak() {
System.out.println(message);
return "this is my test -->spring ioc ";
}
//BeanNameAware回調方法,其實還有BeanClassLoaderAware、BeanFactoryAware
@Override
public void setBeanName(String name) {
System.out.println("BeanNameAware:" + name);
}
}
Junit Test 也就是我們學習源碼的入口,對于學習Spring找到一個入口是非常重要的。
@Test
public void XMLTest() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("appliationContent.xml");
MessageService messageService = (MessageService) applicationContext.getBean("messageService");
System.out.println(messageService.speak());
}
這是我建立測試的gradle子產品清單結構
在進入ClassPathXmlApplicationContext構造方法之前,一般我們學習源碼常用的2種方式,如下
1.ClassPathXmlApplicationContext:見名知意,基于類路徑下的xml作為Spring容器初始化
2.AnnotationConfigApplicationContext:類似于SpringBoot啟動加載,将主類傳入構造方法。
這兩種裡面其實都是圍繞refresh()裡的13個方法展開的,本次我們使用第一種,基于xml的方式。
啟動過程分析
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
//因為 ApplicationContext 建立起來以後,其實我們是可以通過調用 refresh() 這個方法重建的,
// refresh() 會将原來的 ApplicationContext 銷毀,然後再重新執行一次初始化操作。
refresh();
}
}
進入refresh()方法,先對裡面的13個方法有個大概的印象。
@Override
public void refresh() throws BeansException, IllegalStateException {
//來個鎖,不然你refresh()方法還沒結束,你又來個啟動或銷毀的操作,豈不是亂套了?????
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 準備工作,記錄下容器的啟動時間、标記“已啟動”狀态、處理配置檔案中的占位符
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 這步比較關鍵,這步完成後,配置檔案就會解析成一個個 Bean 定義,注冊到 BeanFactory 中,
// 當然,這裡說的 Bean 還沒有初始化,隻是配置資訊都提取出來了,
// 注冊也隻是将這些資訊都儲存到了注冊中心(說到底核心是一個 beanName-> beanDefinition 的 map)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 設定 BeanFactory 的類加載器,添加幾個 BeanPostProcessor,手動注冊幾個特殊的 bean
// 這塊待會會展開說
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 【這裡需要知道 BeanFactoryPostProcessor 這個知識點,Bean 如果實作了此接口,
// 那麼在容器初始化以後,Spring 會負責調用裡面的 postProcessBeanFactory 方法。】
// 這裡是提供給子類的擴充點,到這裡的時候,所有的 Bean 都加載、注冊完成了,但是都還沒有初始化
// 具體的子類可以在這步的時候添加一些特殊的 BeanFactoryPostProcessor 的實作類或做點什麼事
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 調用 BeanFactoryPostProcessor 各個實作類的 postProcessBeanFactory(factory) 方法
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注冊 BeanPostProcessor 的實作類,注意看和 BeanFactoryPostProcessor 的差別
// 此接口兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 兩個方法分别在 Bean 初始化之前和初始化之後得到執行。注意,到這裡 Bean 還沒初始化
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 初始化目前 ApplicationContext 的 MessageSource,國際化這裡就不展開說了,不然沒完沒了了
initMessageSource();
// Initialize event multicaster for this context.
// 初始化目前 ApplicationContext 的事件廣播器,這裡也不展開了
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 從方法名就可以知道,典型的模闆方法(鈎子方法),
// 具體的子類可以在這裡初始化一些特殊的 Bean(在初始化 singleton beans 之前)
onRefresh();
// Check for listener beans and register them.
// 注冊事件監聽器,監聽器需要實作 ApplicationListener 接口。這也不是我們的重點,過
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 初始化所有的 singleton beans
//(lazy-init 的除外)
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 最後,廣播事件,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);
// Propagate exception to caller.
// 把異常往外抛
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
初始化準備工作
主要還是校驗xml,設定一些初始化值…
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();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
// 校驗 xml 配置檔案
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<>();
}
解析xml,注冊bean,初始化BeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 關閉舊的 BeanFactory (如果有),建立新的 BeanFactory,加載 Bean 定義、注冊 Bean 等等
refreshBeanFactory();
// 傳回剛剛建立的 BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
@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());
// 下面這兩個方法很重要,别跟丢了,具體細節之後說
// 1.設定 BeanFactory 的兩個配置屬性:是否允許 Bean 覆寫、是否允許循環引用
customizeBeanFactory(beanFactory);
//2.加載 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);
}
}
到了loadBeanDefinitions方法,他傳入了個beanFactory,通過方法名,我們可以大概猜測到這個是加載BeanDefinition的,還是多個BeanDefinition,然後可能是放到beanFactory裡。
對于BeanFactory也就是Bean工廠和這裡的實作類DefaultListableBeanFactory肯定是有聯系的,我們先來看一下這兩者的UML圖:
DefaultListableBeanFactory:由圖我們可以發現,它幾乎擁有了上面所有的能力,它的頂層幾乎要麼是接口,要麼是抽象類,而對于DefaultListableBeanFactory而言,它就是一個實作類,擁有了頂層所有的能力,這也就是為什麼DefaultListableBeanFactory是整個spring ioc的始祖,研究透它的前生今世對我們了解spring ioc的概念有着重要的作用。
BeanFactory:沒什麼好講的,大緻了解為Bean工廠吧,裡面的一些方法無非就是通過各種傳參類型擷取Bean。
BeanDefinitionRegistry:如果一個類是BeanFactory的實作類,那麼它就需要實作BeanDefinitionRegistry接口,原因很簡單,Bean工廠需要個人幫他把外部的比如xml配置的,或者基于注解掃面的bean注冊到Bean工廠,每個角色都有自己的職責,而不是BeanFactory什麼都去做,展現了接口與的單一職責設計原則。
Q:到這裡,那麼會有一個面試題,BeanFactory和FactoryBean的差別?
A:先看個FactoryBean的幾個實作類,相信你差不多知道答案了,
FactoryBean其實可以了解為Spring的一種靈活的應用,先看個簡單案例:
xml:
<bean id="person" class="com.whp.service.impl.PersonFactoryBean">
<property name="personInfo" value="wanghp,100"/>
</bean>
PersonFactoryBean.java
public class PersonFactoryBean implements FactoryBean<Person> {
protected final Log logger = LogFactory.getLog(getClass());
private String personInfo;
public String getPersonInfo() {
return personInfo;
}
public void setPersonInfo(String personInfo) {
this.personInfo = personInfo;
}
@Override
public Person getObject() throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("進入getObject");
}
logger.info("進入getObject");
Person person = new Person();
String[] split = personInfo.split(",");
person.setName(split[0]);
person.setAge(Integer.parseInt(split[1]));
return person;
}
@Override
public Class<?> getObjectType() {
logger.info("進入getObjectType");
return Person.class;
}
}
測試:
@org.junit.Test
public void FactoryBeanTest() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("appliationContent.xml");
Object person = applicationContext.getBean("&person");
System.out.println(person);//結果輸出:[email protected]
Object personBean = applicationContext.getBean("person");//結果輸出:[email protected]
System.out.println(personBean);
((Person) personBean).message();
//在Person類輸出屬性資訊為:wanghp今年100歲啦
}
如果你在PersonFactoryBean的getObject方法,比如我把設定年齡改成person.setAge(3);
sout為:wanghp今年3歲啦 當然我也不可能3歲哈哈,題外話
是以一個FactoryBean和你想要的普通Bean就是一念之間("&"),如果想具體了解這兩者差別,小夥伴們可以自行查閱相關資料,我們回歸正軌…
下面開始進入驗證階段。
AbstractXmlApplicationContext.java
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
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));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
//重點在這裡
loadBeanDefinitions(beanDefinitionReader);
}
上面無非就是設定beanDefinitionReader的環境,加載資源,實體分解器EntityResolver,有個概念為SAX,你就把它當作是一個将xml解析到javaBean的東西,進入loadBeanDefinitions方法
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
//這裡不會進來,因為getConfigResources()就是傳回Null
reader.loadBeanDefinitions(configResources);
}
//這個就是拿到我們前面ClassPathXmlApplicationContext構造傳進來的xml檔案名
String[] configLocations = getConfigLocations();
if (configLocations != null) {
//走這裡
reader.loadBeanDefinitions(configLocations);
}
}
進入loadBeanDefinitions方法
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
// 注意這裡是個 for 循環,也就是每個檔案是一個 resource
for (String location : locations) {
counter += loadBeanDefinitions(location);
}
// 最後傳回 counter,表示總共加載了多少的 BeanDefinition
return counter;
}
再進入loadBeanDefinitions方法,下面這段代碼是不是頭皮發麻了,看我标記todo 那2行,前面通過
location也就是字元串"appliationContent.xml",把xml加載進來程式設計一個Resource,因為配置檔案能傳多個,是以是個數組,然後将其傳到loadBeanDefinitions進行解析
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
//todo 核心部分在這裡
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
進入loadBeanDefinitions方法
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
for (Resource resource : resources) {
//看這裡
counter += loadBeanDefinitions(resource);
}
return counter;
}
再進去,然後到了這裡,因為我們解析是xml,是以這個方法所在類為XmlBeanDefinitionReader
将傳進來的resource構造放入EncodedResource,然後拿到InputStream二進制流,将其封裝為一個InputSource對象,然後丢到doLoadBeanDefinitions方法,resource通過get又回到了原來姿态
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);
}
// 用一個 ThreadLocal 來存放配置檔案資源
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
System.out.println(Thread.currentThread().getName());
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
System.out.println("now threadName :"+Thread.currentThread().getName());
if (!currentResources.add(encodedResource)) {
System.out.println("insert if----"+Thread.currentThread().getName());
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
System.out.println("out if ----"+Thread.currentThread().getName());
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();
}
}
}
進入doLoadBeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
//此處省略try{}catch代碼
// 這裡就不看了,将 xml 檔案轉換為 Document 對象
Document doc = doLoadDocument(inputSource, resource);
//TODO 解析及注冊 BeanDefinition
return registerBeanDefinitions(doc, resource);
進入registerBeanDefinitions,原來的inputSource變為了Document,而resource還是原來的配方
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//TODO 單一職責原則,DefaultDocumentLoader執行得到doc,而這個BeanDefinitionDocumentReader就是邏輯處理類
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//todo 注冊該xml前Bean 的數量
int countBefore = getRegistry().getBeanDefinitionCount();
//todo 加載及注冊Bean
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//todo 記錄本次加載的 BeanDefinition 個數
return getRegistry().getBeanDefinitionCount() - countBefore;
}
繼續進入registerBeanDefinitions
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
// 前面都是XML解析的準備階段
// 核心部分開始
// 從 xml 根節點開始解析檔案
doRegisterBeanDefinitions(root);
}
到這裡,核心解析xml部分來了哈,進入doRegisterBeanDefinitions方法,傳入的是Element
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
//TODO 委托給delegate解析
this.delegate = createDelegate(getReaderContext(), root, parent);
//判斷目前Beans節點是否是預設命名空間
if (this.delegate.isDefaultNamespace(root)) {
// 這塊說的是根節點 <beans ... profile="dev" /> 中的 profile 是否是目前環境需要的,
// 如果目前環境配置的 profile 不包含此 profile,那就直接 return 了,不對此 <beans /> 解析
//擷取beans節點的profile屬性 "profile"
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
//可以使用逗号或分号将目前beans标簽指定為多個profile類型
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
//判斷目前beans标簽的profile是否被激活
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;
}
}
}
//解析前處理,留給子類實作
//pre和post裡面目前沒有具體實作,模闆設計模式,一個類要麼面向繼承設計,要麼就用final修飾
preProcessXml(root);
//看這裡
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
進入parseBeanDefinitions方法,主要就是Element和Node一些轉換,判斷,目前我們xml是預設标簽配置的,也就是bean開頭,當然你也可以自定義配置,這需要去寫自己的schemas及xsd
// default namespace 涉及到的就四個标簽 <import />、<alias />、<bean /> 和 <beans />,
// 其他的屬于 custom 的
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//TODO 對bean
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方法,就到了我們解析标簽了,判斷預設标簽屬于什麼類型,找到對應解析方法,我們目前是解析标簽的
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
//解析import标簽
importBeanDefinitionResource(ele);
} else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
//解析alias标簽
processAliasRegistration(ele);
} else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
//解析bean标簽 看這裡
processBeanDefinition(ele, delegate);
} else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
進入解析bean的對應方法,重點來了哈,各位提提精神…
到這裡,才是真正的解析單個bean标簽,變為一個javaBean,也就是我們這裡的bdHolder,然後調用registerBeanDefinition注測我們的BeanDefinition,後面我們大概會講一下這些概念,幫小夥伴們梳理一下這塊内容
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 将 <bean /> 節點轉換為 BeanDefinitionHolder,就是上面說的一堆
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
//TODO 終于出來了,紀念一下目前時間 2020-05-19 15:27
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 将bdHolder注冊到bean工廠
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));
}
}
先看如何将一個标簽内容變為BeanDefinitionHolder,進入parseBeanDefinitionElement方法,他這裡使用的是BeanDefinitionParserDelegate解析器
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
//解析 id屬性
String id = ele.getAttribute(ID_ATTRIBUTE);
//解析 name屬性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
//分割 name屬性
List<String> aliases = new ArrayList<>();
// 将 name 屬性的定義按照 “逗号、分号、空格” 切分,形成一個 别名清單數組,
// 當然,如果你不定義 name 屬性的話,就是空的了
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
// 如果沒有指定id, 那麼用别名清單的第一個名字作為beanName
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (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,然後把配置中的資訊都設定到執行個體中,
// 細節後面細說,先知道下面這行結束後,一個 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 {
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)) {
// 把 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;
}
上面看注釋就好,然後核心方法是parseBeanDefinitionElement,傳回AbstractBeanDefinition的對象,先講講AbstractBeanDefinition,UML如下
至于這幾個類的用法小夥伴們可以自行百度,網上這些類說明及注釋很全面,隻需要記住AbstractBeanDefinition是個抽象類,提供相對比較全面的屬性,然後下面是常用的3個實作類。
進入parseBeanDefinitionElement方法,主要就是解析标簽的一些屬性放入到BeanDefinition中,bean标簽沒有的會采用預設的值,比如scope=“singleton”
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
//解析class屬性
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
//建立用于承載屬性的 AbstractBeanDefinition 類型的 GenericBeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//寫死解析預設 bean 的各種屬性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
/**
* 下面的一堆是解析 <bean>......</bean> 内部的子元素,
* 解析出來以後的資訊都放到 bd 的屬性中
*/
//解析中繼資料
parseMetaElements(ele, bd);
//解析 lookup-method 屬性
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//解析 replaced-method 屬性
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//總結:無論look-up replaced-method都是構造了一個MethodOverride,
// 并最終記錄在了AbstractBeanDefinition的methodOverrides屬性中
//解析構造函數參數
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;
}
總結一下parseBeanDefinitionElement方法如何産生BeanDefinitionHolder對象的
1.AbstractBeanDefinition:解析bean标簽完了将标簽屬性封裝在一個(也就是bd)
2.beanName:beanName隻有一個,别名可以有多個,兩者都是關聯起來的。
3.aliasesArray:别名集合,對應bean标簽的name屬性
然後将1,2,3構造封裝在BeanDefinitionHolder裡
注冊BeanDefinition
進入 BeanDefinitionReaderUtils 的registerBeanDefinition方法
/**
* 從下面面的代碼可以看出,解析的 beanDefinition 都會被注冊到 ,
* BeanDefinitionRegistry 類型的執行個體 registry 中,而對于 beanDefinition
* 的注冊分成了兩部分:通過 beanName 的注冊以及通過别名的注冊。
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
//使用 beanName 做唯一辨別注冊
String beanName = definitionHolder.getBeanName();
//1.通過 beanName 注冊 BeanDefinition
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
//2.注冊所有的别名
// 如果還有别名的話,也要根據别名全部注冊一遍,不然根據别名就會找不到 Bean 了
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
看看如何将BeanDefinitionHolder的BeanDefinition 注冊吧,其實這部分看起來比較常,正常邏輯會走else的this.beanDefinitionMap.put(beanName, beanDefinition);這行代碼,看到這裡,就知道前面為什麼會傳回一個DefaultListableBeanFactory的bean工廠了吧,是以最後注冊BeanDefinition是在Bean的始祖DefaultListableBeanFactory裡面注冊的,應證了我們最初的結論,這其實就是個推導到論證的過程。這部分目前隻是單個bean注冊到bean工廠的beanDefinitionMap過程。
@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 {
//注冊前的最後一次校驗,這裡的校驗不同于之前的XML校驗,
// 但是此校驗非彼校驗,之前的校驗時針對于 XML 格式的校驗,而此時的校驗時針是對于 AbstractBean- Definition 的 methodOverrides 屬性的。
//要是對于 AbstractBeanDefinition 屬性中的**
//校驗 methodOverrides 是否與工廠方法并存或者**
((AbstractBeanDefinition) beanDefinition).validate();
} catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
//因為 beanDefinitionMap 是全局變量,這裡定會存在并發通路
// old? 還記得 “允許 bean 覆寫” 這個配置嗎?allowBeanDefinitionOverriding
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
// 處理重複名稱的 Bean 定義的情況
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
// 如果不允許覆寫的話,抛異常
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + existingDefinition + "] bound.");
} else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
// log...用架構定義的 Bean 覆寫使用者自定義的 Bean
if (logger.isWarnEnabled()) {
logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
} else if (!beanDefinition.equals(existingDefinition)) {
//用新的 Bean 覆寫舊的 Bean
if (logger.isInfoEnabled()) {
logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
} else {
// 用同等的 Bean 覆寫舊的 Bean,這裡指的是 equals 方法傳回 true 的 Bean
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
//覆寫
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<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
} else {
// 最正常的應該是進到這個分支。
// Still in startup registration phase
// 将 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,我們自己也可以在運作時注冊 Bean 到容器中的
this.manualSingletonNames.remove(beanName);
}
// 這個不重要,在預初始化的時候會用到,不必管它。
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
//TODO 重置所有的beanName對應的緩存
resetBeanDefinition(beanName);
}
}
不知道到了這裡,還有多少小夥伴在堅持呢?
上面無非就是加載配置檔案讀标簽然後将标簽内容放入到BeanDefinition中,然後注冊到beanFactory的beanDefinitionMap,說到這個注冊,小夥伴千萬别搞懵了,這裡注冊的是BeanDefinition,還不是我們平常用的Spring管理的Bean,對于BeanDefinition,他隻是一個暫時存儲bean标簽資訊,如果這個bean是單例還是多例,是懶加載還是非攔截在,看下面代碼就明白了
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// 我們可以看到,預設隻提供 sington 和 prototype 兩種,
// 很多讀者可能知道還有 request, session, globalSession, application, websocket 這幾種,
// 不過,它們屬于基于 web 的擴充。
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
// 設定父 Bean,這裡涉及到 bean 繼承,不是 java 繼承。請參見附錄的詳細介紹
// 一句話就是:繼承父 Bean 的配置資訊而已
void setParentName(@Nullable String parentName);
// 擷取父 Bean
@Nullable
String getParentName();
//設定 Bean的類名稱,将來是要通過反射來生成執行個體的
void setBeanClassName(@Nullable String beanClassName);
// 擷取 Bean 的類名稱
@Nullable
String getBeanClassName();
// 設定 bean 的 scope
void setScope(@Nullable String scope);
@Nullable
String getScope();
// 設定是否懶加載
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// 設定該 Bean 依賴的所有的 Bean,注意,這裡的依賴不是指屬性依賴(如 @Autowire 标記的),
// 是 depends-on="" 屬性設定的值。
void setDependsOn(@Nullable String... dependsOn);
// 傳回該 Bean 的所有依賴
@Nullable
String[] getDependsOn();
// 設定該 Bean 是否可以注入到其他 Bean 中,隻對根據類型注入有效,
// 如果根據名稱注入,即使這邊設定了 false,也是可以的
void setAutowireCandidate(boolean autowireCandidate);
// 該 Bean 是否可以注入到其他 Bean 中
boolean isAutowireCandidate();
// 主要的。同一接口的多個實作,如果不指定名字的話,Spring 會優先選擇設定 primary 為 true 的 bean
void setPrimary(boolean primary);
// 是否是 primary 的
boolean isPrimary();
// 如果該 Bean 采用工廠方法生成,指定工廠名稱。對工廠不熟悉的讀者,請參加附錄
// 一句話就是:有些執行個體不是用反射生成的,而是用工廠模式生成的
void setFactoryBeanName(@Nullable String factoryBeanName);
// 擷取工廠名稱
@Nullable
String getFactoryBeanName();
// 指定工廠類中的 工廠方法名稱
void setFactoryMethodName(@Nullable String factoryMethodName);
// 擷取工廠類中的 工廠方法名稱
@Nullable
String getFactoryMethodName();
// 構造器參數
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
// Bean 中的屬性值,後面給 bean 注入屬性值的時候會說到
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
// 是否 singleton
boolean isSingleton();
// 是否 prototype
boolean isPrototype();
// 如果這個 Bean 是被設定為 abstract,那麼不能執行個體化,
// 常用于作為 父bean 用于繼承,其實也很少用......
boolean isAbstract();
int getRole();
@Nullable
String getDescription();
@Nullable
String getResourceDescription();
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
準備BeanFactory
這斷你可以了解為前面beanFactory不是拿到了,這裡是填充一下其他的東西,把要的放進來,不要的忽視就ok了,具體看注釋
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
// 設定 BeanFactory 的類加載器,我們知道 BeanFactory 需要加載類,也就需要類加載器,
// 這裡設定為加載目前 ApplicationContext 類的類加載器
beanFactory.setBeanClassLoader(getClassLoader());
// 設定 BeanExpressionResolver
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
// 添加一個 BeanPostProcessor,這個 processor 比較簡單:
// 實作了 Aware 接口的 beans 在初始化的時候,這個 processor 負責回調,
// 這個我們很常用,如我們會為了擷取 ApplicationContext 而 implement ApplicationContextAware
// 注意:它不僅僅回調 ApplicationContextAware,
// 還會負責回調 EnvironmentAware、ResourceLoaderAware 等,看下源碼就清楚了
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);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
/**
* 下面幾行就是為特殊的幾個 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);
// Register early post-processor for detecting inner beans as ApplicationListeners.
// 這個 BeanPostProcessor 也很簡單,在 bean 執行個體化後,如果是 ApplicationListener 的子類,
// 那麼将其添加到 listener 清單中,可以了解成:注冊 事件監聽器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
// 這裡涉及到特殊的 bean,名為:loadTimeWeaver,這不是我們的重點,忽略它
// tips: ltw 是 AspectJ 的概念,指的是在運作期進行織入,這個和 Spring AOP 不一樣,
// 感興趣的讀者請參考我寫的關于 AspectJ 的另一篇文章 https://www.javadoop.com/post/aspectj
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,
* 我們也可以選擇覆寫
*/
// Register default environment beans.
// 如果沒有定義 "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());
}
}
接下來我們開始進入到finishBeanFactoryInitialization這個方法,關于前面的幾個方法這邊再貼一下
// 這裡是提供給子類的擴充點,到這裡的時候,所有的 Bean 都加載、注冊完成了,但是都還沒有初始化
// 具體的子類可以在這步的時候添加一些特殊的 BeanFactoryPostProcessor 的實作類或做點什麼事
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 調用 BeanFactoryPostProcessor 各個實作類的 postProcessBeanFactory(factory) 方法
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注冊 BeanPostProcessor 的實作類,注意看和 BeanFactoryPostProcessor 的差別
// 此接口兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 兩個方法分别在 Bean 初始化之前和初始化之後得到執行。注意,到這裡 Bean 還沒初始化
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 初始化目前 ApplicationContext 的 MessageSource,國際化這裡就不展開說了,不然沒完沒了了
initMessageSource();
// Initialize event multicaster for this context.
// 初始化目前 ApplicationContext 的事件廣播器,這裡也不展開了
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 從方法名就可以知道,典型的模闆方法(鈎子方法),
// 具體的子類可以在這裡初始化一些特殊的 Bean(在初始化 singleton beans 之前)
onRefresh();
// Check for listener beans and register them.
// 注冊事件監聽器,監聽器需要實作 ApplicationListener 接口。這也不是我們的重點,直接過
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 初始化所有的 singleton beans
//(lazy-init 的除外)
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 最後,廣播事件,ApplicationContext 初始化完成
finishRefresh();
進入到本次IOC源碼的高潮部分了,請大家系好安全帶,即将發車…
執行個體化Bean
進入AbstractApplicationContext的finishBeanFactoryInitialization方法
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
// 首先,初始化名字為 conversionService 的 Bean。
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(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
// 這是 AspectJ 相關的内容,放心跳過吧
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);
// Allow for caching all bean definition metadata, not expecting further changes.
// 到這一步的時候,Spring 已經開始預初始化 singleton beans 了,
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
// 看這裡 開始初始化
beanFactory.preInstantiateSingletons();
}
進入preInstantiateSingletons方法,拿到剛剛beanFactory注冊BeanDefinition的名字集合,周遊,可能存在繼承關系,如果有則合并,然後判斷bean是否是抽象的單例的,懶加載的,滿足要求然後再判斷該bean是否是個FactoryBean,isFactoryBean方法主要還是通過instanceof來判斷的,前面那道面試題我們已經講了FactoryBean和普通Bean的差別,取得話就在于beanName前面有無"&"
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isDebugEnabled()) {
logger.debug("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
// this.beanDefinitionNames 儲存了所有的 beanNames
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
// 下面這個循環,觸發所有的非懶加載的 singleton beans 的初始化操作
for (String beanName : beanNames) {
// 合并父 Bean 中的配置,注意 <bean id="" class="" parent="" /> 中的 parent,用的不多吧,
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 非抽象、非懶加載的 singletons。如果配置了 'abstract = true',那是不需要初始化的
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
// 處理 FactoryBean
// FactoryBean 的話,在 beanName 前面加上 ‘&’ 符号。再調用 getBean,getBean 方法别急
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
// 判斷目前 FactoryBean 是否是 SmartFactoryBean 的實作,此處忽略,直接跳過
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
} else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
} else {
// 對于普通的 Bean,隻要調用 getBean(beanName) 這個方法就可以進行初始化了
//看這裡!!!!!!!!
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
// 到這裡說明所有的非懶加載的 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((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
} else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
AbstractBeanFactory.java
來到了getBean方法
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
doGetBean 注意 有2個getSingleton,3個getObjectForBeanInstance,這塊一定要逐個分析一下
//告訴編譯器忽略 unchecked 警告資訊,如使用List,ArrayList等未進行參數化産生的警告資訊。
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//1.轉換對應的beanName
// 擷取一個 “正統的” beanName,處理兩種情況,一個是前面說的 FactoryBean(前面帶 ‘&’),
// 一個是别名問題,因為這個方法是 getBean,擷取 Bean 用的,你要是傳一個别名進來,是完全可以的
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//2.直接嘗試從緩存擷取或者 singleton Factories 巾的 Object Factory 獲垠
// 這裡說下 args 呗,雖然看上去一點不重要。前面我們一路進來的時候都是 getBean(beanName),
// 是以 args 傳參其實是 null 的,但是如果 args 不為空的時候,那麼意味着調用方不是希望擷取 Bean,而是建立 Bean
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
} else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//3.如果從緩存中得到了bean的原始狀态,則對bean進行執行個體化
// 下面這個方法:如果是普通 Bean 的話,直接傳回 sharedInstance,
// 如果是 FactoryBean 的話,傳回它建立的那個執行個體對象
// (FactoryBean 知識,讀者若不清楚請移步附錄)
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
/**
* 隻有在單例的情況才會嘗試解決循環依賴,原型模式情況下,如果存在
* A 中有B的屬性,那麼當依賴注入的時候,就會産生當且還未建立完的時候因為
* 對于B 創邊再次傳回建立A ,造成循環依賴, 也就是下面的情況
*/
//4.原型模式的依賴檢查
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
//檢查一下這個BeanDefinition 在容器中是否存在
BeanFactory parentBeanFactory = getParentBeanFactory();
//如果beanDefinitionMap中也就是在所有已經加載的類中不包括beanName則嘗試從parentBeanFactory中檢測
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
//遞歸到beanFactory中尋找
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
} else if (args != null) {
// Delegation to parent with explicit args.
//委派父級容器根據指定名稱和顯式的參數查找
return (T) parentBeanFactory.getBean(nameToLookup, args);
} else {
// No args -> delegate to standard getBean method.
//委派父級容器根據指定名稱和類型查找
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
//如果不是僅僅做類型檢查則是建立bean,這裡要進行記錄
if (!typeCheckOnly) {
// typeCheckOnly 為 false,将目前 beanName 放入一個 alreadyCreated 的 Set 集合中。向容器标記指定的Bean已經被建立
markBeanAsCreated(beanName);
}
/*
* 稍稍總結一下:
* 到這裡的話,要準備建立 Bean 了,對于 singleton 的 Bean 來說,容器中還沒建立過此 Bean;
* 對于 prototype 的 Bean 來說,本來就是要建立一個新的 Bean。
*/
try {
//将存儲XML配置檔案的GernericBeanDefinition轉換為RootBeanDefinition,如果指定BeanName是子Bean的話同時會合并父類的相關屬性
//主要解決Bean繼承時子類合并父類公共屬性問題
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// 先初始化依賴的所有 Bean,這個很好了解。
// 注意,這裡的依賴指的是 depends-on 中定義的依賴
String[] dependsOn = mbd.getDependsOn();
//若存在依賴則需要遞歸執行個體化依賴的bean
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);
try {
//遞歸調用getBean()方法,先初始化被依賴項
getBean(dep);
} catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
// 如果是 singleton scope 的,建立 singleton 的執行個體
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
//執行建立 Bean , 詳解後面再說
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} 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);
} else {
//如果不是 singleton 和 Prototype 的話,需要委托給相應的實作類來處理
//指定的scope建立bean
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, () -> {
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;
}
}
// Check if required type matches the type of the actual bean instance.
// 最後,檢查一下類型對不對,不對的話就抛異常,對的話就傳回了
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
} 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;
}
第一個getSingleton
然後到getSingleton方法,注意allowEarlyReference為true表示Spring預設是支援循環依賴的,這段邏輯到第一個判斷就直接傳回了,原因在于isSingletonCurrentlyInCreation方法,點進去就是判斷這個beanName是否在這個Set中,不滿足直接傳回了Null
@Override
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
//然後到getSingleton方法,注意allowEarlyReference為true表示Spring預設是支援循環依賴的
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 第一次進來this.singletonObjects.get(beanName)傳回的肯定是null。然後isSingletonCurrentlyInCreation決定了能否進入二級緩存中擷取資料。
synchronized (this.singletonObjects) {
//從二級緩存擷取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//調用預先設定的getObject()方法
singletonObject = singletonFactory.getObject();
//記錄在緩存中,earlySingletonObjects和singletonFactories互斥
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
然後因為sharedInstance為空是以if不滿足走else,然後到了這一步,對原型的檢查
//4.原型模式的依賴檢查
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//如何判斷的,這裡涉及到一個ThreadLocal的概念,目前為空,
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null &&
(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}
然後就是一系列判斷,拿到我們前面注冊到bean工廠的BeanDefinition對象,也就是這裡的RootBeanDefinition,判斷他是單例的還是多例的還是其他的,然後走各自對應的處理邏輯,目前我們的beanName為messageService,預設單例,是以我們又到了看第二個getSingleton方法。
對于下面這段代碼,有個lambda表達式,也許有的老鐵就慌了,莫慌莫慌。調試一下…
// 如果是 singleton scope 的,建立 singleton 的執行個體
if (mbd.isSingleton()) {
//看這裡
sharedInstance = getSingleton(beanName, () -> {
try {
//執行建立 Bean , 詳解後面再說
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) { ...}
斷點調試首先進來getSingleton方法,仔細看圖類名+$lambda,這是什麼鬼????
然後我們看下ObjectFactory,代碼如下:
@FunctionalInterface
public interface ObjectFactory<T> {
/**
* Return an instance (possibly shared or independent)
* of the object managed by this factory.
* @return the resulting instance
* @throws BeansException in case of creation errors
*/
//傳回一個由此工廠管理的執行個體,
T getObject() throws BeansException;
}
然後這個lambda表達式是在調用getObject()方法的時候觸發的,小夥伴們可以自己斷點試試,這也算一個亮眼的操作了…繼續講解getSingleton方法
前面我們在if(isSingletonCurrentlyInCreation)有個判斷,如果成立則會抛出循環依賴的異常資訊,
到這個getSingleton方法裡的beforeSingletonCreation方法才是往singletonsCurrentlyInCreation添加目前的beanName。
然後就是調用singletonFactory.getObject();也就是AbstractBeanFactory的getSingleton的lambda,這塊一定要注意。
到了finally的afterSingletonCreation方法,就把singletonsCurrentlyInCreation的beanName給拿掉
如果lambda執行沒問題newSingleton指派為true,然後執行addSingleton方法。
到這裡,單例bean的外部邏輯我們已經锊清楚了。
下面是getSingleton方法和裡面幾個重要方法的代碼。
//因為在建立單例bean的時候會存在依賴注入的情況,而在建立依賴的時候為了避免循環依賴,
// Spring建立bean的原則是不等bean建立完成就會将建立bean的ObjectFactory提早曝光加入到緩存中,一旦
//下一個bean建立時需要依賴上個bean,則直接使用ObjectFactory.
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
//斷言beanName肯定不為空
Assert.notNull(beanName, "Bean name must not be null");
//同步全局變量,開始建立單例
synchronized (this.singletonObjects) {
//檢視單例是否已經被加載,凡是加載過的單例,都會存在Map<String, Object> singletonObjects裡面
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//this.singletonsCurrentlyInDestruction是個boolean,記錄的是目前這個單例是否正在被銷毀,
//如果是true,代表單例已經執行了自身的destroy銷毀方法,或者有異常的時候執行了destroySingleton方法等情況
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
//從一級緩存中取肯定為NULL,這裡往singletonsCurrentlyInCreation添加beanName
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
//如果此時suppressedExceptions為空,就new LinkedHashSet<>()來儲存接下來可能發生的異常
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//到這裡就會調用外面的lambda表達式
singletonObject = singletonFactory.getObject();
newSingleton = true;
} catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
//如果沒有建立報錯
if (singletonObject == null) {
throw ex;
}
} catch (BeanCreationException ex) {
//把出現過的異常加進去
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
} finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
//後處理,主要是把剛剛在beforeSingletonCreation方法裡面加載的bean狀态删除
afterSingletonCreation(beanName);
}
if (newSingleton) {
//把結果存在緩存中,并删除一些中間狀态
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
beforeSingletonCreation方法
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
然後finally的afterSingletonCreation方法
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
addSingleton方法
if (newSingleton) {
//把結果存在緩存中,并删除一些中間狀态
addSingleton(beanName, singletonObject);
}
建立Bean
也就是執行我們的lambda内容,IOC核心部分要來了
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
//要注意,在我們的初始化階段,args 是 null。
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
// 確定 BeanDefinition 中的 Class 被加載
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
// 準備方法覆寫,這裡又涉及到一個概念: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 {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 讓 InstantiationAwareBeanPostProcessor 在這一步有機會傳回代理,
// 在 《Spring AOP 源碼分析》那篇文章中有解釋,這裡先跳過
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);
}
try {
// 看這裡建立 bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
} catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
進入doCreateBean方法,1,2,3為其中的重點
//标記1,2,3是doCreateBean方法中3個比較重要的點
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 1.說明不是 FactoryBean,這裡執行個體化 Bean,這裡非常關鍵,細節之後再說
//根據指定Bean使用對應的政策建立Bean執行個體:如工廠方法,構造函數自動注入,簡單初始化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 這個就是 Bean 裡面的 我們定義的類 的執行個體,很多地方我直接描述成 "bean 執行個體"
final Object bean = instanceWrapper.getWrappedInstance();
// 類型
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
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");
}
//添加到三級緩存中
//對bean再一次依賴引用。主要應用于SmartInstantiationAwareBeanPostProcessor
//其中我們熟知的AOP的advice就是在這裡動态織入到bean中...若沒有則直接傳回bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 2.這一步也是非常關鍵的,這一步負責屬性裝配,因為前面的執行個體隻是執行個體化了,并沒有設值,這裡就是設值
populateBean(beanName, mbd, instanceWrapper);
// 還記得 init-method 嗎?還有 InitializingBean 接口?還有 BeanPostProcessor 接口?
// 3.這裡就是處理 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);
//如果是A和B存在循環依賴關系,在B的生命周期調用完了後置處理器之後到這,因傳入false,導緻為空,為什麼要傳入false,是因為A此時已經完了後置處理器,但A這個Bean
//其實沒有建立完,如果還想生成代理類,是有問題的,這也就是為什麼spring二級緩存不用,選擇三級緩存的原因
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
} else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(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;
}
推斷構造方法
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
// 確定已經加載了此 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());
}
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
//如果工廠方法不為空則使用工廠方法初始化政策,其實也對是對應xml的<bean factory-method>标簽
if (mbd.getFactoryMethodName() != null) {
// 采用工廠方法執行個體化,不熟悉這個概念的讀者請看附錄,注意,不是 FactoryBean
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
// 如果不是第一次建立,比如第二次建立 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);
}
}
// Candidate constructors for autowiring?
// 判斷是否采用有參構造函數
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 構造函數依賴注入
return autowireConstructor(beanName, mbd, ctors, args);
}
// No special handling: simply use no-arg constructor.
// 調用無參構造函數
return instantiateBean(beanName, mbd);
}
本次我們調用的是無參構造方法,是以進入到instantiateBean,可以看到Spring将執行個體化的bean封裝成了一個BeanWrapper的包裝類
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
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);
}
}
進入到Bean初始化政策的instantiate方法,大體邏輯我們分析一下
1.判斷bd存不存在方法覆寫,預設沒有,是以進if,他先回去嘗試一下能不能拿到我們要用的構造,也就是定義的constructorToUse,正常情況下沒配置都是拿不到,是以為NULL,再進去,通過bd拿到我們的Class,看到這裡,是不是就是我們java的反射知識了,繼續看,他會判斷這個class是不是一個接口,如果是就是抛出RuntimeException類型異常。順便再提一點,我們工作中,關于service層,注意是service層的接口哈,為什麼接口不用加注解,而在結尾為Impl的實作類加了注解@Service的原因,是以看源碼對平常工作還是有一定幫助的。
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
// 如果不存在方法覆寫,那就使用 java 反射進行執行個體化,否則使用 CGLIB,這裡就是判斷采用什麼初始化bean的政策
// 方法覆寫 eg: lookup-method 和 replaced-method
if (!bd.hasMethodOverrides()) {
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(
(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
}
else {
//預設構造方法
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// 利用構造方法進行執行個體化
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
// 存在方法覆寫,利用 CGLIB 來完成執行個體化,需要依賴于 CGLIB 生成子類
// 因為如果不使用 CGLIB 的話,存在 override 的情況 JDK 并沒有提供相應的執行個體化支援
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
上面通過反射拿到我們的構造,接下來傳入到一個BeanUtils的工具類進行執行個體化
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
//主要判斷構造的修飾符,是不是能通路,如果是私有的,或者不能通路,那麼我們就需要進行暴力通路
//也就是加上這行代碼 ctor.setAccessible(true);
ReflectionUtils.makeAccessible(ctor);
//調用初始化政策,目前預設是newInstance來執行個體化的
return (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
}
catch (InstantiationException ex) {
throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
}
catch (InvocationTargetException ex) {
throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
}
}
這個時候我們控制台列印了一句話,通過這個列印我們能清楚的知道這個通過構造進行執行個體化的
提前暴露工廠
執行個體化Bean講完了,下面這段代碼很重要,設及到Spring比較難的知識點:循環依賴
下面這塊代碼是為了解決循環依賴的問題,earlySingletonExposure正常情況下都是true的,isSingletonCurrentlyInCreation(beanName),還記得前面一個方法叫beforeSingletonCreation這個麼,我們這裡還沒有到afterSingletonCreation方法呢,還在lambda表達式裡的getObject()方法執行個體化Bean呢,小夥伴們可千萬别懵了。
然後到addSingletonFactory方法,這裡又傳了一個lambda,道理跟咋們前面講的一樣,
//是否需要提前曝光,判斷條件為:單例&允許循環依賴&是否正在建立過程中
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");
}
//添加到三級緩存中
//對bean再一次依賴引用。主要應用于SmartInstantiationAwareBeanPostProcessor
//其中我們熟知的AOP的advice就是在這裡動态織入到bean中...若沒有則直接傳回bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
addSingletonFactory方法
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
//一級緩存不存在
if (!this.singletonObjects.containsKey(beanName)) {
//放入三級緩存中
this.singletonFactories.put(beanName, singletonFactory);
//移除二技緩存
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
Q:這裡設及到Spring三級緩存方面的問題,由于本篇文章篇幅确實過長了,是以後期考慮開一篇文章來重點講講循環依賴,以及Spring為什麼要使用三級緩存來解決該問題的?
繼續第二步,DI部分
依賴注入(DI)
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
} else {
// Skip property population phase for null instance.
//沒有需要填充的屬性
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
// 1.InstantiationAwareBeanPostProcessor 處理器的postProcessAfterInstantiation函數的應用,此函數可以控制程式是否繼續進行屬性填充
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
// bean 執行個體的所有屬性都在這裡了
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 2. 根據注入類型,提取依賴的bean,并統一存入PropertyValues中
//沒配置的話預設為0 關于名字,類型,構造分别對應1,2,3
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
// 通過名字找到所有屬性值,如果是 bean 依賴,先初始化依賴的 bean。記錄依賴關系
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// 通過類型裝配。複雜一些
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
//後處理器已經初始化
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
//需要依賴檢查
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
// 3. 應用InstantiationAwareBeanPostProcessor處理器的postProcessPropertyValues方法,對屬性擷取完畢填充前對屬性再次處理
//典型應用是RequiredAnnotationBeanPostProcessor類中對屬性的驗證
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);
}
}
// 4. 将PropertyValues屬性填充到BeanWrapper中
if (pvs != null) {
// 設定 bean 執行個體的屬性值 看這裡
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
進入到第四步,前面主要是一些條件判斷,然後拿到屬性名字,原始值,這個原始值可能還不是我們要使用的,需要再處理一下,于是,下一步…
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs.isEmpty()) {
return;
}
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
//如果mpvs中的值已經被轉換為對應的類型那麼可以直接設值到bw中
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
bw.setPropertyValues(mpvs);
return;
} catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
//如果 pvs 并不是使用 MutablePropertyValues 封裝的類型,那麼直接使用原始的屬性擷取方法
original = mpvs.getPropertyValueList();
} else {
original = Arrays.asList(pvs.getPropertyValues());
}
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
//擷取對應·的解析器
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
//周遊屬性,将屬性轉換為對應類的對應屬性的類型
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
} else {
String propertyName = pv.getName();
//原始的屬性值,即轉換之前的屬性值
Object originalValue = pv.getValue();
//做一些類型的強制轉換
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
//轉換之後的屬性值
Object convertedValue = resolvedValue;
//屬性值是否可以轉換
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
} else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
} else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
try {
// AbstractPropertyAccessor
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
} catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
進入BeanDefinitionValueResolver的resolveValueIfNecessary方法
判斷value是不是運作時Bean的引用,顯然這裡是,進入第一個return方法
@Nullable
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
// We must check each value to see whether it requires a runtime reference
// to another bean to be resolved.
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
}
else if (value instanceof RuntimeBeanNameReference) {
String refName = ((RuntimeBeanNameReference) value).getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (!this.beanFactory.containsBean(refName)) {
throw new BeanDefinitionStoreException(
"Invalid bean name '" + refName + "' in bean reference for " + argName);
}
return refName;
}
else if (value instanceof BeanDefinitionHolder) {
// Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
}
else if (value instanceof BeanDefinition) {
// Resolve plain BeanDefinition, without contained name: use dummy name.
BeanDefinition bd = (BeanDefinition) value;
String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
ObjectUtils.getIdentityHexString(bd);
return resolveInnerBean(argName, innerBeanName, bd);
}
else if (value instanceof ManagedArray) {
// May need to resolve contained runtime references.
ManagedArray array = (ManagedArray) value;
Class<?> elementType = array.resolvedElementType;
if (elementType == null) {
String elementTypeName = array.getElementTypeName();
if (StringUtils.hasText(elementTypeName)) {
try {
elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());
array.resolvedElementType = elementType;
}
catch (Throwable ex) {
// Improve the message by showing the context.
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Error resolving array type for " + argName, ex);
}
}
else {
elementType = Object.class;
}
}
return resolveManagedArray(argName, (List<?>) value, elementType);
}
else if (value instanceof ManagedList) {
// May need to resolve contained runtime references.
return resolveManagedList(argName, (List<?>) value);
}
else if (value instanceof ManagedSet) {
// May need to resolve contained runtime references.
return resolveManagedSet(argName, (Set<?>) value);
}
else if (value instanceof ManagedMap) {
// May need to resolve contained runtime references.
return resolveManagedMap(argName, (Map<?, ?>) value);
}
else if (value instanceof ManagedProperties) {
Properties original = (Properties) value;
Properties copy = new Properties();
original.forEach((propKey, propValue) -> {
if (propKey instanceof TypedStringValue) {
propKey = evaluate((TypedStringValue) propKey);
}
if (propValue instanceof TypedStringValue) {
propValue = evaluate((TypedStringValue) propValue);
}
if (propKey == null || propValue == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Error converting Properties key/value pair for " + argName + ": resolved to null");
}
copy.put(propKey, propValue);
});
return copy;
}
else if (value instanceof TypedStringValue) {
// Convert value to target type here.
TypedStringValue typedStringValue = (TypedStringValue) value;
Object valueObject = evaluate(typedStringValue);
try {
Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
if (resolvedTargetType != null) {
return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
}
else {
return valueObject;
}
}
catch (Throwable ex) {
// Improve the message by showing the context.
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Error converting typed String value for " + argName, ex);
}
}
else if (value instanceof NullBean) {
return null;
}
else {
return evaluate(value);
}
}
看到這裡,不知道小夥伴是明白了還是懵了,哈哈,我們說說這斷代碼:拿到beanName,然後判斷,又是一個beanFactory,沒錯,這就是我們前面得到的DefaultListableBeanFactory,IOC的始祖
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
Object bean;
String refName = ref.getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (ref.isToParent()) {
if (this.beanFactory.getParentBeanFactory() == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Can't resolve reference to bean '" + refName +
"' in parent factory: no parent factory available");
}
bean = this.beanFactory.getParentBeanFactory().getBean(refName);
}
else {
//-----------------------------看這裡------------------------------------------
bean = this.beanFactory.getBean(refName);
this.beanFactory.registerDependentBean(refName, this.beanName);
}
if (bean instanceof NullBean) {
bean = null;
}
return bean;
}
catch (BeansException ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
}
}
進入getBean方法
又到了我們最初的messageService的起點了,不過這次是beanName為message的bean
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
這是我們開始的xml配置
<bean id="messageService" name="m1,m2,m3" scope="singleton" class="com.whp.service.impl.MessageServiceImpl">
<!--引入下面id為message的bean-->
<property name="message" ref="message"/>
</bean>
<bean id="message" class="com.whp.bean.Message"/>
然後重複messageService之後,我們拿到了beanName為message的bean,這時候需要給MessageServiceImpl這個類的屬性message指派了,還是我們前面的DI的過程,然後接下來就是指派了。
Bean執行個體化完成函數回調
前面2步我們已經把Bean執行個體化以及DI完成了,最後就是回調以及通知了,工作亦是如此…
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
//JDK的安全機制驗證權限
if (System.getSecurityManager() != null) {
//實作PrivilegedAction接口的匿名内部類
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
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;
}
部分Aware回調
進入invokeAwareMethods方法,這部分我們叫做部分Aware回調,這裡就三個,對于Aware接口的實作肯定有多個,是以這裡我們叫部分Aware接口回調
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
還記得嘛,我開始在MessageServiceImpl實作了BeanNameAware,然後setBeanName方法,就是為了這一步
然後到了BeanPostProcessor的前後通知
applyBeanPostProcessorsBeforeInitialization方法
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
applyBeanPostProcessorsAfterInitialization方法
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
對于BeanPostProcessor,是Spring提供給我們開發者的一個非常重要的拓展點,還有FactoryBean
,InitializingBean我們也可以利用它來初始化我們自定義的一些Bean,Aware接口我們也可以利用起來
第3步完成過後有個if (earlySingletonExposure) {…}這塊屬于循壞依賴東西,後期有時間會開篇文章重點講講。
這個時候我們的beanName為messageService的Bean執行個體化完成了,最後需要把它放入到Spring的一級緩存中,供開發者使用。
afterSingletonCreation(beanName)将singletonsCurrentlyInCreation的beanName移除
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
addSingleton方法
//一句話,Bean添加到一級緩存,移除二三級緩存。
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
//一級緩存添加
this.singletonObjects.put(beanName, singletonObject);
//移除三級,二級緩存
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
// registeredSingletons這個Set是記錄已經建立好的bean
this.registeredSingletons.add(beanName);
}
}
最後一個就是getObjectForBeanInstance方法了
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
//執行建立 Bean , 詳解後面再說
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
* 這個方法就三個判斷:
* 1、如果不是factoryBean 但是name開頭為&,那麼報錯
* 2、如果是FactoryBean,并且name開頭不為&,就取FactoryBean的getObject方法
* 3、如果是FactoryBean,并且name開頭為&,那麼傳回FactoryBean本身。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name)) {
//
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
//如果name開頭&,但又不是factoryBean就報錯
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
//如果不是FactoryBean,那麼就屬于正常的bean執行個體了,直接傳回
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
//加載FactoryBean
Object object = null;
if (mbd == null) {
//嘗試從緩存中擷取bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
//強轉為beanFactory。此時的beanInstance一定是FactoryBean類型的,因為如果不是,就會在上面的if中直接傳回了
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
//檢測這個bean是否已經被加載過
//containsBeanDefinition中會傳回beanDefinitionMap.containsKey(beanName)的值
if (mbd == null && containsBeanDefinition(beanName)) {
//進行父類和子類的合并,把存儲xml配置的GernericBeanDefinition轉換為RootBeanDefinition
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
//我的bean是FactoryBean,那麼就會通過FactoryBean的getObject方法
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
到這裡,可以說是Spring初始化完成了,我們可以通過一下進行調用使用了
本次的Spring IOC源碼解析已接近了尾聲,不知道有多少小夥伴堅持看完了,看完的可以在下方回複Spring IOC,也表示對部落客寫了這麼久的認可哈哈,确實有點辛苦,如果本篇文章有缺點,歡迎指教,需要源碼項目的也可以找我要,省的大家去下載下傳了,本次Spring IOC源碼解析到此結束。