一、容器以及依赖注入
什么是依赖注入
新的一年到了,小明要开始购置全新的衣服,他去以纯买了裤子,耐克买了鞋子,森马买了上衣等等,为此他跑遍了整个城市的专卖店,他觉得很累很麻烦,自己过个年什么衣服都要自己跑去专卖店买。
新的一年到了,小妮也要购置全新的衣服,她在家里跟保姆说,我要一套漂亮的新年衣服,保姆便从某个神秘的地方拿了一套新的衣服给了小妮,这样小妮就不用到处跑来跑去了。
小明跟小妮的故事其实就是一个依赖反转的过程,小明需要的衣服需要自己从每个地方自己去买,而小妮的衣服则是由保姆给她的。对于获取衣服的方式而言,两者的方式从一个主动获取转换为被注入到过程。
控制的反转指的是获取方式的反转。
在Spring中,控制反转指的是原先对象需要自己去关心,创建自己依赖的对象的过程转换为由容器自动生成注入依赖的过程,而对象自己不需要再关心这个过程了。
什么是容器?
当我们去打水的时候,水桶是一个容器,这个容器能盛许多单位的水,不管你是红茶、绿茶等等,只要你是符合水的特性的,都能够往容器里面存放。
而容器能够帮助我们,在需要喝水的时候,自动把水装好并且递给主人的过程。容器与依赖反转的好处?
容器以及依赖注入的出现,使得开发者不需要去创建、生成以及管理bean之间的依赖关系,极大的解放了bean的责任。
二、Spring容器
同样,在Spring中,核心也是容器跟依赖注入的概念。
1、什么是IoC容器
在日常生活中,容器就是用来盛放东西的,比如水桶,水桶可以抽象为一个接口,这个接口定义了要有容量,要有挂钩的就是容器。而水桶的类型有很多种,只要实现了水桶的接口,那么就是一个水桶,也就是一个容器。
在Spring中同样也不例外,我们可以看到BeanFactory就是一个接口,而它其实就是容器的“水桶接口”,BeanFactory简单理解为一个模型,模型定义了Spring的容器的规范。
而在Spring容器中,盛放的bean的方式就是BeanDefinition,BeanDefinition抽象的描述了bean的各种属性。
2、Spring IoC容器总体设计
前面已经说到,Spring有一系列的容器,它的定义是在BeanFactory里面。
先看一下官方文档是怎么定义BeanFactory的
1 | /** |
这个注释也太长了吧
从上面可以看到BeanFactory有如下的特点:
- 它是Spring容器的根接口,实现它的接口并且符合规范的都是容器,同时它也是Spring中最基础的一个容器。
- 实现这个接口可以包含很多的bean definition,而且每个definition的ID都是不一样的,是唯一的。
- BeanFactory能解析配置文件,如xml文件等,转成definition并且存放在容器中。
- 定义了实现BeanFactory的实现类的要求。
而从实现而言,BeanFactory实现了几个容器的必备功能,例如获取Bean,判断Bean是否存在等等。
1 | public interface BeanFactory { |
3、Spring IoC容器细节
因为BeanFactory都比较大同小异,所以在这里只使用已经废弃的XMLBeanfactory进行学习。
主要是因为比较简单易懂
同样我们需要摘代码出来看一下:
@Deprecated
@SuppressWarnings({"serial", "all"})
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
/**
* Create a new XmlBeanFactory with the given resource,
* which must be parsable using DOM.
* @param resource XML resource to load bean definitions from
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
/**
* Create a new XmlBeanFactory with the given input stream,
* which must be parsable using DOM.
* @param resource XML resource to load bean definitions from
* @param parentBeanFactory parent bean factory
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
从上面可以总结这个类做的事情:
- 使用Resource,把有着bean信息的XML文件转成Resource类型。
- 先创建了一个XmlBeanDefinitionReader,顾名思义就是用来读BeanDefinition资源的。
- 使用reader读取已经被转成Resource类型的XML定义的bean。
- 完成容器的构建
看起来够简单明了,简单可以理解为寻找到XML文件,将XML文件转换为Resource类型,使用XmlBeanDefinitionReader加载bean。
4、Spring IoC容器的主要工作
- 寻址:寻找bean的配置信息,并且以Resource方式进行读取。
- 载入:将Resource资源文件读取完毕后,将bean的配置信息转换为BeanFactory的BeanDefinition。
注册:将载入的BeanDefinition注册到IoC容器中,以HashMap的方式进行存储。
这一阶段可以总结为寻址->载入->注册阶段,称之为容器的初始化阶段,这是单独的一个过程。
注入:当触发getBean操作的时候会触发将Bean注入的过程。
这一阶段可以总结为注入阶段,是容器发挥作用的阶段,同样跟容器的初始化阶段是两个不同的过程。