之前就IOC的原理及使用有了一定的認(rèn)識,作為Spring核心特性之一,IOC是很有必要重點(diǎn)掌握的历筝。這次沉淀將會開啟IOC源碼閱讀的序幕。
對于源碼的理解廊谓,以注釋添加在對應(yīng)代碼塊上方
一梳猪、IOC概念回顧
IOC(Inversion of Control),即“控制反轉(zhuǎn)”蒸痹,IOC意味著將你設(shè)計好的對象交給容器控制春弥,而不是傳統(tǒng)的在你的對象內(nèi)部直接控制呛哟。那么到底“誰控制誰,控制什么匿沛,為什么是反轉(zhuǎn)扫责,哪些方面反轉(zhuǎn)了”:
●誰控制誰,控制什么:IOC出現(xiàn)之前我們程序員會直接在對象內(nèi)部通過new創(chuàng)建對象逃呼,是程序主動去創(chuàng)建依賴對象公给;而IOC是通過一個容器來創(chuàng)建,即由IOC容器來控制對象的創(chuàng)建蜘渣;誰控制誰淌铐?是IOC 容器控制對象;控制什么蔫缸?那就是主要控制了外部資源獲韧茸肌(不僅僅是對象,還包括文件等)拾碌。
●為何是反轉(zhuǎn)吐葱,哪些方面反轉(zhuǎn)了:傳統(tǒng)應(yīng)用程序是由我們程序員在一個對象中主動控制從而直接獲取依賴對象,也就是正轉(zhuǎn)校翔;而反轉(zhuǎn)則是由容器來幫忙創(chuàng)建及注入依賴對象弟跑;為什么是反轉(zhuǎn)?因?yàn)橛扇萜鲙臀覀儾檎壹白⑷胍蕾噷ο蠓乐ⅲ瑢τ趯ο笫潜粍拥慕邮芰艘蕾噷ο竺霞越凶龇崔D(zhuǎn);哪些方面反轉(zhuǎn)了蔫敲?依賴對象在獲取時被反轉(zhuǎn)了饲嗽。
二、源碼剖析
1. SpringDemo
以我spring入門的demo為例:
public static void main( String[] args ){
String xmlPath="src//main/resources/spring.xml";
ApplicationContext context = new FileSystemXmlApplicationContext(xmlPath);
((Car)context.getBean("car")).whistle();
}
注:該代碼位置必須在spring-context模塊下
類ApplicatContext的構(gòu)造方法中包含了容器的啟動奈嘿,IOC的初始化貌虾。
spring為ApplicationContext提供的3種實(shí)現(xiàn)分別為:
- ClassPathXmlApplicationContext 在class路徑下加載 classpath:***.xml。
- FileSystemXmlApplicationContext 可以指定磁盤任意資源路徑裙犹。
- XmlWebApplicationContext 是專為Web工程定制的尽狠。
而ApplicatContext 的標(biāo)準(zhǔn)實(shí)現(xiàn)是 FileSystemXmlApplicationContext。
打好斷點(diǎn)叶圃,開始刨根問底源碼的剖析袄膏。
2. 源碼剖析入口FileSystemXmlApplicationContext
/**
* Create a new FileSystemXmlApplicationContext, loading the definitions
* from the given XML files and automatically refreshing the context.
* @param configLocations array of file paths
* @throws BeansException if context creation failed
*/public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, null);
}
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
// 調(diào)用父類容器的構(gòu)造方法(super(parent)方法)為容器設(shè)置好Bean資源加載器。
super(parent);
//設(shè)置Bean定義資源文件的定位路徑盗似。
setConfigLocations(configLocations);
if (refresh) {
//刷新容器哩陕。
refresh();
}
}
由以上代碼我們可以感覺到,refresh 方法才是初始化容器的重要方法:
Spring IOC容器對Bean定義資源的載入是從refresh()函數(shù)開始的其作用是:在創(chuàng)建IOC容器前赫舒,如果容器已經(jīng)存在悍及,則需銷毀和關(guān)閉已有的容器,為的是保證在refresh之后使用的是新建的IOC容器接癌。我們進(jìn)入該方法看看:該方法是 FileSystemXmlApplicationContext 的父類 AbstractApplicationContext 中的方法心赶。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//調(diào)用容器準(zhǔn)備刷新的方法
prepareRefresh();
/**調(diào)用子類中refreshBeanFactory()方法
*啟動Bean定義資源文件的過程
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//為BeanFactory配置容器特性
prepareBeanFactory(beanFactory);
try {
//為容器的子類指定事件處理器
postProcessBeanFactory(beanFactory);
//調(diào)用所有注冊的BeanFactoryPostProcessor的Bean
invokeBeanFactoryPostProcessors(beanFactory);
/**為BeanFactory注冊BeanPost事件處理器.
*BeanPostProcessor是Bean后置處理器,用于監(jiān)聽容器觸發(fā)的事件
*/
registerBeanPostProcessors(beanFactory);
//初始化信息源
initMessageSource();
//初始化容器事件傳播器.
initApplicationEventMulticaster();
//調(diào)用子類Bean初始化方法
onRefresh();
//為事件傳播器注冊事件監(jiān)聽器.
registerListeners();
finishBeanFactoryInitialization(beanFactory);
/**初始化容器的生命周期事件處理器
*并發(fā)布容器的生命周期事件
*/
finishRefresh();
}
catch (BeansException ex) {
destroyBeans();
cancelRefresh(ex);
throw ex;
}
}
}
refresh()方法的步驟:
- 構(gòu)建BeanFactory缺猛,從而產(chǎn)生所需的 Bean缨叫。
- 注冊事件處理器。
- 常見Bean實(shí)例對象初始化荔燎。
- 觸發(fā)被監(jiān)聽的事件的監(jiān)聽器耻姥。
子類容器的refreshBeanFactory()方法執(zhí)行Spring IOC容器載入Bean定義資源文件的整個過程,所以整個refresh()中代碼:
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
之后的代碼都是注冊容器的信息源和生命周期事件有咨,載入過程就是由上面這行代碼啟動琐簇。
obtainFreshBeanFactory()方法調(diào)用AbstractApplicationContext的子類容器中的refreshBeanFactory()方法,此方法負(fù)責(zé)啟動容器載入Bean定義資源文件的過程如下:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//父類定義了抽象的refreshBeanFactory()方法座享,具體實(shí)現(xiàn)調(diào)用子類容器的refreshBeanFactory()方法
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
refreshBeanFactory()方法源碼如下:
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
// 如果已經(jīng)有容器存在就銷毀
destroyBeans();
closeBeanFactory();
}
try {
// 創(chuàng)建IOC容器
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 設(shè)置序列化
beanFactory.setSerializationId(getId());
/** 定制化IOC容器婉商,如:
* 設(shè)置啟動參數(shù),開啟注解的自動裝配
*/
customizeBeanFactory(beanFactory);
// 使用BeanFactory加載bean定義渣叛,具體的實(shí)現(xiàn)在子類容器中
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
refreshBeanFactory()方法的步驟:
- 已經(jīng)有容器存在就銷毀Beans并關(guān)閉beanFactory丈秩。
- 創(chuàng)建DefaultListableBeanFactory,即BeanFactory的默認(rèn)實(shí)現(xiàn)淳衙。
- 調(diào)用loadBeanDefinitions(beanFactory)裝載bean蘑秽。
refreshBeanFactory()代碼中有一段代碼:
// 使用BeanFactory加載bean定義,具體的實(shí)現(xiàn)在子類容器中
loadBeanDefinitions(beanFactory);
loadBeanDefinitions(beanFactory)箫攀,看名字是加載 Definitions筷狼, Definition 是核心之一,代表著IOC 中的基本數(shù)據(jù)結(jié)構(gòu)匠童。該方法為抽象方法埂材,AbstractRefreshableApplicationContext中只定義了抽象的loadBeanDefinitions方法,容器真正調(diào)用的是其子類AbstractXmlApplicationContext對該方法的實(shí)現(xiàn)汤求,loadBeanDefinitions方法的源碼如下:
//實(shí)現(xiàn)父類抽象的載入Bean定義方法
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//創(chuàng)建Bean讀取器俏险,并通過回調(diào)機(jī)制set到容器中,容器通過讀取器讀取Bean定義資源
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
/**為Bean讀取器設(shè)置Spring資源加載器扬绪,AbstractXmlApplicationContext的
*祖先父類AbstractApplicationContext繼承DefaultResourceLoader竖独,
*因此,容器本身也是一個資源加載器
*/
beanDefinitionReader.setResourceLoader(this);
//為Bean讀取器設(shè)置xml解析器
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//當(dāng)Bean讀取器讀取Bean定義的Xml資源文件時挤牛,啟用Xml的校驗(yàn)機(jī)制
initBeanDefinitionReader(beanDefinitionReader);
//Bean讀取器真正實(shí)現(xiàn)加載的方法
loadBeanDefinitions(beanDefinitionReader);
}
loadBeanDefinitions()方法的步驟:
- 創(chuàng)建Bean讀取器莹痢,用于讀取XML中配置。
- 設(shè)置環(huán)境,資源加載器竞膳。
- 初始化航瞭,加載。
其中真正實(shí)現(xiàn)加載Bean定義資源的方法為loadBeanDefinitions(XmlBeanDefinitionReader reader):
//Xml Bean讀取器加載Bean定義資源
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//獲取Bean定義資源的定位
Resource[] configResources = getConfigResources();
/**如果Bean定義資源的定位不為空坦辟,
*Bean讀取器調(diào)用其父類AbstractBeanDefinitionReader讀取定位到的Bean定義資源
*/
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
/**如果子類中獲取的Bean定義資源定位為空刊侯,
*則獲取FileSystemXmlApplicationContext構(gòu)造方法中setConfigLocations方法設(shè)置的資源
*/
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
由于Demo中我們使用FileSystemXmlApplicationContext,getConfigResources的返回值為null锉走,所以程序直接跳過第一個if分支滨彻,直接執(zhí)行reader.loadBeanDefinitions(configLocations)分支。
Bean讀取器方法loadBeanDefinitions實(shí)現(xiàn):
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//獲取在IOC容器初始化過程中set的資源加載器
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
try {
/**將指定位置的Bean定義資源文件解析為Spring IOC容器封裝的資源
*加載多個指定位置的Bean定義資源文件
*/
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
//調(diào)用其子類XmlBeanDefinitionReader的方法,實(shí)現(xiàn)加載功能
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 {
/**將指定位置的Bean定義資源文件解析為Spring IOC容器封裝的資源
*加載單個指定位置的Bean定義資源文件
*/
Resource resource = resourceLoader.getResource(location);
//調(diào)用其子類XmlBeanDefinitionReader的方法,實(shí)現(xiàn)加載功能
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
該方法做了兩件事:
- 調(diào)用資源加載器的獲取資源方法resourceLoader.getResource(location)盹愚,獲取到要加載的資源凑术。
- 真正執(zhí)行加載功能是其子類XmlBeanDefinitionReader的loadBeanDefinitions方法。
未完跟進(jìn)中......(IOC容器初始化:Bean的解析和注冊)
XmlBeanDefinitionReader通過調(diào)用其父類DefaultResourceLoader的getResource方法獲取要加載的資源,源碼如下
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
//如果是類路徑標(biāo)識,需通過ClassPathResource 得到bean文件的Resource對象
if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
try {
// 如果是URL標(biāo)識,通過UrlResource 作為bean文件的Resource對象
URL url = new URL(location);
return new UrlResource(url);
}
catch (MalformedURLException ex) {
}
/**若既不是classpath標(biāo)識只冻,也不是URL標(biāo)識,則調(diào)用
*容器本身的getResourceByPath方法獲取bean文件的Resource對象
*/
return getResourceByPath(location);
}
我們可以按照這個邏輯對IOC 配置文件從任何地方加載進(jìn)行加載计技。
Spring中提供的響應(yīng)的資源抽象:
●ClassPathResource
●URLResource
●FileSystemResource
上述的是定位Resource 的一個過程喜德,而這只是加載過程的一部分.
可以看到方法loadBeanDefinitions(String location, Set<Resource> actualResources) 中調(diào)用了方法 loadBeanDefinitions(Resource resource),如下:
//XmlBeanDefinitionReader加載Resource的入口方法
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//將讀入的XML資源進(jìn)行編碼處理
return loadBeanDefinitions(new EncodedResource(resource));
}
方法loadBeanDefinitions(EncodedResource encodedResource)部分源碼:
//這里是載入XML形式Bean定義資源文件方法
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
.......
try {
//將資源文件轉(zhuǎn)為InputStream的IO流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//讀取過程具體實(shí)現(xiàn)
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
//關(guān)閉從Resource中得到的IO流
inputStream.close();
}
}
讀取過程由方法doLoadBeanDefinitions(InputSource inputSource, Resource resource)實(shí)現(xiàn):
//讀取過程具體實(shí)現(xiàn)
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
源碼實(shí)現(xiàn):
//從特定XML文件中實(shí)際載入Bean定義資源
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//將XML文件轉(zhuǎn)換為DOM對象垮媒,documentLoader實(shí)現(xiàn)解析過程
Document doc = doLoadDocument(inputSource, resource);
//啟動Spring IOC容器對Bean定義解析過程舍悯,會使用到Spring的Bean配置規(guī)則
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);
}
}
至此已完成Spring IOC容器根據(jù)定位的Bean定義資源文件,將其加載讀入并轉(zhuǎn)換為Document對象的過程睡雇。
doLoadBeanDefinitions()方法的步驟:
- 將XML文件轉(zhuǎn)換為DOM對象萌衬。
- registerBeanDefinitions方法啟動Spring IOC容器對Bean定義解析過程。
接下來需要剖析的就是如何解析為Spring IOC管理的Bean對象并將其注冊到容器中:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//獲得容器中注冊的Bean數(shù)量
int countBefore = getRegistry().getBeanDefinitionCount();
//解析過程入口它抱,具體的解析實(shí)現(xiàn)過程有實(shí)現(xiàn)類DefaultBeanDefinitionDocumentReader完成
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//統(tǒng)計解析的Bean數(shù)量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
BeanDefinitionDocumentReader接口通過registerBeanDefinitions方法調(diào)用其實(shí)現(xiàn)類DefaultBeanDefinitionDocumentReader對Document對象進(jìn)行解析秕豫,解析過程入口:
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
//獲得Document的根元素
Element root = doc.getDocumentElement();
/**具體的解析過程由BeanDefinitionParserDelegate實(shí)現(xiàn),
*BeanDefinitionParserDelegate中定義了Spring Bean定義XML文件的各種元素
*/
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
preProcessXml(root);
//從Document的根元素開始進(jìn)行Bean定義的Document對象
parseBeanDefinitions(root, delegate);
postProcessXml(root);
}
該方法最核心的邏輯就是調(diào)用 parseBeanDefinitions(root, this.delegate)观蓄,該方法具體實(shí)現(xiàn):
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//如果Bean定義的Document對象使用了Spring默認(rèn)的XML命名空間
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
//獲取Bean定義的Document對象根元素的所有子節(jié)點(diǎn)
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)) {
/**如果Bean定義的Document對象使用了Spring默認(rèn)的XML命名空間
*使用Spring的Bean規(guī)則解析元素節(jié)點(diǎn)
*/
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
/**如果沒有使用Spring默認(rèn)的XML命名空間混移,
*則使用用戶自定義的解析規(guī)則解析元素節(jié)點(diǎn)
*/
delegate.parseCustomElement(root);
}
}
此方法使用Spring的Bean規(guī)則從Document的根元素開始進(jìn)行Bean定義的Document對象。
parseDefaultElement方法的實(shí)現(xiàn):
//使用Spring的Bean規(guī)則解析Document元素節(jié)點(diǎn)
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
/**如果元素節(jié)點(diǎn)既不是導(dǎo)入元素<Import>侮穿,也不是別名元素<Alias>歌径,即普通的<Bean>元素,
*則按照Spring的Bean規(guī)則解析元素
*/
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
}
可以看到解析bean規(guī)則的方法為processBeanDefinition亲茅,如下:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
/**BeanDefinitionHolder是對BeanDefinition的封裝回铛,即Bean定義的封裝類狗准,
*對Document對象中<Bean>元素的解析由BeanDefinitionParserDelegate實(shí)現(xiàn)
*/
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//向Spring IOC容器注冊解析得到的Bean定義,這是Bean定義向IoC容器注冊的入口
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
//發(fā)送注冊事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
processBeanDefinition()方法的步驟:
- 定義Bean的封裝類茵肃。
- 向Spring IOC容器注冊解析得到的Bean定義腔长。
- 執(zhí)行容器通知事件。
靜態(tài)方法BeanDefinitionReaderUtils.registerBeanDefinition 向Spring IOC容器注冊解析得到的Bean定義免姿,這是Bean定義向IoC容器注冊的入口饼酿,剖析如下:
//將解析的BeanDefinitionHold注冊到容器中
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
//獲取解析的BeanDefinition的名稱
String beanName = definitionHolder.getBeanName();
//向IOC容器注冊BeanDefinition
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
//如果解析的BeanDefinition有別名榕酒,向容器為其注冊別名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String aliase : aliases) {
registry.registerAlias(beanName, aliase);
}
}
}
registerBeanDefinition()方法的步驟:
- 從bean的持有者那里獲取了beanName胚膊。
- 注冊bean的名字和 BeanDefinition。
方法registerBeanDefinition實(shí)現(xiàn)注冊bean的名字和 BeanDefinition想鹰,該方法是DefaultListableBeanFactory向IOC容器注冊bean的最后一步紊婉,使用一個 ConcurrentHashMap存放IOC容器中注冊解析的BeanName和BeanDefinition。實(shí)現(xiàn):
//定義ConcurrentHashMap存儲注冊的BeanName和BeanDefinition
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, 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");
//校驗(yàn)解析的BeanDefiniton
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
//線程同步保證數(shù)據(jù)的一致性
synchronized (this.beanDefinitionMap) {
Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
/**如果有同名的BeanDefinition已經(jīng)在IOC容器中注冊辑舷,
*并且不允許覆蓋已注冊的Bean喻犁,則拋出注冊失敗異常
*/
if (oldBeanDefinition != null) {
if (!this.allowBeanDefinitionOverriding) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else {
//如果允許覆蓋,則后注冊的覆蓋先注冊的
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
/**如果IOC容器中沒有已經(jīng)注冊同名的bean何缓,
*按正常注冊流程注冊
*/
else {
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
this.beanDefinitionMap.put(beanName, beanDefinition);
//重置所有已注冊過BeanDefinition的緩存
resetBeanDefinition(beanName);
}
}
到目前為止肢础,Bean定義資源文件中配置的Bean經(jīng)過解析后,已注冊到IOC容器中碌廓,由容器管理传轰,完成了IOC容器初始化的全部工作。
至此IOC容器中已構(gòu)建起了Bean的配置信息谷婆,這些BeanDefinition信息已可以使用并可被檢索慨蛙。
IOC容器的作用就是對這些注冊的BeanDefinition信息進(jìn)行處理和維護(hù)。BeanDefinition信息是IOC容器控制反轉(zhuǎn)的基礎(chǔ)纪挎,正是有了這些注冊的數(shù)據(jù)期贫,容器才可以進(jìn)行依賴注入。
未完跟進(jìn)中......(IOC容器的依賴注入)
IOC容器的依賴注入
當(dāng)Spring IOC容器完成了Bean定義資源的定位异袄、載入和解析注冊以后通砍,IOC容器中已經(jīng)管理類Bean定義的相關(guān)數(shù)據(jù),但此時IOC容器還未對所管理的Bean進(jìn)行依賴注入烤蜕。
通常IOC容器觸發(fā)依賴注入在以下兩種情況發(fā)生:
- 當(dāng)用戶第一次通過getBean方法向IOC容索要Bean的時候封孙;
- 當(dāng)用戶在Bean定義資源中為<Bean>元素配置了lazy-init屬性,即讓容器在解析注冊Bean定義時進(jìn)行預(yù)實(shí)例化的時候玖绿。
BeanFactory接口定義了Spring IOC容器的基本功能規(guī)范敛瓷,是Spring IOC容器應(yīng)遵守的最底層和最基本的編程規(guī)范,同時接口中定義了幾個getBean方法斑匪,即用戶向IOC容器索取管理的Bean的方法呐籽,通過分析其子類的具體實(shí)現(xiàn)锋勺,理解Spring IOC容器在用戶索取Bean時如何完成依賴注入。
以我spring入門的demo為例:
public static void main( String[] args ){
String xmlPath="src//main/resources/spring.xml";
ApplicationContext context = new FileSystemXmlApplicationContext(xmlPath);
((Car)context.getBean("car")).whistle();
}
我們進(jìn)入getBean方法中狡蝶,看看其具體實(shí)現(xiàn):
//獲取IOC容器中指定名稱的Bean
public Object getBean(String name) throws BeansException {
//doGetBean是真正向IOC容器獲取被管理Bean的實(shí)現(xiàn)過程
return doGetBean(name, null, null, false);
}
//獲取IOC容器中指定名稱和類型的Bean
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
//doGetBean是真正向IOC容器獲取被管理Bean的實(shí)現(xiàn)過程
return doGetBean(name, requiredType, null, false);
}
//獲取IOC容器中指定名稱和參數(shù)的Bean
public Object getBean(String name, Object... args) throws BeansException {
//doGetBean是真正向IOC容器獲取被管理Bean的實(shí)現(xiàn)過程
return doGetBean(name, null, args, false);
}
//獲取IOC容器中指定名稱庶橱、類型和參數(shù)的Bean
public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException {
//doGetBean是真正向IOC容器獲取被管理Bean的實(shí)現(xiàn)過程
return doGetBean(name, requiredType, args, false);
}
從上述代碼可以得知,方法doGetBean才是真正向IOC容器獲取被管理bean的實(shí)現(xiàn)方法贪惹,如下:
//真正實(shí)現(xiàn)向IOC容器獲取Bean的方法苏章,也是觸發(fā)依賴注入功能的地方
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
/**根據(jù)指定名稱獲取被管理Bean名稱,首先剝離指定名稱中對容器的相關(guān)依賴
*如果指定的是別名奏瞬,需要將別名轉(zhuǎn)換為規(guī)范的bean名稱
*/
final String beanName = transformedBeanName(name);
Object bean;
/**先從緩存中取是否已經(jīng)有被創(chuàng)建過的單態(tài)類型的Bean枫绅,
*對于單態(tài)模式的Bean整個IOC容器中只創(chuàng)建一次,不需要重復(fù)創(chuàng)建
*/
Object sharedInstance = getSingleton(beanName);
//IOC容器創(chuàng)建單態(tài)模式Bean實(shí)例對象
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
/**如果指定名稱的Bean在容器中已存在單態(tài)模式的Bean被創(chuàng)建硼端,
*直接返回已經(jīng)創(chuàng)建的Bean
*/
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 + "'");
}
}
//獲取給定Bean的實(shí)例對象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
/**如果沒有正在創(chuàng)建的單態(tài)模式Bean并淋,
*緩存中已經(jīng)有已經(jīng)創(chuàng)建的原型模式Bean,
*但是由于循環(huán)引用的問題導(dǎo)致實(shí)例化對象失敗
*/
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
/**對IOC容器中是否存在指定名稱的BeanDefinition進(jìn)行檢查珍昨,
*首先檢查是否能在當(dāng)前的BeanFactory中獲取的所需要的Bean县耽,
*如果不能,則委托當(dāng)前容器的父級容器去查找镣典,
*若仍然找不到兔毙,則沿著容器的繼承體系向父級容器查找
*/
BeanFactory parentBeanFactory = getParentBeanFactory();
//如果當(dāng)前容器的父級容器存在,同時當(dāng)前容器中不存在指定名稱的Bean
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
//解析指定Bean名稱的原始名稱
String nameToLookup = originalBeanName(name);
if (args != null) {
//若參數(shù)不為null兄春,委派父級容器根據(jù)指定原始名稱和顯式的參數(shù)進(jìn)行查找
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
//若參數(shù)為null澎剥,那么委派父級容器根據(jù)指定原始名稱和所需類型查找
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
/**根據(jù)指定bean名稱獲取其父級的bean定義,
*主要是為了解決bean繼承時子類合并父類公共屬性的問題
*/
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
//獲取當(dāng)前bean所有依賴bean的名稱
String[] dependsOn = mbd.getDependsOn();
//如果當(dāng)前bean有依賴bean神郊,即當(dāng)前bean依賴其他的bean
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
//獲取當(dāng)前bean的依賴bean肴裙,遞歸調(diào)用getBean方法
getBean(dependsOnBean);
//將被依賴的bean注冊給當(dāng)前依賴的bean
registerDependentBean(dependsOnBean, beanName);
}
}
//創(chuàng)建單態(tài)模式bean的實(shí)例對象
if (mbd.isSingleton()) {
//匿名內(nèi)部類實(shí)現(xiàn)創(chuàng)建bean實(shí)例對象,并注冊給所依賴的對象
sharedInstance = getSingleton(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
try {
/**創(chuàng)建一個指定bean實(shí)例對象涌乳,
*如果有父級繼承蜻懦,則合并子類和父類的定義
*/
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//顯式地從容器單態(tài)模式Bean緩存中清除實(shí)例對象
destroySingleton(beanName);
throw ex;
}
}
});
//獲取給定bean的實(shí)例對象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//IOC容器創(chuàng)建原型模式bean實(shí)例對象
else if (mbd.isPrototype()) {
//如果是原型模式,則每次都會創(chuàng)建一個新的對象
Object prototypeInstance = null;
try {
/**回調(diào)beforePrototypeCreation方法夕晓,
*默認(rèn)的功能:注冊當(dāng)前創(chuàng)建的原型對象
*/
beforePrototypeCreation(beanName);
//創(chuàng)建指定bean對象實(shí)例
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
/**回調(diào)afterPrototypeCreation方法宛乃,
*默認(rèn)的功能:告訴IOC容器指定bean的原型對象不再創(chuàng)建了
*/
afterPrototypeCreation(beanName);
}
//獲取給定Bean的實(shí)例對象
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
/**如果要創(chuàng)建的bean既不是單態(tài)模式,也不是原型模式蒸辆,
*則根據(jù)bean定義資源中配置的生命周期范圍征炼,選擇實(shí)例化bean的合適方法
*/
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
//如果bean定義資源中沒有配置生命周期范圍,則bean定義不合法
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
//匿名內(nèi)部類實(shí)現(xiàn)獲取一個指定生命周期范圍的實(shí)例
Object scopedInstance = scope.get(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
//獲取給定Bean的實(shí)例對象
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);
}
}
}
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return (T) bean;
}
注:
1.BeanFactory和FactoryBean的區(qū)別:BeanFactory是管理容器中Bean的工廠躬贡,而FactoryBean是創(chuàng)建對象的工廠Bean谆奥,兩者之間有區(qū)別;
2.原型模式(Prototype)即每次都會創(chuàng)建一個新的對象拂玻。
上述是向IOC容器獲取Bean方法酸些,步驟如下:
1.如果bean定義的單例模式(Singleton)宰译,則容器在創(chuàng)建之前先從緩存中查找,以確保整個容器中只存在一個實(shí)例對象魄懂;
2.如果Bean定義的是原型模式(Prototype)沿侈,則容器每次都會創(chuàng)建一個新的實(shí)例對象。
具體的Bean實(shí)例對象的創(chuàng)建過程由實(shí)現(xiàn)了ObejctFactory接口的匿名內(nèi)部類的createBean方法完成市栗,ObejctFactory使用委派模式缀拭,具體的Bean實(shí)例創(chuàng)建過程交由其實(shí)現(xiàn)類AbstractAutowireCapableBeanFactory完成。
接下來繼續(xù)分析AbstractAutowireCapableBeanFactory的createBean方法的源碼填帽,目的是理解其創(chuàng)建Bean實(shí)例的具體實(shí)現(xiàn)過程蛛淋。
AbstractAutowireCapableBeanFactory負(fù)責(zé)創(chuàng)建Bean實(shí)例對象,其實(shí)現(xiàn)了ObejctFactory接口盲赊,創(chuàng)建容器指定的Bean實(shí)例對象铣鹏,同時還對創(chuàng)建的Bean實(shí)例對象進(jìn)行初始化處理敷扫。其創(chuàng)建Bean實(shí)例對象的方法源碼如下:
//創(chuàng)建bean實(shí)例對象
protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
//判斷需要創(chuàng)建的bean是否可實(shí)例化
resolveBeanClass(mbd, beanName);
//校驗(yàn)和準(zhǔn)備bean中的方法覆蓋
try {
mbd.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
/**如果bean配置了初始化前和初始化后的處理器哀蘑,
*則返回一個需要創(chuàng)建bean的代理對象
*/
Object bean = resolveBeforeInstantiation(beanName, mbd);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
//創(chuàng)建bean的入口
Object beanInstance = doCreateBean(beanName, mbd, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
而真正創(chuàng)建bean的方法如下:
//真正創(chuàng)建bean的方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
//封裝被創(chuàng)建的bean對象
BeanWrapper instanceWrapper = null;
//如果bean是單態(tài)模式的,先從容器中緩存中獲取同名bean
if (mbd.isSingleton()){
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//創(chuàng)建bean的實(shí)例對象
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
//調(diào)用PostProcessor后置處理器
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
}
//向容器中緩存單態(tài)模式的bean對象葵第,以防循環(huán)引用
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");
}
//匿名內(nèi)部類實(shí)現(xiàn)绘迁,為了防止循環(huán)引用
addSingletonFactory(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
/**bean對象的初始化,依賴注入在此觸發(fā)
*這個exposedObject在初始化完成之后返回作為依賴注入完成后的bean
*/
Object exposedObject = bean;
try {
//將bean實(shí)例對象封裝卒密,并且bean定義中配置的屬性值賦值給實(shí)例對象
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
//初始化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) {
//獲取指定名稱的已注冊的單例模式bean對象
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
//如果根據(jù)名稱獲取已注冊的bean和正在實(shí)例化的bean相同
if (exposedObject == bean) {
//當(dāng)前實(shí)例化的Bean初始化完成
exposedObject = earlySingletonReference;
}
//當(dāng)前bean依賴其他bean缀台,同時當(dāng)發(fā)生循環(huán)引用時不允許新創(chuàng)建實(shí)例對象
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
//獲取當(dāng)前bean所依賴的其他bean
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.");
}
}
}
}
//注冊完成依賴注入的bean
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
通過對方法源碼的分析,可以看到具體的依賴注入實(shí)現(xiàn)在以下兩個方法中:
1.createBeanInstance:創(chuàng)建bean所包含的java對象實(shí)例哮奇。
2.populateBean :對bean屬性的依賴注入進(jìn)行處理膛腐。
下面繼續(xù)分析這兩個方法的代碼實(shí)現(xiàn)。
createBeanInstance方法創(chuàng)建Bean的java實(shí)例對象鼎俘,根據(jù)指定的初始化策略哲身,使用靜態(tài)工廠、工廠方法或者容器的自動裝配特性生成java實(shí)例對象贸伐,源碼如下:
//創(chuàng)建bean的實(shí)例對象
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
//首先檢查確認(rèn)bean是可實(shí)例化的
Class beanClass = resolveBeanClass(mbd, beanName);
//通過工廠方法對bean進(jìn)行實(shí)例化
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
if (mbd.getFactoryMethodName() != null) {
//調(diào)用工廠方法實(shí)例化
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
//通過容器的自動裝配方法進(jìn)行實(shí)例化
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) {
/**配置了自動裝配屬性勘天,使用容器的自動裝配實(shí)例化
*容器的自動裝配是根據(jù)參數(shù)類型匹配bean的構(gòu)造方法
*/
return autowireConstructor(beanName, mbd, null, null);
}
else {
//使用默認(rèn)的無參構(gòu)造方法實(shí)例化
return instantiateBean(beanName, mbd);
}
}
//使用bean的構(gòu)造方法進(jìn)行實(shí)例化
Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//通過容器的自動裝配特性,調(diào)用匹配的構(gòu)造方法實(shí)例化
return autowireConstructor(beanName, mbd, ctors, args);
}
//通過默認(rèn)的無參構(gòu)造方法實(shí)例化
return instantiateBean(beanName, mbd);
}
//通過默認(rèn)的無參構(gòu)造方法實(shí)例化bean對象
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
//獲取系統(tǒng)的安全管理接口捉邢,JDK標(biāo)準(zhǔn)的安全管理API
if (System.getSecurityManager() != null) {
//匿名內(nèi)置類實(shí)現(xiàn)脯丝,根據(jù)實(shí)例化策略創(chuàng)建實(shí)例對象
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
}, getAccessControlContext());
}
else {
//將實(shí)例化的對象封裝起來
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);
}
}
經(jīng)過上述分析,我們不難發(fā)現(xiàn)對使用工廠方法和自動裝配特性的bean的實(shí)例化相對比較清楚伏伐,調(diào)用相應(yīng)的工廠方法或者參數(shù)匹配的構(gòu)造方法即可完成實(shí)例化對象的工作宠进。
但對于最常使用的默認(rèn)無參構(gòu)造方法就需要使用相應(yīng)的初始化策略(JDK的反射機(jī)制或者CGLIB)來進(jìn)行初始化了。
未完跟進(jìn)中......(默認(rèn)的無參構(gòu)造方法創(chuàng)建Bean實(shí)例化對象)
在使用默認(rèn)的無參構(gòu)造方法創(chuàng)建bean的實(shí)例化對象的方法instantiateBean中調(diào)用了類SimpleInstantiationStrategy中的實(shí)例化bean的方法藐翎,源碼如下:
return getInstantiationStrategy().instantiate(mbd, beanName, parent);
方法instantiate的具體實(shí)現(xiàn):
//使用初始化策略實(shí)例化bean對象
public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
//如果bean定義中不存在方法覆蓋材蹬,則不需要CGLIB父類方法
if (beanDefinition.getMethodOverrides().isEmpty()) {
Constructor<?> constructorToUse;
synchronized (beanDefinition.constructorArgumentLock) {
//獲取對象的構(gòu)造方法或工廠方法
constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod;
//如果沒有構(gòu)造方法同時也沒有工廠方法
if (constructorToUse == null) {
//使用JDK的反射機(jī)制潦匈,判斷需實(shí)例化的bean是否為接口
final Class clazz = beanDefinition.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
//匿名內(nèi)部類實(shí)現(xiàn),通過反射機(jī)制獲取bean的構(gòu)造方法
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
public Constructor run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
}
});
}
else {
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
}
beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Exception ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
//通過BeanUtils實(shí)例化赚导,通過反射機(jī)制進(jìn)行實(shí)例化
return BeanUtils.instantiateClass(constructorToUse);
}
else {
//通過CGLIB來實(shí)例化對象
return instantiateWithMethodInjection(beanDefinition, beanName, owner);
}
}
上述代碼步驟:
- 如果bean存在方法被覆蓋的情況茬缩,那么通過JDK的反射機(jī)制進(jìn)行實(shí)例化。
- 否則吼旧,通過CGLIB實(shí)例化凰锡。
可以看到方法instantiateWithMethodInjection執(zhí)行了通過CGLIB來實(shí)例化對象,其具體實(shí)現(xiàn)是在SimpleInstantiationStrategy的子類CglibSubclassingInstantiationStrategy中:
//通過CGLIB實(shí)例化bean對象
public Object instantiate(Constructor ctor, Object[] args) {
Enhancer enhancer = new Enhancer();
//將bean本身作為其基類
enhancer.setSuperclass(this.beanDefinition.getBeanClass());
enhancer.setCallbackFilter(new CallbackFilterImpl());
enhancer.setCallbacks(new Callback[] {
NoOp.INSTANCE,
new LookupOverrideMethodInterceptor(),
new ReplaceOverrideMethodInterceptor()
});
//通過CGLIB的create方法生成實(shí)例對象
return (ctor == null) ?
enhancer.create() :
enhancer.create(ctor.getParameterTypes(), args);
}
這里涉及到CGLIB動態(tài)代理圈暗,我們簡單來看下代理相關(guān):
CGLIB是一個常用的字節(jié)碼生成器的類庫掂为,它提供了一系列API實(shí)現(xiàn)java字節(jié)碼的生成和轉(zhuǎn)換功能。我們在學(xué)習(xí)JDK的動態(tài)代理時都知道员串,JDK的動態(tài)代理只能針對接口勇哗,如果一個類沒有實(shí)現(xiàn)任何接口,要對其進(jìn)行動態(tài)代理只能使用CGLIB寸齐。
靜態(tài)代理的缺點(diǎn)很明顯:
一個代理類只能對一個業(yè)務(wù)接口的實(shí)現(xiàn)類進(jìn)行包裝欲诺,如果有多個業(yè)務(wù)接口的話就要定義很多實(shí)現(xiàn)類和代理類才行。而且渺鹦,如果代理類對業(yè)務(wù)方法的預(yù)處理扰法、調(diào)用后操作都是一樣的(比如:調(diào)用前輸出提示、調(diào)用后自動關(guān)閉連接)毅厚,則多個代理類就會有很多重復(fù)代碼塞颁。這時我們可以定義這樣一個代理類,它能代理所有實(shí)現(xiàn)類的方法調(diào)用:根據(jù)傳進(jìn)來的業(yè)務(wù)實(shí)現(xiàn)類和方法名進(jìn)行具體調(diào)用吸耿,即動態(tài)代理祠锣。
動態(tài)代理分為JDK動態(tài)代理和CGLIB動態(tài)代理:
JDK動態(tài)代理的代理對象在創(chuàng)建時,需要使用業(yè)務(wù)實(shí)現(xiàn)類所實(shí)現(xiàn)的接口作為參數(shù)(因?yàn)樵诤竺娲矸椒〞r需要根據(jù)接口內(nèi)的方法名進(jìn)行調(diào)用)咽安。如果業(yè)務(wù)實(shí)現(xiàn)類是沒有實(shí)現(xiàn)接口而是直接定義業(yè)務(wù)方法的話伴网,就無法使用JDK動態(tài)代理了。并且板乙,如果業(yè)務(wù)實(shí)現(xiàn)類中新增了接口中沒有的方法是偷,這些方法是無法被代理的(因?yàn)闊o法被調(diào)用)。此時應(yīng)該交給CGLIB來處理:CGLIB是針對類來實(shí)現(xiàn)代理的募逞,原理是通過繼承業(yè)務(wù)類蛋铆,對指定的業(yè)務(wù)類生成一個動態(tài)代理子類,并覆蓋其中業(yè)務(wù)方法實(shí)現(xiàn)代理放接。