spring读取xml生成BeanDefinion时的扩展点
来源:互联网 发布:2016年鞍山中考大数据 编辑:程序博客网 时间:2024/05/29 06:51
spring读取xml生成beanDefinion时的扩展点(虽然基本上用不到,但既然看到了还是记录一下(┬_┬))
通常在我们的web项目中spring的上下文实现类是XmlWebApplicationContext类。
比如org.springframework.web.context.ContextLoader#determineContextClass
protected Class<?> determineContextClass(ServletContext servletContext) { String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM); if (contextClassName != null) { try { return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader()); } catch (ClassNotFoundException ex) { throw new ApplicationContextException( "Failed to load custom context class [" + contextClassName + "]", ex); } } else { contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); try { return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader()); } catch (ClassNotFoundException ex) { throw new ApplicationContextException( "Failed to load default context class [" + contextClassName + "]", ex); } }}
在web中配置的ContextLoaderListener启动之后会调用上面的方法确定使用什么Context实现类,如果没有额外配置的话会使用默认的XmlWebApplicationContext。
org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory
@Overrideprotected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); //此处会加载BeanDefinitions loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); }}
在AbstractRefreshableApplicationContext的refreshBeanFactory方法中会加载所有的BeanDefinitions。
然后我们看到XmlWebApplicationContext实现了AbstractRefreshableApplicationContext的loadBeanDefinitions方法。
org.springframework.web.context.support.XmlWebApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader);}
在上面的方法中XmlWebApplicationContext创建了一个XmlBeanDefinitionReader类用于读取xml中的数据。
spring加载beanDefinion都是通过AbstractBeanDefinitionReader抽象类来加载的,AbstractBeanDefinitionReader继承了BeanDefinitionReader接口,而具体是什么介质并加载是由子类来实现BeanDefinitionReader接口的loadBeanDefinitions方法来做的。
AbstractBeanDefinitionReader的子类实现有三个分别是PropertiesBeanDefinitionReader、GroovyBeanDefinitionReader、XmlBeanDefinitionReader。
我们看到
由于XmlBeanDefinitionReader继承于AbstractBeanDefinitionReader,所以实现了BeanDefinitionReader接口的org.springframework.beans.factory.support.BeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource)方法。并且在该方法中最终会走到registerBeanDefinitions方法。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); documentReader.setEnvironment(this.getEnvironment()); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore;}
如上方法会调用createBeanDefinitionDocumentReader()方法获取BeanDefinitionDocumentReader对象,并调用该对象的registerBeanDefinitions()方法。我们的扩展点也就是在这个方法中扩展的。
@Overridepublic void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root);//此处调用下面的方法}protected void doRegisterBeanDefinitions(Element root) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { Assert.state(this.environment != null, "Environment must be set for evaluating profiles"); String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!this.environment.acceptsProfiles(specifiedProfiles)) { return; } } BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(this.readerContext, root, parent); preProcessXml(root);//在解析xml并注册BeanDefinition之前执行 parseBeanDefinitions(root, this.delegate); postProcessXml(root);//在解析xml并注册BeanDefinition之后执行 this.delegate = parent;}
spring有默认的BeanDefinitionDocumentReader接口实现类:DefaultBeanDefinitionDocumentReader。
我们看到DefaultBeanDefinitionDocumentReader类有两个没有任何实现的方法。
/** * Allow the XML to be extensible by processing any custom element types first, * before we start to process the bean definitions. This method is a natural * extension point for any other custom pre-processing of the XML. * <p>The default implementation is empty. Subclasses can override this method to * convert custom elements into standard Spring bean definitions, for example. * Implementors have access to the parser's bean definition reader and the * underlying XML resource, through the corresponding accessors. * @see #getReaderContext() */protected void preProcessXml(Element root) {}/** * Allow the XML to be extensible by processing any custom element types last, * after we finished processing the bean definitions. This method is a natural * extension point for any other custom post-processing of the XML. * <p>The default implementation is empty. Subclasses can override this method to * convert custom elements into standard Spring bean definitions, for example. * Implementors have access to the parser's bean definition reader and the * underlying XML resource, through the corresponding accessors. * @see #getReaderContext() */protected void postProcessXml(Element root) {}
preProcessXml()方法在解析xml注册beanDefinion()之前执行,postProcessXml()在之后执行。所以,我们要想在这两个步骤中做自己的处理就必须继承DefaultBeanDefinitionDocumentReader并实现preProcessXml()方法和postProcessXml()方法。
我们看到在org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinitions方法中会调用它的createBeanDefinitionDocumentReader()方法创建一个BeanDefinitionDocumentReader对象并返回。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();//这儿 documentReader.setEnvironment(this.getEnvironment()); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore;}
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));}
createBeanDefinitionDocumentReader()方法中是通过自身的documentReaderClass属性来确定了创建对象类型。所以,我们可以通过XmlBeanDefinitionReader类的setDocumentReaderClass(Class documentReaderClass)方法来改变这个属性为我们自己定义的继承了DefaultBeanDefinitionDocumentReader并实现了preProcessXml()方法和postProcessXml()方法的类的类型。
public void setDocumentReaderClass(Class<?> documentReaderClass) { if (documentReaderClass == null || !BeanDefinitionDocumentReader.class.isAssignableFrom(documentReaderClass)) { throw new IllegalArgumentException( "documentReaderClass must be an implementation of the BeanDefinitionDocumentReader interface"); } this.documentReaderClass = documentReaderClass;}
我们知道在初始化容器并调用org.springframework.web.context.support.XmlWebApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)这个方法的时候会创建一个XmlBeanDefinitionReader对象。
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader);}
在上面的方法中提供了org.springframework.web.context.support.XmlWebApplicationContext#initBeanDefinitionReader方法来初始化XmlBeanDefinitionReader对象,所以我们可以继承XmlWebApplicationContext类来实现initBeanDefinitionReader()方法,并在该方法中调用传进去的XmlBeanDefinitionReader对象的setDocumentReaderClass()方法来设置我们自定义的继承BeanDefinitionDocumentReader并实现preProcessXml()方法和postProcessXml()方法的类类型。
最后一步就是在web.xml中显示配置contextClass变量为继承了XmlWebApplicationContext的自定义容器类类型。
比如:
<context-param> <param-name>contextClass</param-name> <param-value>com.explore.develop.MyXmlWebApplicationContext</param-value></context-param>
当然springMVC的容器是另外一个容器,只是在初始化的时候会把ContextLoaderListener加载的容器指定为父容器。如果想要springMVC容器在加载beanDefinion的时候也执行扩展点,也需要指定它的contextClass变量。如下:
<servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/spring/spring-mvc.xml</param-value> </init-param> <init-param> <param-name>contextClass</param-name> <param-value>com.explore.develop.MyXmlWebApplicationContext</param-value> </init-param> <load-on-startup>1</load-on-startup></servlet>
总结
实现扩展spring读取xml生成beanDefinion时的扩展点的步骤为:
1. 继承DefaultBeanDefinitionDocumentReader并实现preProcessXml()方法和postProcessXml()。
2. 继承XmlWebApplicationContext类并重写initBeanDefinitionReader()方法。
3. 在重写了XmlWebApplicationContext的initBeanDefinitionReader()方法中,调用XmlBeanDefinitionReader对象的setDocumentReaderClas()方法设置我们在第1步继承DefaultBeanDefinitionDocumentReader的子类类型。
4. web.xml中配置contextClass变量类型为第2步自定义的XmlWebApplicationContext类的子类
- spring读取xml生成BeanDefinion时的扩展点
- Spring的XML文件的Schema扩展点PluggableSchemaResolver
- 读取生成的xml
- Spring Container的扩展点
- spring之扩展点
- spring-扩展点-BeanPostProcessor
- 基于schema的spring xml namespace扩展
- 基于schema的spring xml namespace扩展
- DOM模型的XML文件生成读取
- DOM模型的XML文件生成读取
- Java 如何读取sqlserver生成的xml
- 安卓中xml的读取与生成
- [Spring]Spring容器扩展点
- spring xml扩展
- Spring之模拟XML的读取
- spring读取xml的两种方法
- 读取与生成XML
- xml读取和生成
- pyhook监听鼠标事件和键盘事件
- C语言知识点
- 普通SQL注入
- easyUI的使用待修改
- 编写web测试用例
- spring读取xml生成BeanDefinion时的扩展点
- live templates语法
- 前后端分离的交互式开发模式
- Selenium-java(XML-元素管理篇)
- Android面试题-Android源码编译实现静默安装和静默偷拍
- Vijos P1772 巧妙填数【进制+置换】
- [李景山php] 深入理解PHP内核[读书笔记]--第三章:变量及数据类型--变量的结构和类型
- [svc]免费ssl实践
- 用户、组或角色 在当前数据库中已存在