9

Spring 有一个非常方便的名为PropertyPlaceholderConfigurer的类,它采用标准的 .properties 文件并将其中的值注入到您的 bean.xml 配置中。

有谁知道一个做完全相同的事情的类,并以相同的方式与 Spring 集成,但接受 XML 文件进行配置。具体来说,我正在考虑 Apache 消化器风格的配置文件。这样做很容易,我只是想知道是否有人已经拥有。

建议?

4

4 回答 4

7

我刚刚对此进行了测试,它应该可以正常工作。

PropertiesPlaceholderConfigurer 包含一个 setPropertiesPersister 方法,因此您可以使用自己的PropertiesPersister子类。默认的 PropertiesPersister 已经支持 XML 格式的属性。

只是为了向您展示完整的工作代码:

JUnit 4.4 测试用例:

package org.nkl;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@ContextConfiguration(locations = { "classpath:/org/nkl/test-config.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
public class PropertyTest {

    @Autowired
    private Bean bean;

    @Test
    public void testPropertyPlaceholderConfigurer() {
        assertNotNull(bean);
        assertEquals("fred", bean.getName());
    }
}

弹簧配置文件test-config.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"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
">
  <context:property-placeholder 
      location="classpath:/org/nkl/properties.xml" />
  <bean id="bean" class="org.nkl.Bean">
    <property name="name" value="${org.nkl.name}" />
  </bean>
</beans>

XML 属性文件properties.xml- 有关使用说明,请参见此处

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
  <entry key="org.nkl.name">fred</entry>
</properties>

最后是 bean:

package org.nkl;

public class Bean {
    private String name;
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

希望这可以帮助...

于 2009-01-26T16:32:28.933 回答
4

发现 Spring Modules 提供了 Spring 和 Commons Configuration 之间的集成,它具有层次结构的 XML 配置样式。这直接与 PropertyPlaceholderConfigurer 相关联,这正是我想要的。

于 2009-01-29T13:32:12.470 回答
3

一直试图自己想出一个很好的解决方案

  1. 围绕为配置文件创建 XSD - 因为在我看来,使用 XML 的全部好处是您可以在数据类型方面强输入配置文件,以及哪些字段是强制性/可选的
  2. 将针对 XSD 验证 XML,因此如果缺少值,它将抛出错误,而不是您的 bean 被注入“null”
  3. 不依赖于 spring 注释(比如@Value - 在我看来,这让 bean 了解它们的容器 + 与其他 bean 的关系,因此破坏了 IOC)
  4. 将针对 XSD 验证 spring XML,因此如果您尝试引用 XSD 中不存在的 XML 字段,它也会抛出错误
  5. bean 不知道它的属性值是从 XML 注入的(即我想注入单个属性,而不是整个 XML 对象)

我想出的内容如下,抱歉,这很啰嗦,但我喜欢它作为一种解决方案,因为我相信它涵盖了所有内容。希望这可能对某人有用。先说些琐碎的:

我希望将属性值注入的 bean:

package com.ndg.xmlpropertyinjectionexample;

public final class MyBean
{
    private String firstMessage;
    private String secondMessage;

    public final String getFirstMessage ()
    {
        return firstMessage;
    }

    public final void setFirstMessage (String firstMessage)
    {
        this.firstMessage = firstMessage;
    }

    public final String getSecondMessage ()
    {
        return secondMessage;
    }

    public final void setSecondMessage (String secondMessage)
    {
        this.secondMessage = secondMessage;
    }
}

测试类以创建上述 bean 并转储它获得的属性值:

package com.ndg.xmlpropertyinjectionexample;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public final class Main
{
    public final static void main (String [] args)
    {
        try
        {
            final ApplicationContext ctx = new ClassPathXmlApplicationContext ("spring-beans.xml");
            final MyBean bean = (MyBean) ctx.getBean ("myBean");
            System.out.println (bean.getFirstMessage ());
            System.out.println (bean.getSecondMessage ());
        }
        catch (final Exception e)
        {
            e.printStackTrace ();
        }
    }

}

MyConfig.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:myconfig="http://ndg.com/xmlpropertyinjectionexample/config" targetNamespace="http://ndg.com/xmlpropertyinjectionexample/config">

    <xsd:element name="myConfig">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element minOccurs="1" maxOccurs="1" name="someConfigValue" type="xsd:normalizedString" />
                <xsd:element minOccurs="1" maxOccurs="1" name="someOtherConfigValue" type="xsd:normalizedString" />
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

</xsd:schema>

基于 XSD 的示例 MyConfig.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<config:myConfig xmlns:config="http://ndg.com/xmlpropertyinjectionexample/config">
    <someConfigValue>First value from XML file</someConfigValue>
    <someOtherConfigValue>Second value from XML file</someOtherConfigValue>
</config:myConfig>

运行 xsd2java 的 pom.xml 文件的片段(除了设置为 Java 1.6 和 spring-context 依赖项之外,这里没有太多其他内容):

        <plugin>
            <groupId>org.jvnet.jaxb2.maven2</groupId>
            <artifactId>maven-jaxb2-plugin</artifactId>
            <executions>
                <execution>
                    <id>main-xjc-generate</id>
                    <phase>generate-sources</phase>
                    <goals><goal>generate</goal></goals>
                </execution>
            </executions>
        </plugin>

现在是 spring XML 本身。这将创建一个模式/验证器,然后使用 JAXB 创建一个解组器以从 XML 文件创建一个 POJO,然后使用 spring # 注释通过查询 POJO 来注入属性值:

<?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.2.xsd" >

    <!-- Set up schema to validate the XML -->

    <bean id="schemaFactory" class="javax.xml.validation.SchemaFactory" factory-method="newInstance">
        <constructor-arg value="http://www.w3.org/2001/XMLSchema"/>
    </bean> 

    <bean id="configSchema" class="javax.xml.validation.Schema" factory-bean="schemaFactory" factory-method="newSchema">
        <constructor-arg value="MyConfig.xsd"/>
    </bean>

    <!-- Load config XML -->

    <bean id="configJaxbContext" class="javax.xml.bind.JAXBContext" factory-method="newInstance">
        <constructor-arg>
            <list>
                <value>com.ndg.xmlpropertyinjectionexample.config.MyConfig</value>
            </list>
        </constructor-arg>
    </bean>

    <bean id="configUnmarshaller" class="javax.xml.bind.Unmarshaller" factory-bean="configJaxbContext" factory-method="createUnmarshaller">
        <property name="schema" ref="configSchema" />
    </bean>

    <bean id="myConfig" class="com.ndg.xmlpropertyinjectionexample.config.MyConfig" factory-bean="configUnmarshaller" factory-method="unmarshal">
        <constructor-arg value="MyConfig.xml" />
    </bean>

    <!-- Example bean that we want config properties injected into -->

    <bean id="myBean" class="com.ndg.xmlpropertyinjectionexample.MyBean">
        <property name="firstMessage" value="#{myConfig.someConfigValue}" />
        <property name="secondMessage" value="#{myConfig.someOtherConfigValue}" />
    </bean>

</beans>
于 2013-05-05T11:28:41.727 回答
2

我不确定 Apache 消化器风格的配置文件,但我找到了一个不难实现且适合我的 xml 配置文件的解决方案。

您可以使用 spring 中的普通 PropertyPlaceholderConfigurer,但要读取您的自定义配置,您必须创建自己的 PropertiesPersister,您可以在其中解析 xml(使用 XPath)并自己设置所需的属性。

这是一个小例子:

首先通过扩展默认的 PropertiesPersister 创建你自己的:

public class CustomXMLPropertiesPersister extends DefaultPropertiesPersister {
            private XPath dbPath;
            private XPath dbName;
            private XPath dbUsername;
            private XPath dbPassword;

            public CustomXMLPropertiesPersister() throws JDOMException  {
                super();

            dbPath = XPath.newInstance("//Configuration/Database/Path");
            dbName = XPath.newInstance("//Configuration/Database/Filename");
            dbUsername = XPath.newInstance("//Configuration/Database/User");
            dbPassword = XPath.newInstance("//Configuration/Database/Password");
        }

        public void loadFromXml(Properties props, InputStream is)
        {
            Element rootElem = inputStreamToElement(is);

            String path = "";
            String name = "";
            String user = "";
            String password = "";

            try
            {
                path = ((Element) dbPath.selectSingleNode(rootElem)).getValue();
                name = ((Element) dbName.selectSingleNode(rootElem)).getValue();
                user = ((Element) dbUsername.selectSingleNode(rootElem)).getValue();
                password = ((Element) dbPassword.selectSingleNode(rootElem)).getValue();
            }
            catch (JDOMException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            props.setProperty("db.path", path);
            props.setProperty("db.name", name);
            props.setProperty("db.user", user);
            props.setProperty("db.password", password);
        }

        public Element inputStreamToElement(InputStream is)
        {       
            ...
        }

        public void storeToXml(Properties props, OutputStream os, String header)
        {
            ...
        }
    }

然后将 CustomPropertiesPersister 注入应用程序上下文中的 PropertyPlaceholderConfigurer:

<beans ...>
    <bean id="customXMLPropertiesPersister" class="some.package.CustomXMLPropertiesPersister" />

    <bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_FALLBACK" />
        <property name="location" value="file:/location/of/the/config/file" />
        <property name="propertiesPersister" ref="customXMLPropertiesPersister" />
    </bean> 
</beans>

之后,您可以像这样使用您的属性:

<bean id="someid" class="some.example.class">
  <property name="someValue" value="$(db.name)" />
</bean>
于 2011-05-25T09:05:59.177 回答