简述SpringIOC和DI的实现原理
Inversion of Control,所谓控制反转,就是原先我们代码需要实现的对象创建、依赖的代码,反转给容器便忙实现。那就需要一个容器、一种描述需要创建的对象与对象的关系,这种描述最具体的表现就是我们的配置文件。
Dependency Injection,所谓依赖注入,被动接受依赖而不主动去找, 就是对象不是从容器中查找它依赖的类,而是在容器实例化对象的时候主动将它依赖的类注入给它。
对象和对象的关系怎么表示?
可以用xml、 properties文件等语义配置文件表示。
描述对象关系的文件存放在哪里?
可能是classpath、filesystem ,或者是 URL 网络资源, servletContext 等。
有了配置文件,那如何解析配置文件?
Spring核心容器类结构:
(1)BeanFactory:
Spring Bean 的创建是典型的工厂模式,这一系列的 Bean 工厂,也即 IOC 容器为开发者管理对象间的依赖关系提供了很多便利和基础服务,在 Spring 中有许多的 IOC 容器的实现供用户选择和使用,其相互关系如下:
其中BeanFactory 作为最顶层的一个接口类,它定义了 IOC 容器的基本功能规范, BeanFactory 有三个子类: ListableBeanFactory 、 Hierarc hicalBeanFactory 和 AutowireCapableBeanFactory 。但是从上图中我们可以发现最终的默认实现类是DefaultListableBeanFactory ,他实现了所有的接口。那为何要定义这么多层次的接口呢?查阅这些接口的源码和说明发现,每个接口都有他使用的场合,它主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。例如 ListableBeanFactory 接口表示这些 Bean 是可列表的,而 HierarchicalBeanFactory表示的是这些 Bean 是有继承关系的,也就是每个 Bean 有可能有父 Bean 。AutowireCapableBeanFactory 接口定义 Bean 的自动装配规则。这四个接口共同定义了 Bean 的集合、 Bean 之间的关系、以及 Bean 行为
最基本的IOC 容器接口 BeanFactory
public interface BeanFactory {
//对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
// 如果需要得到工厂本身,需要转义
String FACTORY_BEAN_PREFIX = "&";
// 根据bean的名字,获取在IOC容器中得到bean实例
Object getBean(String name) throws BeansException;
// 根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。
<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
//提供对bean的检索,看看是否在IOC容器有这个名字的bean
boolean containsBean(String name);
//根据bean名字得到bean实例,并同时判断这个bean是不是单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
//得到bean实例的Class类型
@Nullable
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
//得到bean的别名,如果根据别名检索,那么其原名也会被检索出来
String[] getAliases(String name);
}
在BeanFactory 里只对 IOC 容器的基本行为作了定义,根本不关心你的 Bean 是如何定义怎样加载的。正如我们只关心工厂里得到什么的产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心。
而要知道工厂是如何产生对象的,我们需要看具体的 IOC 容器实现, Spring 提供了许 多 IOC 容器的实现。比如 XmlBeanFactory ClasspathXmlApplicationContext 等。其中 XmlBeanFactory就是针对最基本的 IOC 容器的实现,这个 IOC 容器可以读取 XML 文件定义的 BeanDefinition XML文件中对 bean 的描述) 如果说 XmlBeanFactory 是容器中的屌丝, ApplicationContext 应该算容器中的高帅富
ApplicationContext 是 Spring 提供的一个高级的 IOC 容器,它除了能够提供 IOC 容器的基本功能外, 还为用户提供了以下的附加服务。
从ApplicationContext 接口的实现,我们看出其特点:
1. 支持信息源,可以实现国际化。(实现 MessageSource 接口)
2. 访问资源。 实现 ResourcePatternResolver 接口,后面章节会讲到
3. 支持应用事件。 实现 ApplicationEventPublisher 接口
(2)BeanDefinition
SpringIOC 容器管理了我们定义的各种 Bean 对象及其相互的关系, Bean 对象在 Spring 实现中是以 BeanDef inition 来描述的,其继承体系如下:
Bean的解析过程非常复杂,功能被分的很细,因为这里需要被扩展的地方很多,必须保证有足够的灵活性,以应对可能的变化。 Bean 的解析主要就是对 Spring 配置文件的解析。这个解析过程主要通过下图中的类完成: