BeanFactory是Spring中十分重要的接口,也是Spring IOC容器的顶级接口。它基于工厂模式,定义了最基本的IOC容器的功能,如获取Bean实例、查看Bean的类型和查看Bean是否存在等:
在BeanFactory的基础上扩展了很多接口,每个接口都有各自的功能。BeanFactory的继承体系如下:
可以看出,Spring很好地贯彻了面向接口编程的原则,几乎所有的重要的类上面都定义了接口。而且,通过接口的继承,可以灵活地扩展出不同功能的接口。
对于不同来源的Resource,Spring都提供了对应的实现类,常用的有文件系统资源FileSystemResource和类路径资源ClassPathResource等。
BeanDefinition加载是Spring最重要的一个步骤,只有加载了所有定义的BeanDefinition后,才能根据其创建指定Bean,注入依赖,并完成后续一系列功能。BeanDefinition加载是在容器启动时自动完成的。
书中以XmlBeanFactory为例,讲解了BeanDefinition的加载和注册流程。虽然现在都以注解方式定义Bean,XML文件方式很少使用,但两种方式只是BeanDefinition的来源不同,核心处理流程是类似的,因此仍然以书中的内容为准。至于注解方式加载BeanDefinition的流程,如果感兴趣可以看下AnnotationConfigApplicationContext类。
XmlBeanFactory加载BeanDefinition的流程大致可以分为三个核心步骤:
可以显式指定BeanDefinition所在资源的位置,如书中代码所示:
Resource resource = new ClassPathResource("applicationContext.xml");
XmlBeanFactory beanFactory = new XmlBeanFactory(resource);
这样显式Resource的方式省去了资源定位的步骤,但是,实际上没有这么用的,现在使用的都是ApplicationContext接口,其加载资源的处理在AbstractRefreshableApplicationContext#refreshBeanFactory()中,后面章节有具体叙述。
不管基于何种方式,现在拿到了BeanDefinition所在的资源文件Resource,则创建XmlBeanFactory,执行BeanDefinition解析的工作。
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
//加载配置文件
this.reader.loadBeanDefinitions(resource);
}
XmlBeanFactory在维护了一个XmlBeanDefinitionReader实例,其功能就是从XML配置文件中解析出BeanDefinition。XmlBeanDefinitionReader是BeanDefinitionReader接口的实现类,BeanDefinitionReader接口的作用就是解析BeanDefinition。
解析过程中的核心类:
XmlBeanFactory并没有自己完成BeanDefinition解析的工作,而是委托给各种不同的类去处理,每个类只关注一项具体的功能,这也是单一职责原则的很好的体现。
加载BeanDefinition流程:
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
//BeanDefinitionParserDelegate代理对象,主要用于BeanDefinition的解析与注册
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
//profile属性处理,只解析满足当前profile的BeanDefinition
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
//解析前置处理,模板方法,留给子类实现
preProcessXml(root);
//实际的BeanDefinition解析与注册
parseBeanDefinitions(root, this.delegate);
//解析前置处理,模板方法,留给子类实现
postProcessXml(root);
this.delegate = parent;
}