Существует ли класс, подобный PropertyPlaceholderConfigurer, для использования с Spring, который принимает XML? - PullRequest
8 голосов
/ 26 января 2009

Spring имеет очень удобный класс удобства, называемый PropertyPlaceholderConfigurer , который берет стандартный файл .properties и вставляет из него значения в конфигурацию bean.xml.

Кто-нибудь знает класс, который делает то же самое, и таким же образом интегрируется с Spring, но принимает XML-файлы для конфигурации. В частности, я имею в виду конфигурационные файлы в стиле Apache. Это было бы достаточно легко сделать, я просто хотел бы знать, есть ли у кого-нибудь это.

Предложения

Ответы [ 4 ]

7 голосов
/ 26 января 2009

Я только что проверил это, и оно должно просто работать.

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>

И, наконец, боб:

package org.nkl;

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

Надеюсь, это поможет ...

4 голосов
/ 29 января 2009

Обнаружено, что модули Spring обеспечивают интеграцию между Spring и Commons Configuration , которая имеет иерархический стиль конфигурации XML. Это напрямую связано с PropertyPlaceholderConfigurer, что я и хотел.

3 голосов
/ 05 мая 2013

Сам пытался придумать хорошее решение этого вопроса, которое

  1. Обращается вокруг создания XSD для файла конфигурации - поскольку, на мой взгляд, все преимущества использования XML в том, что вы можете строго набирать файл конфигурации с точки зрения типов данных и какие поля являются обязательными / необязательными
  2. Будет проверять XML на соответствие XSD, поэтому, если значение отсутствует, оно выдаст ошибку, а не ваш бин, введенный с 'null'
  3. Не полагается на весенние аннотации (например, @Value - по моему мнению, это дает бинам знания об их контейнере + отношения с другими бобами, поэтому нарушает МОК)
  4. Будет проверять пружинный XML на соответствие XSD, поэтому, если вы попытаетесь сослаться на поле XML, отсутствующее в XSD, оно также выдаст ошибку
  5. Бин не знает, что значения его свойств внедряются из XML (т.е. я хочу внедрить отдельные свойства, а не объект XML в целом)

Я придумал следующее: извинения, это довольно долго, но мне нравится это решение, так как я считаю, что оно охватывает все. Надеюсь, это может оказаться полезным для кого-то. Сначала тривиальные пьесы:

Боб, в который я хочу вставить значения свойств:

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

Тестовый класс для создания вышеуказанного компонента и вывода значений свойств, которые он получил:

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>

Пример файла MyConfig.xml на основе XSD:

<?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>

Фрагмент файла pom.xml для запуска xsd2java (здесь не было ничего другого, кроме установки на Java 1.6 и зависимости Spring-контекста):

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

Теперь сам XML-источник. Это создает схему / валидатор, затем использует JAXB для создания демаршаллера для создания POJO из файла XML, а затем использует пружинную аннотацию # для ввода значений свойств путем запроса 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>
2 голосов
/ 25 мая 2011

Я не уверен насчет конфигурационных файлов в стиле Apache, но я нашел решение, которое не так сложно реализовать и подходит для моего XML-конфигурационного файла.

Вы можете использовать обычный PropertyPlaceholderConfigurer из Spring, но чтобы прочитать свою пользовательскую конфигурацию, вы должны создать свой собственный 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...