前言
从这篇文章开始我会去探索一下Spring中IOC机制的一些底层实现,至于IOC(控制反转)是什么在这里不多做介绍,网上的资料也很多。
IOC(控制反转)是Spring框架中最核心的机制,所以我们需要对其实现原理有一定的理解,才能更好的使用它甚至自己设计一个类似Spring的简单框架。这篇文章我们先不管其运行流程,而是先来看一下他的两个重要的接口,只有先把这些接口弄明白了,我们才能理解IOC机制的工作流程及原理。
BeanFactory
package org.springframework.beans.factory;
import org.springframework.beans.BeansException;
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
T getBean(String name, Class requiredType) throws BeansException;
T getBean(Class requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
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);
}
这个便是spring核心的Bean工厂定义,上面的author说是2001年写的,已经历史久远了, 这个类是spring中所有bean工厂,也就是俗称的IOC容器的祖宗,各种IOC容器都只是它的实现或者为了满足特别需求的扩展实现。 从上面的方法就可以看出,这些工厂的实现最大的作用就是根据bean的名称亦或类型等等,来返回一个bean的实例。
BeanFactory
BeanFactory,以Factory结尾,表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂。在Spring中, BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。
ApplicationContext接口
它由BeanFactory接口派生而来,ApplicationContext包含BeanFactory的所有功能,通常建议比BeanFactory优先。
ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,ApplicationContext包还提供了以下的功能:
- MessageSource, 提供国际化的消息访问
- 资源访问,如URL和文件
- 事件传播
- 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层;
对BeanFactory的思考
一个工厂如果想拥有这样的功能,那么它一定需要以下几个因素:
1、 需要持有各种bean的定义,否则无法正确的完成bean的实例化。
2、 需要持有bean之间的依赖关系,否则在bean实例化的过程中也会出现问题。例如,A包含了B的实例。但是在A初始化之后,调用B实例的方法时,就会报空指针异常,因为A并没有被真正的正确初始化。
3、 以上两种都要依赖于我们所写的依赖关系的定义,暂且认为是XML文件(其实可以是各种各样的),那么我们需要一个工具来完成XML文件的读取。
我目前想到的,只需要满足以上三种条件,便可以创建一个bean工厂,来生产各种bean。当然,spring肯定有更高级的做法,以上只是我直观的去想如何实现IOC。
那么从上面的描述中,我又引申出了另一个核心问题,Bean的定义是什么,他的依赖关系又如何描述?
那么答案是,一个祖宗级别的接口,来看BeanDefinition。
BeanDefinition
package org.springframework.beans.factory.config;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.core.AttributeAccessor;
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
String getParentName();
void setParentName(String parentName);
String getBeanClassName();
void setBeanClassName(String beanClassName);
String getFactoryBeanName();
void setFactoryBeanName(String factoryBeanName);
String getFactoryMethodName();
void setFactoryMethodName(String factoryMethodName);
String getScope();
void setScope(String scope);
boolean isLazyInit();
void setLazyInit(boolean lazyInit);
String[] getDependsOn();
void setDependsOn(String[] dependsOn);
boolean isAutowireCandidate();
void setAutowireCandidate(boolean autowireCandidate);
boolean isPrimary();
void setPrimary(boolean primary);
ConstructorArgumentValues getConstructorArgumentValues();
MutablePropertyValues getPropertyValues();
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
int getRole();
String getDescription();
String getResourceDescription();
BeanDefinition getOriginatingBeanDefinition();
}
接口上给出的注释简明扼要的描述了该接口: BeanDefinition描述了一个bean实例,它具有属性值,构造函数参数值以及具体实现提供的更多信息。
可以看到上面的很多属性和方法都很熟悉,例如类名、scope、属性、构造函数参数列表、依赖的bean、是否是单例类、是否是懒加载等,其实就是将Bean的定义信息存储到这个BeanDefinition相应的属性中,后面对Bean的操作就直接对BeanDefinition进行,例如拿到这个BeanDefinition后,可以根据里面的类名、构造函数、构造函数参数,使用反射进行对象创建。 BeanDefinition是一个接口,是一个抽象的定义,实际使用的是其实现类,如ChildBeanDefinition、RootBeanDefinition、GenericBeanDefinition等。
继承关系
BeanDefinition这个接口便是spring中的bean定义接口,所以其实我们工厂里持有的bean定义,就是一堆这个玩意,或者是他的实现类和子接口。这个接口并非直接的祖宗接口,他所继承的两个接口一个是core下面的AttributeAccessor,继承这个接口就以为这我们的bean定义接口同样具有处理属性的能力,而另外一个是beans下面的BeanMetadataElement,这个接口就是bean的元数据元素,它可以获得bean的配置定义的一个元素。在XML文件中来说,就是会持有一个bean标签。
BeanDefinition的一些依赖与实现,这里就不细致展开
(图片参考自 www.jianshu.com/p/1d06f6342…)
小结
本篇文章介绍了Spring实现IOC这一机制的最基础的两个接口BeanFactory和BeanDefinition。一个是生产Bean的工厂,一个是对Bean的定义,这两个接口以最基础的形式定义了Bean是什么以及是如何产生的,Spring在实际应用中使用的类或者接口很多也都是实现了这两个接口,如ApplicationContext、ChildBeanDefinition等等。