如何从应用程序上下文programmaticaly创建spring xml配置文件?

时间:2017-04-10 08:50:43

标签: xml spring configuration-files applicationcontext

我已经在spring spring应用程序上下文中以编程方式加载了bean定义。 (xml配置为空)。我需要在这里做相反的过程。目前我已经使用bean定义加载了上下文。现在我想将这些转换为xml配置文件。 有人知道怎么做吗?

下面给出的是样本方法。

static ApplicationContext appContext = new ClassPathXmlApplicationContext("beans.xml"); //beans.xml has no bean definitions
AutowireCapableBeanFactory factory = appContext.getAutowireCapableBeanFactory();
BeanDefinitionRegistrry registry = (BeanDefinitionRegistry) factory;
GenericBeanDefinition beanDefinition;

public void registerBeanDefintions(List<SimpleField> simpleFields) {
if (null != simpleFields) {
String beanId;
for (SimpleField simpleField : simpleFields) {
beanId = simpleField.getDataField().replace(".", "_");
beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(SimpleField.class);
beanDefinition.setAutowireCandidate(true);
MutablePropertyValues values = new MutablePropertyValues();
values.add("engineFields", simpleField.getEngineFields());
values.add("dataField", simpleField.getDataField());
values.add("fieldDataType", simpleField.getFieldDataType());
values.add("setDefaultValueIfNull", simpleField.getSetDefaultValueIfNull());
beanDefinition.setPropertyValues(values);
if (!factory.containsBean(beanId)) {
registry.registerBeanDefinition(beanId, beanDefinition);                factory.autowireBeanProperties(this,AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
}}}}

的beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">



</beans>

加载的bean可以作为appContext.getBean(&#34; beanName&#34;)访问。

1 个答案:

答案 0 :(得分:0)

最后,解决方案就在这里!我们来看看吧。

问题陈述

众所周知,在spring应用程序中,我们通过'ApplicationContext'提供配置信息。 Spring框架提供了多个类来实现此接口,并帮助我们在应用程序中使用配置信息,而ClassPathXmlApplicationContext就是其中之一。通常在这种情况下,所有bean定义都在一个独立的xml文件中配置,通常称为“application-context.xml”。

但是,在较大的项目结构中,最佳做法是保留多个弹簧配置文件,以便于将所有内容堆叠到一个文件中,从而易于维护和模块化。在这种情况下,最好的办法是将所有Spring bean配置文件组织到一个XML文件中,然后导入其中的所有文件。此外,在应用程序上下文中,我们加载此单个xml文件。

现在如果要创建的配置文件数量超大怎么办?比方说,接近100或更多?

现在这是一个单调乏味的蜗牛工作!是时候找到自动化这个过程的路径了。 让我们想一想我们在外部源中拥有所有必需数据的情况,例如excel表。现在我们需要从工作表中读取数据并自动生成接近100个弹簧配置文件。

如何自动执行此流程? JAXB救援

JAXB有一个绑定编译器。 JAXB XJC模式绑定编译器将源XML模式转换或绑定到Java编程语言中的一组JAXB内容类。

  1. 查找需要在生成的xml中引用的xml架构 - http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  2. 在浏览器中点击此网址以获取xsd。现在将它保存在某个位置(如spring.xsd)。
  3. 下载jaxbri包并设置环境路径变量。如果是maven项目,请包含jaxb-ri和jaxb-core的依赖项。
  4. 从spring.xsd所在的文件夹中执行命令xjc.exe spring.xsd。 这将生成与xsd相关联的类。
  5. 执行命令时,如果“已定义属性”错误,需要执行哪些操作?

    可能会出现一个例外情况,即“已定义属性”。如果是这样,可以通过创建绑定文件来解决该问题,以覆盖抛出异常的属性。

    绑定文件

    <jxb:bindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        version="1.0">
    
        <jxb:bindings schemaLocation="http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" node="/xs:schema">
    
    <!-- Resolve:
    [ERROR] Property "Ref" is already defined. Use &lt;jaxb:property> to resolve this conflict.
      line 975 of file:/home/dw/sandbox/BRZtests/src/jaxb/spring25.xsd
    
    [ERROR] Property "Value" is already defined. Use &lt;jaxb:property> to resolve this conflict.
      line 977 of file:/home/dw/sandbox/BRZtests/src/jaxb/spring25.xsd
      -->
            <jxb:bindings node="//xs:complexType[@name='propertyType']">
                <jxb:bindings node=".//xs:attribute[@name='ref']">
                    <jxb:property name="refAttribute"/>
                </jxb:bindings>
                <jxb:bindings node=".//xs:attribute[@name='value']">
                    <jxb:property name="valueAttribute"/>
                </jxb:bindings>
            </jxb:bindings>
    <!--
    [ERROR] Property "Ref" is already defined. Use &lt;jaxb:property> to resolve this conflict.
      line 577 of file:/home/dw/sandbox/BRZtests/src/jaxb/spring25.xsd
    
    [ERROR] The following location is relevant to the above error
      line 606 of file:/home/dw/sandbox/BRZtests/src/jaxb/spring25.xsd
    
    [ERROR] Property "Value" is already defined. Use &lt;jaxb:property> to resolve this conflict.
      line 579 of file:/home/dw/sandbox/BRZtests/src/jaxb/spring25.xsd
    
    [ERROR] The following location is relevant to the above error
      line 613 of file:/home/dw/sandbox/BRZtests/src/jaxb/spring25.xsd
    
    -->
            <jxb:bindings node="//xs:element[@name='constructor-arg']">
                <jxb:bindings node=".//xs:attribute[@name='ref']">
                    <jxb:property name="refAttribute"/>
                </jxb:bindings>
                <jxb:bindings node=".//xs:attribute[@name='value']">
                    <jxb:property name="valueAttribute"/>
                </jxb:bindings>
            </jxb:bindings>
    
    <!--
    [ERROR] Property "Key" is already defined. Use &lt;jaxb:property> to resolve this conflict.
      line 1063 of file:/home/dw/sandbox/BRZtests/src/jaxb/spring25.xsd
    
    [ERROR] The following location is relevant to the above error
      line 1066 of file:/home/dw/sandbox/BRZtests/src/jaxb/spring25.xsd
    -->
            <jxb:bindings node="//xs:complexType[@name='entryType']">
                <jxb:bindings node=".//xs:attribute[@name='key']">
                    <jxb:property name="keyAttribute"/>
                </jxb:bindings>
            </jxb:bindings>
        </jxb:bindings>
    </jxb:bindings>
    

    使用以下命令解析架构并生成类。

    xjc -b spring25.xjb -verbose -xmlschema http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

    将生成与xsd关联的所有类。现在创建一个Bean实例并对其进行编组。这将生成带有所需输出的xml文件。

    示例代码 - 在生成的类的文件夹中创建的测试类

    package org.springframework.schema.beans;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.URISyntaxException;
    import java.util.ArrayList;
    
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.JAXBException;
    import javax.xml.bind.Marshaller;
    import javax.xml.namespace.QName;
    
    import org.springframework.util.CollectionUtils;
    
    import com.hrb.leap.bean.SpringConfigGenerator;
    
    public class Test {
        public static void main(String[] args) throws JAXBException {
            ObjectFactory factory = new ObjectFactory();
            JAXBContext context = JAXBContext.newInstance("org.springframework.schema.beans");
    
            /*
             * Create the root element 'Beans'
             * Set the required schema properties
             */
            Beans rootElement = factory.createBeans();
            rootElement.getOtherAttributes().put(new QName("xmlns:xsi"), "http://www.w3.org/2001/XMLSchema-instance");
            rootElement.getOtherAttributes().put(new QName("xsi:schemaLocation"), "http://www.springframework.org/schema/beans spring-beans-3.2.xsd");
    
            /*
             * How to import resources
             * How to define list of reference beans
             */
            java.util.List<String> resources = new ArrayList<>();
            resources.add("ResourceOne");
            resources.add("ResourceTwo");
            resources.add("ResourceThree");
    
            resources.forEach(resourceName -> {
                Import importResource = new Import();
                importResource.setResource(resourceName+".xml");
                rootElement.getImportOrAliasOrBean().add(importResource);
            });
    
            Bean bean = factory.createBean();
            bean.setId("id");
            bean.setClazz("java.util.ArrayList");
            if (!CollectionUtils.isEmpty(resources)) {
                ConstructorArg constructorArgs = factory.createConstructorArg();
                org.springframework.schema.beans.List listOfResources = new org.springframework.schema.beans.List();
                resources.forEach(referenceFormName -> {
                    Ref refBean = new Ref();
                    refBean.setBean(referenceFormName);
                    listOfResources.getBeanOrRefOrIdref().add(refBean);
                });
                constructorArgs.setList(listOfResources);
                bean.getMetaOrConstructorArgOrProperty().add(constructorArgs);
            }
            rootElement.getImportOrAliasOrBean().add(bean);
    
            /*
             * Sample bean definition to show how to store list of values as a property
             */
                Bean simpleBean = factory.createBean();
                simpleBean.setId("SimpleBean");
                simpleBean.setClazz("com.packagename.ClassName");
    
                PropertyType firstProperty= factory.createPropertyType();
                firstProperty.setName("listOfValuesDemo");
    
                java.util.List<String> listOfValues = new ArrayList<>();
                listOfValues.add("ValueOne");
                listOfValues.add("ValueTwo");
                listOfValues.add("ValueThree");
    
                org.springframework.schema.beans.List listToStoreValues = new org.springframework.schema.beans.List();
                listOfValues.forEach(name -> {
                     Value value = factory.createValue();
                     value.getContent().add(name);
                     listToStoreValues.getBeanOrRefOrIdref().add(value);
                 });
                firstProperty.setList(listToStoreValues);
                //Add the property to the bean.
                simpleBean.getMetaOrConstructorArgOrProperty().add(factory.createProperty(firstProperty));
                // Add the bean under the root element 'beans'
                rootElement.getImportOrAliasOrBean().add(simpleBean);
    
            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty("jaxb.formatted.output",Boolean.TRUE);
            createXmlConfiguration(marshaller , "output", rootElement);
        }
    
        /*
         * Method create the xml under the 'src/main/resources' folder in the project.
         */
        public static void createXmlConfiguration (Marshaller marshaller , String fileName, Beans rootElement) {
            try {
                java.net.URL url = SpringConfigGenerator.class.getResource("/");
                File fullPathToSubfolder = new File(url.toURI()).getAbsoluteFile();
                String projectFolder = fullPathToSubfolder.getAbsolutePath().split("target")[0];
                // TODO - Destination folder to be configured
                File outputFile = new File(projectFolder + "src/main/resources/" + "/"+fileName+".xml");
                if (!outputFile.exists()) {
                    outputFile.createNewFile();
                }
                OutputStream os = new FileOutputStream(outputFile);
                marshaller.marshal(rootElement, os);
            } catch (URISyntaxException uriException) {
    
            } catch (IOException ioException) {
    
            } catch (JAXBException jaxbException) {
    
            }
    
        }
    }
    

    <强>输出

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <beans xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans spring-beans-3.2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <import resource="ResourceOne.xml"/>
        <import resource="ResourceTwo.xml"/>
        <import resource="ResourceThree.xml"/>
        <bean class="java.util.ArrayList" id="id">
            <constructor-arg>
                <list>
                    <ref bean="ResourceOne"/>
                    <ref bean="ResourceTwo"/>
                    <ref bean="ResourceThree"/>
                </list>
            </constructor-arg>
        </bean>
        <bean class="com.packagename.ClassName" id="SimpleBean">
            <property name="listOfValuesDemo">
                <list>
                    <value>ValueOne</value>
                    <value>ValueTwo</value>
                    <value>ValueThree</value>
                </list>
            </property>
        </bean>
    </beans>
    

    按照以下步骤查看示例输出

    1. 点击浏览器中的架构网址获取xsd。现在将其保存在某个位置(例如: - spring.xsd)。
    2. 下载jaxbri包并设置环境路径变量。
    3. 设置jaxb库的类路径和当前路径(点),例如(在IDE中执行此命令提示符或equalant)         set classpath = C:\ folder_name \ jaxb-ri \ lib;。;
    4. 将生成的类提取到命令下运行的文件夹(从cmd中提取的文件夹中)后,编译“Test”类。 javac folder_name \ Test.java
    5. 最后运行程序。 java folder_name.Test 注意: - 输出将在控制台中打印,如果'createXmlConfiguration(marshaller,&#34; output&#34;,rootElement);'替换为'marshaller.marshal(rootElement,System.out);'
    6. <强>优点

      • 努力减少了很多。考虑到我必须手动配置的bean定义的复杂性,一个人最少需要20-25天来配置接近85个文件(考虑9小时/天),这可能会达到225小时。但是,上述工具只需不到3秒钟即可完成。
      • 如果将来要进行微小的配置更改,我们可以单独使用特定文件并进行更正。

      替代方法

      如果配置文件的数量非常少,我们可以尝试动态加载具有所有bean定义的上下文,而不生成物理xml文件。这可以通过以编程方式加载spring上下文来实现,并在需要时运行应用程序。

      缺点

      • 记忆
      • 性能
      • 数据源中的小错误会产生很大的影响。
      • 冒险在生产环境中即时运行。
      • 不建议,如果数据源几乎保持不变。
      • 难以排除故障。