IOC(二)DefaultListableBeanFactory

2,493 阅读6分钟

前言

上一章我们已经初步认识了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接口。参考自<Spring in action>例子.
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容器初始化的过程,不过其中有些地方还没有完全领悟,待自己有所提升后再回来看看应该会有不一样的感受。


依赖注入过程参考自