DefaultListableBeanFactory:从上章的第3张图片中可以看出,几个实现类都引用了这个类,XmlBeanFactory继承了这个类,我们来看下这个DefaultListableBeanFactory类:它实现了BeanDefinitionRegistry、ConfigurableListableBeanFactory、AbstractAutowireCapableBeanFactory、Serializable接口,和引用了其他的依赖类;
创建一个IoC容器就要使用DefaultListableBeanFactory这个类:
1、创建配置文件,如beans.xml;
2、创建BeanFactory,都会引用或继承DefaultListableBeanFactory;
3、创建资源加载器,如Resource接口;
4、解析、注入资源配置信息,IoC建立成功,就可以直接使用了;
ApplicationContext:
在spring中,spring已经提供了多种ioc容器,BeanFactory是基本的容器,常用ApplicationContext作为容器。
扩展MessageSource接口,这个接口支持国际化语言;
扩展ResourceLoader接口,ResourceLoader是依赖Resource接口的,获得不同地方的Bean定义资源;
扩展ApplicationEventPublisher接口,在容器中引入事件机制,事件与生命周期结合动态管理Bean;
扩展BeanFactory,使功能更丰富;
以FileSystemXmlApplicationContext作为ApplicationContext的实现类,来详解:
FileSystemXmlApplicationContext的构造方法最终都会调用这个构造方法:
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
//public void setParent(ApplicationContext parent) {this.parent = parent;
setConfigLocations(configLocations);
//处理传来的beans.xml字段,并保存给configLocations[];若为空,默认为ApplicationContext.xml,保存之后供refresh()调用;
if (refresh) {
refresh();
//得到beans.xml的配置文件信息
}
}
super(parent);这个方法在AbstractApplicationContext的构造方法设置;
setConfigLocations在AbstractRefreshableConfigApplicationContext定义
refresh :true / false;
refresh()在AbstractApplicationContext中定义
FileSystemXmlApplicationContext获取资源的方法:
@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
refresh()方法:
@Override
public void refresh() throws BeansException, IllegalStateException {
//private final Object startupShutdownMonitor = new Object();
synchronized (this.startupShutdownMonitor) {
//获取currenttime,验证属性,设置容器同步
prepareRefresh();
//refreshBeanFactory();销毁已存在的容器,创建新容器,并绑定id,设置同步;getBeanFactory();获得存在的容器
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//配置类加载器,运行处理器,配置依赖属性;
prepareBeanFactory(beanFactory);
try {
//所有的配置资源将被加载,还没有允许注册,但允许注册特殊beanpostprocessors(运行处理器)等在当前的容器中实现。
//注册、指定beanpostprocessors
postProcessBeanFactory(beanFactory);
//调用注册了的beanpostprocessors(运行处理器)
invokeBeanFactoryPostProcessors(beanFactory);
//实例化注册了的beanpostprocessors(运行处理器)
registerBeanPostProcessors(beanFactory);
//初始化MessageSource
initMessageSource();
initApplicationEventMulticaster();
//子类特定加载方法
onRefresh();
//注册事件监听器
registerListeners();
//对容器lazy-init属性进行处理的入口方法
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}catch (BeansException ex) {
destroyBeans();
cancelRefresh(ex);
throw ex;
}}}
$2、refresh()与IoC容器的初始化:
当执行refresh()这个方法时就会启动一个IoC容器,也就是说在new FileSystemXmlApplicationContext(String str)或其他构造方法时(都会调用上面讲到的那个构造方法),都会创启动一个IoC容器;
启动一个IoC就包括BeanDefinition(这里可以把BeanDefinition理解一个beans.xml配置文件)定位,载入和注册;这章的主要内容就是分析:定位、载入和注册;
定位:在上章中讲解了Resource、ResurceLoader如可找到一个配置文件(相对路径、绝对路径、URL路径、字节数组),
载入:通过定位读取到了这些配置文件,比如定义了一个<bean id='skx' class='org.skx.api'><property name='name' value='skx'/></bean>,根据这样的配置去执行它所表示的意思;
注册:注册时通过BeanDefinitionRegistry接口完成的,本章开头部分讲过,IoC具体实现类都引用或继承了DefaultListableBeanFactory类,而DefaultListableBeanFactory实现了BeanDefinitionRegistry接口,所以,所以实现类都能通过BeanDefinitionRegistry接口完成注册;
FileSystemXmlApplicationContext继承AbstractXmlApplicationContext;在这个父类的loadBeanDefinitions()方法:
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//初始化读取器
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//设置读取器
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//启动、加载读取器
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
最后执行了loadBeanDefinitions(beanDefinitionReader);
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//这个getConfigResources()方法就是与构造器中的setConfigLocations(configLocations)对应
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
这里最后执行的是 reader.loadBeanDefinitions(configLocations);参数是Resource或String:
AbstractBeanDefinitionReader.
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
for (Resource resource : resources) {
counter += loadBeanDefinitions(resource);
}
return counter;
}
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
最后:XmlBeanDefinitionReader. 继承 AbstractBeanDefinitionReader.
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
doLoadDocument(inputSource, resource);
registerBeanDefinitions(doc, resource);
这个
loadBeanDefinitions()方法 从beanFactory到reader到resource再到encodeResource 重载了几次,完成对容器的资源文件定位、加载
上个方法中的最后一步:
如何将这些(个)资源文件进行解析和转换为容器数据的,这个过程由XmlBeanDefinitionReader.registerBeanDefinitions(doc,resource)完成;
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//documentReader 将完成对资源文件的解析,
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); //BeanDefinitionDocumentReader
documentReader.setEnvironment(this.getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
图1.
图2.这里所说的document对象是指文档对象,包括doc、xml、html,
BeanDefinitionParserDelegate负责解析
图3.
documentReader是将得到的document对象按照spring的Bean规则进行解析,解析之后的结果由BeanDefinitionHolder对象持有;
接着上面的
XmlBeanDefinitionReader.
registerBeanDefinitions() {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();方法:
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); //类型转换--->父接口
}
private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
再来看
DefaultBeanDefinitionDocumentReader.processBeanDefinition()方法:
//ele对应在Spring BeanDefinition中定义的XML元素
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//通过spring规则解析,bdHolder 获得解析后的结果
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//bdHolder持有这些数据,在内存中,
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex);
}
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);的代码清单:
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
里面包含了如何处理<bean></bean>元素信息:id、name、aliase等,把这些元素值读出来设置到BeanDefinitionHoler中去;对于其他配置,如bean的属性配置,通过一个较为复杂的解析过程完成,但解析完成后一并放入BeanDefinitionHoler中;返回一
个
BeanDefinitionHoler实例;
在AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);这个方法里:就是对BeanDefinition数据分析和载入的过程
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
parseConstructorArgElements(ele, bd);
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));