32、深入解析spring技术$二
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 重载了几次,完成对容器的资源文件定位、加载
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)); } }
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));