IoC:依賴倒置原理,個(gè)人覺(jué)得其核心思想就是減少代碼的耦合度,很多復(fù)雜的應(yīng)用都是依靠多個(gè)類之間的合作來(lái)完成的迅细。如果類本身和合作類的引用需要靠自身來(lái)實(shí)現(xiàn),那么代碼的耦合度會(huì)很高淘邻。那么在Spring中茵典,IoC是實(shí)現(xiàn)依賴反轉(zhuǎn)的載體;Spring在對(duì)象初始化的時(shí)候?qū)?shù)據(jù)注入到對(duì)象中,或者將對(duì)象的引用注入到數(shù)據(jù)域中的方式來(lái)注入對(duì)方法調(diào)用的依賴。
Spring IoC提供了一個(gè)基本的javaBean容器宾舅,通過(guò)IoC模式管理依賴關(guān)系,并通過(guò)依賴注入和AOP切面增強(qiáng)了為javeBean這樣的POJO對(duì)象賦予事務(wù)管理统阿,生命周期管理等基本功能彩倚。而Bean都在Spring容器里,Spring容器負(fù)責(zé)它們的創(chuàng)建扶平,裝配帆离,管理它們整個(gè)的生命周期结澄「绻龋《深入理解Spring技術(shù)內(nèi)幕》
SpringIoC容器系列(BeanFactory跟ApplicationContext)
BeanFactory跟ApplicationContext都屬于Spring容器们妥。
BeanFactory:定義了最基本的容器設(shè)計(jì)規(guī)范,如getBean(),containBean(),getType()等基本的方法勉吻。
ApplicationContext:由圖可知ApplicationContext應(yīng)用的上下文都是基于ConfigurableApplicationContext跟WebApplicationContext的實(shí)現(xiàn)监婶。ApplicationContext繼承了BeanFactory的接口同時(shí)又繼承MessageSource(支持不同的信息源),ResourceLoader(訪問(wèn)資源),ApplicationEventPublisher(支持應(yīng)用事件)。
IoC接口設(shè)計(jì)圖圖片引用《深入理解spring技術(shù)內(nèi)幕》
容器是如何初始化的齿桃?
容器的初始化是通過(guò)refresh()方法來(lái)完成的惑惶,總共包括三個(gè)步驟:
- 定位:通過(guò)Resource定位BeanDefinition,BeanDefinition抽象了對(duì)bean的定義源譬,比如bean的信息集惋,依賴關(guān)系等。這個(gè)過(guò)程可以想象成尋找bean的過(guò)程踩娘。
下面我們通過(guò)代碼來(lái)簡(jiǎn)要分析下容器是如何初始化的
public class ApplicationContextInit {
public static void main(String[] args) {
FileSystemXmlApplicationContext fileSystemXmlApplicationContext = new FileSystemXmlApplicationContext("bean.xml");
}
}
FileSystemXmlApplicationContext是通過(guò)文件來(lái)載入Resource的,運(yùn)行上述代碼
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
//...省略部分源碼
//通過(guò)文件的位置來(lái)定位到beanDefinition
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
//通過(guò)refresh()方法來(lái)完成BeanDefinition信息讀取和載入
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
}
refresh()來(lái)啟動(dòng)IoC容器的初始化
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 容器初始化的一些準(zhǔn)備工作.
prepareRefresh();
// 告知子類要初始化BeanFactory刮刑,BeanDefinition信息的讀取是在子類的
// refreshBeanFactory()方法里完成的
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 準(zhǔn)備bean工廠以在此上下文中使用。
prepareBeanFactory(beanFactory);
try {
// 設(shè)置beanFactory的后置處理
postProcessBeanFactory(beanFactory);
// 調(diào)用beanFactory的后置處理
invokeBeanFactoryPostProcessors(beanFactory);
// 注冊(cè)beanFactory的后置處理
registerBeanPostProcessors(beanFactory);
// 初始化上下文的消息
initMessageSource();
// 初始化上下的事件
initApplicationEventMulticaster();
// 初始化一些特殊的bean
onRefresh();
// 檢查一些監(jiān)聽(tīng)的bean并注冊(cè)到容器中
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// 發(fā)布容器事件养渴,結(jié)束Refresh過(guò)程
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 銷毀已經(jīng)生成的bean
destroyBeans();
// 重置激活狀態(tài).
cancelRefresh(ex);
throw ex;
}
finally {
resetCommonCaches();
}
}
}
beanDefinition信息是通過(guò)ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()里的refreshBeanFactory()來(lái)完成的雷绢,而這個(gè)方法則是在AbstractRefreshableApplicationContext實(shí)現(xiàn)的。
@Override
protected final void refreshBeanFactory() throws BeansException {
//如果容器已經(jīng)存在,那么銷毀并且關(guān)閉該容器,保證每次產(chǎn)生的都是新的容器
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//創(chuàng)建基礎(chǔ)的BeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
//載入BeanDefinition的信息
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
DefaultListableBeanFactory其實(shí)是一個(gè)最基礎(chǔ)的容器,很多容器都是基于這個(gè)容器來(lái)作擴(kuò)展,那么這個(gè)容器里自然也包含了很多基礎(chǔ)重要的功能理卑,那么通過(guò)loadBeanDefinitions()來(lái)完成BeanDefinition信息的載入的,這里是委托子類來(lái)完成這個(gè)工作的翘紊。
//抽象類,具體的resource定位跟BeanDefinition的載入是委托子類來(lái)完成的
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws BeansException, IOException;
//這是loadBeanDefinitions的具體實(shí)現(xiàn)
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//創(chuàng)建XmlBeanDefinitionReader,并通過(guò)回調(diào)設(shè)置到beanFactory里面去
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 使用此上下文的資源加載環(huán)境配置beanFactory
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//啟動(dòng)bean信息的載入過(guò)程
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
//這里應(yīng)該算是容器初始化第一步resource定位,首先得到beanDefinition信息的Resource定位
//然后通過(guò)XmlBeanDefinitionReader來(lái)讀取
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//通過(guò)resource來(lái)定位
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
//通過(guò)文件路徑來(lái)定位
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//獲取ResourceLoader
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
//判斷ResourceLoader的路徑模式,
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
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;
}
}
getResourceByPath被子類FileSystemXmlApplicationContext實(shí)現(xiàn),最終返回FileSystemResource對(duì)象藐唠,通過(guò)這個(gè)對(duì)象,Spring進(jìn)行相關(guān)的I/O操作帆疟,完成beanDefinition的定位。
總結(jié)下Resource定位BeanDefinition的流程
1.FileSystemXmlApplicationContext里調(diào)用refresh()方法初始化IoC容器宇立。
2.在refresh()方法里調(diào)用obtainFreshBeanFactory()里面的refreshBeanFactory()來(lái)完成BeanDefinition的定位,而refreshBeanFactory()是由子類AbstractRefreshableApplicationContext來(lái)實(shí)現(xiàn)的踪宠。
3.refreshBeanFactory()中是通過(guò)loadBeanDefinitions()來(lái)完成BeanDefinition的定位,而loadBeanDefinitions()是一個(gè)抽象的方法,具體由AbstractBeanDefinitionReader里的loadBeanDefinitions()來(lái)實(shí)現(xiàn)。
4.在loadBeanDefinitions()通過(guò)DefaultResourceLoader的getResource方法里返回resource對(duì)象妈嘹。
- 載入:BeanDefinition的信息已經(jīng)定位到了柳琢,第二步就是把定義的BeanDefinition在Ioc容器中轉(zhuǎn)化成一個(gè)Spring內(nèi)部標(biāo)示的數(shù)據(jù)結(jié)構(gòu)的過(guò)程。
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (this.logger.isInfoEnabled()) {
this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!((Set)currentResources).add(encodedResource)) {
throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
} else {
int var5;
try {
//準(zhǔn)備讀取xml文件
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//具體的讀取過(guò)程是在doLoadBeanDefinitions()這個(gè)方法里完成
var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
} finally {
inputStream.close();
}
} catch (IOException var15) {
throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
} finally {
((Set)currentResources).remove(encodedResource);
if (((Set)currentResources).isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
return var5;
}
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
int validationMode = getValidationModeForResource(resource);
//這里通過(guò)documentLoader來(lái)讀取xml最終獲取Document對(duì)象
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
//這里通過(guò)registerBeanDefinitions()方法完成BeanDefinition的解析
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//獲取BeanDefinitionDocumentReader對(duì)xml對(duì)BeanDefinition進(jìn)行解析
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(this.getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount();
//具體解析是在registerBeanDefinitions()這個(gè)方法里進(jìn)行對(duì)
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
//注冊(cè)BeanDefinition
doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
//委托父類解析
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//對(duì)xml里根節(jié)點(diǎn)下所有對(duì)子節(jié)點(diǎn)進(jìn)行解析
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);
}
}
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
//如果為bean的話 解析BeanDefinition
processBeanDefinition(ele, delegate);
}//beans
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 遞歸解析
doRegisterBeanDefinitions(ele);
}
}
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
}
首先通過(guò)調(diào)用XML的解析器得到Document對(duì)象,此時(shí)這些Document對(duì)象并沒(méi)有按照Spring的Bean規(guī)則進(jìn)行解析柬脸,在完成通用的XML解析以后他去,才是按照Spring Bean規(guī)則進(jìn)行解析的地方,這個(gè)過(guò)程在documentReader中實(shí)現(xiàn)倒堕,使用的documentReader是默認(rèn)設(shè)置好的DefaultBeanDefinitionDocumentReader灾测。
- 注冊(cè):將抽象好的BeanDefinition統(tǒng)一注冊(cè)到IoC容器中,IoC容器是通過(guò)hashMap來(lái)維護(hù)BeanDefinition信息的涩馆,key為beanName行施,value為BeanDefinition。
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
BeanDefinition的注冊(cè)是發(fā)生在BeanDefinition信息載入之后的魂那,
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 oldBeanDefinition;
//如果beanName已經(jīng)在map里存在,那么拋出異常
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// 使用synchronize為了保證數(shù)據(jù)一致性蛾号,key為bean的名字,key為beanDefinition信息
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
這樣就完成了beanDefinition在IoC容器中的注冊(cè);
下一篇會(huì)大概分析下依賴注入的過(guò)程, 第一次寫這種源碼分析的文章,思路還是比較混亂,還請(qǐng)大家多多指教,共同進(jìn)步!