前言
上一章我们已经初步认识了BeanFactory和BeanDefinition,一个是IOC的核心工厂接口,一个是IOC的bean定义接口。
spring无法让BeanFactory持有一个Map<String,Object>来完成bean工厂的功能,是因为spring的初始化是可以控制的,可以到用的时候才将bean实例化供开发者使用,除非我们将bean的lazy-init属性设置为true,初始化bean工厂时采用延迟加载。
那么知道了上述两个接口,我相信不少人甚至不看源码都已经猜到spring是如何做的了。没错,就是让bean工厂持有一个Map<String,BeanDefinition>,这样就可以在任何时候我们想用哪个bean,取到它的bean定义,我们就可以创造出一个新的实例。
接口当然不可能持有这样一个对象,那么这个对象一定是在BeanFactory的某个实现类或者抽象实现类当中所持有的,来看DefaultListableBeanFactory。
一、源码分析
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
private static Class<?> javaUtilOptionalClass = null;
private static Class<?> javaxInjectProviderClass = null;
static {
try {
javaUtilOptionalClass =
ClassUtils.forName("java.util.Optional", DefaultListableBeanFactory.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
// Java 8 not available - Optional references simply not supported then.
}
try {
javaxInjectProviderClass =
ClassUtils.forName("javax.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - Provider interface simply not supported then.
}
}
/** Map from serialized id to factory instance */
private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =
new ConcurrentHashMap<String, Reference<DefaultListableBeanFactory>>(8);
/** Optional id for this factory, for serialization purposes */
private String serializationId;
/** Whether to allow re-registration of a different definition with the same name */
private boolean allowBeanDefinitionOverriding = true;
/** Whether to allow eager class loading even for lazy-init beans */
private boolean allowEagerClassLoading = true;
/** Optional OrderComparator for dependency Lists and arrays */
private Comparator<Object> dependencyComparator;
/** Resolver to use for checking if a bean definition is an autowire candidate */
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
/** Map from dependency type to corresponding autowired value */
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<Class<?>, Object>(16);
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
/** Map of singleton and non-singleton bean names, keyed by dependency type */
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);
/** Map of singleton-only bean names, keyed by dependency type */
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);
/** List of bean definition names, in registration order */
private volatile List<String> beanDefinitionNames = new ArrayList<String>(256);
/** List of names of manually registered singletons, in registration order */
private volatile Set<String> manualSingletonNames = new LinkedHashSet<String>(16);
/** Cached array of bean definition names in case of frozen configuration */
private volatile String[] frozenBeanDefinitionNames;
/** Whether bean definition metadata may be cached for all beans */
private volatile boolean configurationFrozen = false;
该类的属性就在这里了,至于方法此处被我省略,因为太长了…
看它名字就知道,这是一个默认的bean工厂实现类,根据类注释可以知道这是一个完整的,成熟的IOC容器。也就是说,如果你需要的功能非常单一,这个实现类已经足够可以满足你了,而以后如果你想要对spring的容器扩展,那么只需要扩展或者持有这个对象即可。
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
看到这一行,其实已经证明了我的猜测,它所注释的意思是bean定义的map对象,采用beanName作为key值。
只继承了一个抽象类,同时把集大成的接口ConfigurableListableBeanFactory给实现了,同时还有BeanDefinitionRegistry接口,从名字上看就知道是BeanDefinition的注册接口。
看到这里,思路已经很明确了,bean工厂的初始化其实就是往这个Map里填充东西。只要把我们XML文件中定义的bean都填充到这里,其实这个工厂就已经可以工作了。
那么从现在来看,我们需要什么才能把Map填充呢?也就是初始化bean工厂呢,或者说建立IOC容器。
二、IOC容器实现原理讨论
这次先不关注源码,先首先看看它的用法。
ClassPathResource res=new ClassPathResource("beans.xml");
DefaultListableBeanFactory factory=new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);
Performer performer=(Performer) factory.getBean("dancer");
performer.perform();
简单解释一下:
1、我们在beans.xml中定义了一个Bean,id为“dancer”,实现了Performer接口。参考自
2、利用Resource抽象实现类,来包装这个包含了BeanDefinition的定义信息。
3、创建一个BeanFactory,DefaultListableBeanFactory
4、创建一个载入BeanDefinition的读取器,通过回调配置给BeanFactory.
5、 从定义好的Resource中,读取配置信息。由XmlBeanDefinitionReader完成解析,完成整个载入和注册Bean定义的过程。
6、 通过BeanFactory的getBean()方法,获取对应的Bean。这里涉及到了Bean的实例化以及依赖注入
依赖注入的过程
以上过程可以看成是IOC容器初始化的过程,这个初始化过程完成的主要工作是完成BeanDefinition在IOC容器中的数据映射。而这里并没有实例化任何对象,也从来没有完成过依赖注入的过程。
依赖注入是通过getBean方法完成的,当然如果将lazy-init属性设置为true,则可以在初始化的过程中完成依赖注入,实现预实例化。
Performer performer=(Performer) factory.getBean("dancer");
通过getBean获得名为“dancer”的对象,而factory现在保有的仅仅是键为“dancer”的BeanDefinition对象(保存在Map中)。
而通过源码可以发现getbean()方法是由AbstractBeanFactory实现的,而具体实现又跳到了doGetBean()方法,
doGetBean()方法负责从Bean工厂中获取bean对象的具体实现,下面来看看该方法的具体实现:
1、 检查手动注册的单例集合缓存中是否含有该bean对象,若有,则取出返回,否则继续执行;
2、 检查该bean是否已经创建,从而判断是否属于循环引用,若是,抛出异常返回,否则继续执行;
3、 判断bean工厂中是否存在该bean definition,若存在,则取出返回,否则继续执行;
4、 初始化该bean所依赖的bean对象;
5、 判断该bean是否是单例模式(singleton),若是,创建单例对象,否则继续执行;
6、 判断该bean是否是原型模式(prototype),若是,创建原型对象,否则继续执行;
7、 创建自定义类型(scope)bean对象。
8、 从上面对doGetBean方法分析,可看出创建并获取bean对象是一个非常复杂的过程,并不是简简单单的放入Map中再从其中取出。
三、小结
整篇文章下来,可以看到DefaultListableBeanFactory实现了IOC容器的初始化并且通过getbean()完成了依赖注入。整个IOC容器初始化过程总结起来就是定位(定位到配置文件)、解析(解析配置文件,一般是XML)、注册(将读出来的数据放到map中)。
这篇文章里我并没有仔细记录源码的执行过程,因为内容实在是太多,我只是通过一个demo讲述了DefaultListableBeanFactory获取一个bean的大概过程。具体源码执行过程还需要各位读者自己去探索,我也是自己通过源码把这个过程探索了一遍才知道IOC容器初始化的过程,不过其中有些地方还没有完全领悟,待自己有所提升后再回来看看应该会有不一样的感受。
依赖注入过程参考自