IOC依賴注入,兩個或多個類的彼此合作實現業務邏輯,這使每個對象都需要與其合作對象的引用(依賴),否則代碼高度耦合,難以測試。
應用IOC,當對象創建時,由一個掉控系統內的所以對象的外界實例將其所依賴的對象的引用傳遞給它,即依賴被注入到對象中。所以控制反轉是一個對象如何獲取它所依賴的對象的引用,反轉指的是責任的反轉。
IOC的設計與實現:BeanFactory和ApplicationContext
用戶使用容器時:可以使用轉義符“&” 來得到FactoryBean本身,FactoryBean:不是一個簡單的Bean,而是一個能產生或修飾對象生成的工廠Bean,它的實現與工廠模式、裝飾器模式類似。
public interface BeanFactory{
String FACROTY_BEAN_PREFIX="&";
Object getBean (String name) throws BeansException;
<T> T getBean(String name,Class<T> requiredType) throws BeansException;
Object getBean(String name,Object... args) throws BeansExption;
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name,Class targetType ) throws NoSuchBeanDefinitionException;
Class getType(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);
}
例如:XMLBeanFactory->(繼承)DefaultListenerBeanFactory->AbstractAutowireCapableBeanFactory->AbstractBeanFactory 只提供最基本的IOC容器的功能,可以認爲直接的BeanFactory實現是IOC容器的基本形式,各種ApplicationContext的實現是IOC容器的高級表現形式。
Resource是spring用來封裝I/o操作的類。“ClassPath-Resource res=new ClassPathResource("beans.xml")”,BeanDefinition 以XML文件的形式存在,這樣IOC容器就可以方便的定位到需要的BeanDefinition信息對Bean完成容器的初始化和依賴注入過程。
public class XmlBeanFactory extends DefaultListableBeanFactory{
private final XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource res) throws BeansEcception{
this(resource,null);
public XmlBeanFactory(Resource res,BeanFactory parentBeanFactory) throws BeansException{
super(parentBeanFactory);
this.reader.loadBeanDefinitions(res);
}
}
}
構造XmlBeanFactory這個IOC容器時,需指定BeanDefinition的信息來源,這個信息來源封裝成spring中的Resource類來給出。
編程式使用IOC容器的過程:
ClassPathResource res=new ClassPathResource("bean.xml");
DefaultListableBeanFactory factory=new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);
ApplicationContext設計原理:
public FileSystenXmlApplicationContext(String[] configurations, boolean refresh,ApplicationContext parent) throws BeansException{
super(parent);
setConfigLocations(configLocations);
if(refresh){
refresh();
}
protected Resource getResourceByPath(String path){//得到FileSystemResource的資源定位
if(path!=null && path.startswith("/")){
path=path.subString(1);
}
return new FileSystemResource(path);
}
}
IOC容器的初始化:
1.Resource定位過程;用桶裝水先找水。
2.BeanDefinition的載入;把用戶定義好的Bean表示成IOC容器內部的數據結構(BeanDefinition),實際就是POJO對象在IOC容器裏的抽象,使IOC方便對POJO對象進行管理。
3.向IOC容器註冊BeanDefinition。調用BeanDefinitionRegistry接口。註冊過程是把載入過程解析得到的BeanDefinition向IOC註冊,注入到一個HashMap中。
注意,IOC的初始化過程並不包括對Bean依賴注入的實現。Bean定義的載入和依賴注入是兩個獨立的過程。依賴注入一般發生在第一次通過getBean向容器索取Bean的時候。lazyinit例外。