32、深入解析spring技术$2

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));

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值