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例外。