1. 程式人生 > >Spring IOC之ignoredDependencyInterface

Spring IOC之ignoredDependencyInterface

        在閱讀Spring原始碼的時候,我曾經遇到了一個方法ignoredDependencyInterface();當時很是困惑,在查閱大量的資料的時候才初步的理解到了這個方法的作用。這篇文章是邁向Spring IOC原始碼的初步。可能在文章中存在個人的偏見或者主觀臆測,希望大家不要留面子,直接指證,我們一起進步吧。好了,我們開始吧!

        在這裡我使用的原始碼是Spring4.3.16的原始碼包。

        先建立一個Bean吧。

public class SpringBeanExplor {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(final String name) {
        this.name = name;
    }
}

配置資原始檔:

<?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">
    <import resource="classpath:spring/spring-dao.xml"/>
    <bean id="springBeanExplor" class="com.gosaint.domain.SpringBeanExplor">
        <property name="name" value="caozg"/>
    </bean>
</beans>

 測試獲取Bean

public class BeanTest {

    @Test
    public void testBeanLife() throws Exception{
        Resource resource=new ClassPathResource("applicationContext.xml");
        BeanFactory beanFactory=new DefaultListableBeanFactory();
        BeanDefinitionReader bdr=new XmlBeanDefinitionReader((BeanDefinitionRegistry) beanFactory);
        bdr.loadBeanDefinitions(resource);
        SpringBeanExplor bean = beanFactory.getBean(SpringBeanExplor.class);
        System.out.println(bean.getName());
    }
}

 1 讀取資原始檔,返回Resource的過程這裡我暫且不再贅述。

        2 上述建立BeanFactory物件的時候,我沒有使用XmlBeanFactory實現,因為這是一個過時的實現。我使用DefaulteListableBeanFacory作為實現。在new的時候開始建立物件,我們可以觀察這個過程中都幹了些什麼。

public DefaultListableBeanFactory() {
		super();
}

在DefaultListableBeanFactory的構造器中呼叫了父類的構造器。DefaultListableBeanFactory繼承了AbstractAutowireCapableBeanFactory。這是一個抽象的自動注入的一個Bean容器。當然是從字面理解。我們再來看看它的構造器的實現:

public AbstractAutowireCapableBeanFactory() {
		super();
		ignoreDependencyInterface(BeanNameAware.class);
		ignoreDependencyInterface(BeanFactoryAware.class);
		ignoreDependencyInterface(BeanClassLoaderAware.class);
}

  AbstractAutowireCapableBeanFactory的父類是AbstractBeanFactory。它沒有實現。交給子類去實現。大家可以看看三者之間的繼承關係,如下圖所示:

再看上述的方法:ignoreDependencyInterface(Class class);這個方法都幹了寫什麼。

/**
	 * Ignore the given dependency interface for autowiring.
	 * <p>This will typically be used by application contexts to register
	 * dependencies that are resolved in other ways, like BeanFactory through
	 * BeanFactoryAware or ApplicationContext through ApplicationContextAware.
	 * <p>By default, only the BeanFactoryAware interface is ignored.
	 * For further types to ignore, invoke this method for each type.
	 * @see org.springframework.beans.factory.BeanFactoryAware
	 * @see org.springframework.context.ApplicationContextAware
	 */
      //上述註釋的翻譯:忽略給定依賴介面的自動裝配,這通常被應用程式上下文用於註冊。
      //依賴關係是通過其他方式解決的,比如BeanFactory BeanFactoryAware或ApplicationContext通過ApplicationContextAware
      //預設情況下,只有BeanFactoryAware介面被忽略。若要忽略其他型別,請為每種型別呼叫此方法。 
	public void ignoreDependencyInterface(Class<?> ifc) {
		this.ignoredDependencyInterfaces.add(ifc);
	}

        簡單的說:由於我要建立一個BeanFactory。但是這個過程中我的Bean可能會依賴一些介面,如:BeanNameAware等。這些介面在建立Bean的過程中不會去例項化,而是自動忽略掉這些依賴。為什麼要忽略這些依賴呢?

private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<Class<?>>();

這貨其實是個Set集合。目前我們存在兩個問題沒有搞清楚

        1 為什麼在實現某些介面的時候依賴的介面要自動忽略注入?

        2 如何實現忽略注入的?(待續)

關於第一個問題:對於Spring自動建立Bean,但是Bean是無狀態的,也就是說Bean不知道Spring容器BeanFactory的任何信心,包括Bean自己的名稱name,Spring這樣做的目的是為了Spring容器和Bean的解耦,帶來的問題就是Bean的無狀態。那麼Bean要想定製化的做一些操作,就必然要獲取BeanFactory中的資訊,在Spring Bean的生命週期中我們都知道實現一些列介面去觀察Bean建立過程中的一些資訊。這裡的BeanNameAware、BeanfactoryAware、BeanClassLoaderAware這些介面就是獲取Bean的名稱、BeanFactory的資訊以及類載入器的資訊的。因此這裡牽扯到Spring建立bean的方式,正常例項化的bean和對定製化的bean要有所區分,因此Spring正常例項化的Bean就要忽略這個依賴注入放入介面。