propertysource property example context application java xml spring properties

java - example - ¿Existe una clase similar a PropertyPlaceholderConfigurer para usar con Spring que acepte XML?



spring boot configuration properties (4)

Acabo de probar esto, y debería funcionar.

PropertiesPlaceholderConfigurer contiene un método setPropertiesPersister, por lo que puede usar su propia subclase de PropertiesPersister . El valor predeterminado de PropertiesPersister ya admite propiedades en formato XML.

Solo para mostrarte el código completamente funcional:

Caso de prueba 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()); } }

El archivo de configuración de primavera 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>

El archivo de properties.xml XML properties.xml - mira aquí para una descripción del uso.

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

Y finalmente el frijol:

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

Espero que esto ayude...

Spring tiene una clase de conveniencia muy útil llamada PropertyPlaceholderConfigurer , que toma un archivo .properties estándar e inyecta valores desde él en su configuración de bean.xml.

¿Alguien sabe de una clase que hace exactamente lo mismo, y se integra con Spring de la misma manera, pero acepta archivos XML para la configuración. Específicamente, estoy pensando en los archivos de configuración estilo digestor de Apache. Sería bastante fácil hacer esto, solo me pregunto si alguien ya lo hizo.

Sugerencias?


Descubrió que Spring Modules brinda integración entre Spring y Commons Configuration , que tiene un estilo de configuración XML jerárquico. Esto se relaciona directamente con PropertyPlaceholderConfigurer, que es exactamente lo que yo quería.


No estoy seguro de los archivos de configuración del estilo del digestor Apache, pero encontré una solución que no era tan difícil de implementar y adecuada para mi archivo de configuración xml.

Puede utilizar el PropertyPlaceholderConfigurer normal desde la primavera, pero para leer sus configuraciones personalizadas debe crear su propia PropertiesPersister, donde puede analizar el xml (con XPath) y establecer las propiedades necesarias usted mismo.

Aquí hay un pequeño ejemplo:

Primero crea tu propio PropertiesPersister extendiendo el predeterminado:

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) { ... } }

A continuación, inserte CustomPropertiesPersister en PropertyPlaceholderConfigurer en el contexto de la aplicación:

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

Después de eso puedes usar tus propiedades de esta manera:

<bean id="someid" class="some.example.class"> <property name="someValue" value="$(db.name)" /> </bean>


He estado tratando de encontrar una buena solución para esto que

  1. Gira en torno a la creación de un XSD para el archivo de configuración, ya que en mi opinión la ventaja de usar XML es que puedes escribir fuertemente el archivo de configuración, en términos de tipos de datos, y qué campos son obligatorios / opcionales
  2. Validará el XML contra el XSD, por lo que si falta un valor arrojará un error en lugar de que su bean sea inyectado con un ''nulo''
  3. No confía en las anotaciones de primavera (como @Value - en mi opinión eso le está dando a los frijoles el conocimiento sobre su contenedor + relación con otros frijoles, por lo que rompe el COI)
  4. Validará el XML de primavera con el XSD, por lo que si intenta hacer referencia a un campo XML que no está presente en el XSD, también arrojará un error
  5. The Bean no tiene conocimiento de que sus valores de propiedad se estén inyectando desde XML (es decir, quiero inyectar propiedades individuales, y no el objeto XML como un todo)

Lo que se me ocurrió es lo siguiente, disculpas, esto es bastante largo, pero me gusta como una solución, ya que creo que cubre todo. Espero que esto pueda serle útil a alguien. Piezas triviales primero:

El bean que quiero que los valores de propiedad se inyecten en:

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

Clase de prueba para crear el bean anterior y volcar los valores de propiedad que obtuvo:

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>

Ejemplo de archivo MyConfig.xml basado en el 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>

Fragmento del archivo pom.xml para ejecutar xsd2java (no había mucho más aquí además de configurar Java 1.6 y la dependencia del contexto de primavera):

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

Ahora el XML de primavera en sí. Esto crea un esquema / validador, luego usa JAXB para crear un unmarshaller para crear un POJO a partir del archivo XML, luego usa la anotación # de primavera para inyectar los valores de propiedad al consultar el 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>