原創内容,轉載請注明出處
1、BeanFactory類圖
BeanFactory類圖如下
從上圖可以看出BeanFactory主要實作類是XmlBeanFactory(Spring3.1建議棄用,可以使用DefaultListableBeanFactory和XmlBeanDefinitionReader程式設計實作)和DefaultListableBeanFactory。
2、BeanFactory程式設計式實作
基本IOC容器BeanFactory的程式設計式實作方式大緻可分為三個步驟
1.加載xml資源 Resource定位xml
2.BeanDefinition讀取和加載 BeanDefinitionParserDelegate代理對象去讀取
3.BeanDefinition注冊 BeanDefinitionRegistry去注冊
建立bean.xml,内容如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="person" class="com.test.bean.Person">
<property name="name" value="ylxy"/>
<property name="age" value="25"/>
</bean>
</beans>
建立Person類,代碼如下
package com.test.bean;
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void info(){
System.out.println("name:"+getName()+" age:"+getAge());
}
}
建立junit測試代碼,内容如下
@Test
public void testBeanFactory(){
ClassPathResource resource = new ClassPathResource("bean.xml");
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf);
reader.loadBeanDefinitions(resource);
Person p = bf.getBean("person", Person.class);
p.info();
}
最終測試結果如下
3、IOC配置檔案處理(BeanDefinition解析與注冊)
從程式設計代碼上看,可分以下幾個步驟
1.Resource定位(即Resource包裝spring xml配置檔案)。
2.BeanDefinition解析和注冊(由XmlBeanDefinitionReader類處了解析和注冊)。
3.擷取Bean(由BeanFactory擷取,依賴注入)。
從上面可知BeanDefinition的解析和注冊入口在XmlBeanDefinitionReader的loadBeanDefinitions(Resource resource)方法上。
1.在loadBeanDefinitions方法中,調用該類的doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法。
2.在doLoadBeanDefinitions方法中通過DocumentLoader(實際是DefaultDocumentLoader對象)加載xml檔案成Document類,之後調用該類的registerBeanDefinitions(Document doc, Resource resource)方法去解析加載和注冊BeanDefinition。
3.在registerBeanDefinitions方法中建立DefaultBeanDefinitionDocumentReader對象,并調用registerBeanDefinitions( Document doc, XmlReaderContext readerContext)去解析注冊BeanDefinition,解析時會對不同的xml元素進行不同的解析,比如<import/><alias/><bean/><beans/>等元素。
4.最終實際解析BeanDefinition的實作是建立BeanDefinitionParserDelegate委托對象,調用方法parseBeanDefinitionElement(Element ele)去解析BeanDefinition。
5.注冊對象是在BeanDefinitionReaderUtils.registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)中實作。
BeanDefinition解析實作:調用BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele)去解析xml成BeanDefinition,并将BeanDefinition封裝成BeanDefinitionHolder。
BeanDefinition注冊實作:調用BeanDefinitionRegistry.registerBeanDefinition(String beanName, BeanDefinition beanDefinition),由于DefaultListableBeanFactory實作了該接口的方法,故而實作注冊BeanDefinition是在DefaultListableBeanFactory中。在該類中通過将BeanDefinition存儲到一個HashMap集合中,完成對BeanDefinition的注冊。
4、依賴注入
依賴注入和控制反轉是同一個概念。當某個A javaBean需要B javaBean的引用去協助處理一些事情的時候,在傳統程式設計中,是需要A去new一個B對象。然而在spring中卻不一樣,建立B對象的工作不是由A來new,而是由spring IOC容器去建立,然後将建立的B對象注入到A中。
spring的依賴注入入口也就是BeanFactory的getBean()方法。getBean()方法最後調用doGetBean()方法,即doGetBean()方法是依賴注入的真實入口,代碼如下。
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
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 + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
//檢查這個bean是否在目前這個BeanFactory中,如果目前BeanFactory的不包含這個bean,則去父級BeanFactory查找。
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
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);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
//查找這個BeanDefinition是否有依賴對象,如果有依賴的對象,則IOC容器先建立依賴對象。
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
getBean(dependsOnBean);
registerDependentBean(dependsOnBean, beanName);
}
}
// Create bean instance.
if (mbd.isSingleton()) {
//擷取單例對象
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
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);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
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 && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
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;
}
從上述代碼可以看出建立對象是由DefaultSingletonBeanRegistry的getSingleton方法去建立,然後回調ObjectFactory的getObject方法,ObjectFactory的getObject方法又調用了createBean方法。也就是說實際建立對象的方法是AbstractAutowireCapableBeanFactory類的createBean方法,該方法内又調用doCreateBean去建立Bean。
1.調用createBeanInstance方法去建立BeanWrap(BeanWrap将Bean執行個體包裝了),該方法通過Java反射機制調用Bean的構造函數,完成Bean對象的建立,并将Bean包裝到一個BeanWrap對象中。
2.調用populateBean方法,給bean的屬性初始化,也就是<bean/>标簽中配置的屬性值。
3.調用initializeBean方法,初始化Bean。
3.1.invokeAwareMethods方法,如果Bean實作了Aware,則調用對應的Aware接口方法。
3.2.applyBeanPostProcessorsBeforeInitialization方法,如果BeanFactory配置了BeanPostProcessor,則執行BeanPostProcessor的postProcessBeforeInitialization方法。
3.3.invokeInitMethods方法,如果Bean實作了InitializingBean接口,則調用執行InitializingBean的接口方法。
3.4.applyBeanPostProcessorsAfterInitialization方法,如果BeanFactory配置了BeanPostProcessor,則執行BeanPostProcessor的postProcessAfterInitialization方法。
4.registerDisposableBeanIfNecessary方法,如果Bean實作了DisposableBean接口或者Bean需要destroy方法,則給Bean注冊DisposableBean功能(即把bean名稱和銷毀方法儲存在一個Map集合中)。
5.getObjectForBeanInstance(sharedInstance, name, beanName, mbd)方法,建立bean完成後,如果建立的bean執行個體是一個FactoryBean(相當于工廠模式的Factory,用來生産Bean執行個體),則會再調用FactoryBean的getObject()方法來生成實際需要的bean執行個體。也就是說如果getBean("factoryBean")會首先擷取FactoryBean執行個體,并且在通過FactoryBean工廠的getObject方法去擷取Bean,如果是getBean(“&factoryBean”),則spring會直接傳回一個FactoryBean執行個體。
5、總結
對于BeanDefinition的解析和注冊過程,首先将xml配置檔案加載進Resource中,然後将Resource解析成Document對象,最後通過BeanDefinitionParserDelegate委托對象去解析Document對象,并将解析的BeanDefinition包裝成BeanDefinitionHolder。最後通過BeanDefinitionRegistry接口将BeanDefinition存儲到HashMap集合中,以完成BeanDefinition的的注冊,具體實作在DefaultListableBeanFactory類中,該類實作了BeanDefinitionRegistry接口。
對于依賴注入,spring主要是使用Java的反射機制來建立bean對象,并為bean進行一些初始化操作。
源代碼如附件