面試官:講講Spring IOC!
來(lái)源:juejin.cn/post/7327447632111779891
推薦:https://t.zsxq.com/17Qr4cXwo
IOC(Inversion of Control),即控制反轉(zhuǎn),它是一種設(shè)計(jì)思想
- 控制(誰(shuí)控制誰(shuí))
之前通過(guò)new()進(jìn)行創(chuàng)建對(duì)象,主動(dòng)去創(chuàng)建依賴(lài)對(duì)象,而現(xiàn)在通過(guò)IOC容器負(fù)責(zé)實(shí)例化、配置和組裝 bean。
?在Spring IOC中,控制反轉(zhuǎn)指的是將對(duì)象的創(chuàng)建和管理交給Spring容器來(lái)完成,而不是由程序員手動(dòng)管理。因此,在Spring IOC中,Spring容器控制對(duì)象的創(chuàng)建和管理,而不是對(duì)象控制容器。因此,可以說(shuō)在Spring IOC中,Spring容器控制對(duì)象。
- 反轉(zhuǎn)(反轉(zhuǎn)什么)
之前對(duì)象主動(dòng)直接去獲取依賴(lài)對(duì)象,而現(xiàn)在通過(guò)Ioc容器查找及注入(DI) 依賴(lài)對(duì)象。
?在Spring IOC中,控制反轉(zhuǎn)(Inversion of Control,IoC)指的是將對(duì)象的創(chuàng)建和管理交給Spring容器來(lái)完成,而不是由應(yīng)用程序自己來(lái)創(chuàng)建和管理對(duì)象??刂品崔D(zhuǎn)反轉(zhuǎn)的是控制權(quán),即原本由應(yīng)用程序控制對(duì)象的創(chuàng)建和生命周期,變成了由Spring容器控制對(duì)象的創(chuàng)建和生命周期。這種反轉(zhuǎn)的控制權(quán)可以帶來(lái)更好的松耦合、更高的可維護(hù)性和可測(cè)試性。
- 依賴(lài)注入
DI(Dependency Injection),即依賴(lài)注入,是IOC具體的實(shí)現(xiàn),IOC容器動(dòng)態(tài)的將某個(gè)依賴(lài)注入到對(duì)象之中
Spring Bean 在Spring中,Spring IoC 容器管理的對(duì)象稱(chēng)為 bean。
Spring IOC
Spring提供了兩種容器:BeanFactory和ApplicationContext
BeanFactory 接口提供配置框架和基本功能,能夠管理任何類(lèi)型的對(duì)象。
ApplicationContext是BeanFactory的子接口
通過(guò)上圖我們可以看到ApplicationContext還繼承了其他接口,增加了消息資源處理(用于國(guó)際化)、事件發(fā)布、資源訪(fǎng)問(wèn)等功能。
初始化流程
通過(guò)前面的內(nèi)容,我們可以了解到Spring IOC 容器,主要負(fù)責(zé)管理 Bean 的實(shí)例化、配置和組裝,接下來(lái)我們看看Spring IOC的初始化過(guò)程(以xml配置為例)
<xml version="1.0" encoding="UTF-8">
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="clientMessageReq" class="com.tx.general.rtnp.ws.req.ClientMessageReq" scope="prototype">
</bean>
</beans>
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("clientMessageReq.xml");
ClientMessageReq clientMessageReq = context.getBean("clientMessageReq", ClientMessageReq.class);
clientMessageReq.setParams("text");
System.out.println(JSON.toJSONString(clientMessageReq));
}
通過(guò)new ClassPathXmlApplicationContext()方法創(chuàng)建了一個(gè)IOC容器,我們主要這個(gè)構(gòu)造方法開(kāi)始,分析一下IOC容器的初始化過(guò)程。
/**
* 構(gòu)造一個(gè)ClassPathXmlApplicationContext對(duì)象。
*
* @param configLocations 配置文件路徑數(shù)組
* @param refresh 是否刷新上下文
* @param parent 父上下文對(duì)象,可能為空
* @throws BeansException 如果在創(chuàng)建對(duì)象時(shí)發(fā)生錯(cuò)誤,拋出BeansException異常
*/
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
// 設(shè)置Bean資源加載器
super(parent);
// 設(shè)置Xml配置路徑
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
重點(diǎn)就是refresh()方法,它是IOC容器初始化的核心
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// ▲1.調(diào)用容器準(zhǔn)備刷新的方法,獲取容器的當(dāng)時(shí)時(shí)間,同時(shí)給容器設(shè)置同步標(biāo)識(shí)
prepareRefresh();
// ▲2.初始化BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// ▲3.準(zhǔn)備Bean工廠(chǎng)以在上下文中使用
prepareBeanFactory(beanFactory);
try {
// ▲4.為子類(lèi)設(shè)置BeanFactory的后置處理器
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// ▲5.調(diào)用實(shí)現(xiàn)了BeanFactoryPostProcessor的類(lèi)
invokeBeanFactoryPostProcessors(beanFactory);
// ▲6.注冊(cè)bean初始化時(shí)候的processor
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// ▲7.對(duì)上下文的消息源進(jìn)行初始化
initMessageSource();
// ▲8.初始化上下文的事件機(jī)制
initApplicationEventMulticaster();
// ▲9.初始化其他特殊的Bean
onRefresh();
// ▲10.注冊(cè)實(shí)現(xiàn)了ApplicationListener的listener
registerListeners();
// ▲11.初始化配置為lazy-init=false的bean
finishBeanFactoryInitialization(beanFactory);
// ▲12.觸發(fā)所有監(jiān)聽(tīng)ContextRefreshedEvent事件的listener
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
destroyBeans();
cancelRefresh(ex);
throw ex;
}
finally {
resetCommonCaches();
contextRefresh.end();
}
}
}
可以看到容器的創(chuàng)建和初始化就在obtainFreshBeanFactory()方法,重點(diǎn)來(lái)看一下
-
obtainFreshBeanFactory()初始化BeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
/**
* 刷新Bean工廠(chǎng) 委托模式
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果已經(jīng)有容器存在,則需要把已有的容器銷(xiāo)毀和關(guān)閉,以保證在refresh之后使用的是新建立起來(lái)的IoC容器
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 創(chuàng)建DefaultListableBeanFactory對(duì)象
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 設(shè)置序列化ID
beanFactory.setSerializationId(getId());
// 自定義Bean工廠(chǎng)
customizeBeanFactory(beanFactory);
// 加載定義的Bean
loadBeanDefinitions(beanFactory);
// 將beanFactory賦值給類(lèi)成員變量
this.beanFactory = beanFactory;
}
catch (IOException ex) {
// 解析bean定義源時(shí)發(fā)生I/O錯(cuò)誤拋出ApplicationContextException異常
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
定位Resource(bean的Xml)
-
AbstractXmlApplicationContext#loadBeanDefinitions()加載BeanDefinition
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 創(chuàng)建XmlBeanDefinitionReader讀取器
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
// 設(shè)置Spring資源加載器
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 讀取器讀取Bean定義的Xml資源文件時(shí),啟用Xml的校驗(yàn)機(jī)制
initBeanDefinitionReader(beanDefinitionReader);
// 通過(guò)beanDefinitionReader加載BeanDefinitions
loadBeanDefinitions(beanDefinitionReader);
}
-
AbstractXmlApplicationContext#loadBeanDefinitions()定位資源,以Resource的形式去加載資源
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 獲得Bean配置文件的資源位置
Resource[] configResources = getConfigResources();
if (configResources != null) {
// 讀取AbstractBeanDefinitionReader中定位的資源
reader.loadBeanDefinitions(configResources);
}
// 獲取ClassPathXmlApplicationContext構(gòu)造方法中setConfigLocations方法設(shè)置的資源
String[] configLocations = getConfigLocations();
if (configLocations != null) {
//通過(guò)AbstractBeanDefinitionReader#loadBeanDefinitions()方法,以Resource的形式去加載資源。
reader.loadBeanDefinitions(configLocations);
}
}
載入BeanDefinition
經(jīng)過(guò)上面的步驟我們定義的資源以及容器本身需要的資源全部加載到reader中,通過(guò)XmlBeanDefinitionReader#loadBeanDefinitions()方法會(huì)得到一個(gè)XML文件的InputStream,然后 將Bean定義資源轉(zhuǎn)換成Document對(duì)象。最后在registerBeanDefinitions()方法中完成對(duì)解析
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 創(chuàng)建DefaultBeanDefinitionDocumentReader對(duì)象
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
// 通過(guò)DefaultBeanDefinitionDocumentReader對(duì)象的registerBeanDefinitions()方法解析Document
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
而具體的解析過(guò)程由BeanDefinitionParserDelegate()來(lái)實(shí)現(xiàn)
protected void doRegisterBeanDefinitions(Element root) {
// ... 代碼部分省略
// 執(zhí)行XML預(yù)處理操作
preProcessXml(root);
// 解析Bean定義
parseBeanDefinitions(root, this.delegate);
// 執(zhí)行XML后處理操作
postProcessXml(root);
// ... 代碼部分省略
}
通過(guò)BeanDefinitionParserDelegate#parseBeanDefinitionElement()方法,得到結(jié)果BeanDefinitionHolder(BeanDefinitionHolder是BeanDefinition的封裝類(lèi),封裝了BeanDefinition,Bean的名字、別名)
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 對(duì)給定的<bean>標(biāo)簽進(jìn)行解析,得到BeanDefinitionHolder對(duì)象
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 向IOC容器注冊(cè)解析到BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 在BeanDefinition像IOC容器注冊(cè)完以后,發(fā)送事件消息
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
BeanDefiniton注冊(cè)
最終Xml配置被解析成了BeanDefinitionHolder類(lèi),通過(guò)DefaultListableBeanFactory#registerBeanDefinition()方法,將BeanDefinition注冊(cè)到beanDefinitionsMap中
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
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;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
至此,IOC容器完成了初始化,其內(nèi)部使用ConcurrentHashMap(Spring IOC容器本質(zhì))保存了BeanDefinition信息
總結(jié)
Spring IOC初始化可以分為三個(gè)步驟:
- 通過(guò)
ResourceLoader來(lái)完成資源文件位置的定位(Resource) - 將Resource定位好的資源載入到BeanDefinition(通過(guò) BeanDefinitionReader來(lái)完成定義信息的解析)
- 將BeanDefiniton注冊(cè)到容器中(通過(guò)BeanDefinitionRegistry接口,將BeanDefinition保存到ConcurrentHashMap中)
Spring IOC容器管理了定義的各種Bean對(duì)象及其相互的關(guān)系,降低了耦合度
