Сам пытался придумать хорошее решение этого вопроса, которое
- Обращается вокруг создания XSD для файла конфигурации - поскольку, на мой взгляд, все преимущества использования XML в том, что вы можете строго набирать файл конфигурации с точки зрения типов данных и какие поля являются обязательными / необязательными
- Будет проверять XML на соответствие XSD, поэтому, если значение отсутствует, оно выдаст ошибку, а не ваш бин, введенный с 'null'
- Не полагается на весенние аннотации (например, @Value - по моему мнению, это дает бинам знания об их контейнере + отношения с другими бобами, поэтому нарушает МОК)
- Будет проверять пружинный XML на соответствие XSD, поэтому, если вы попытаетесь сослаться на поле XML, отсутствующее в XSD, оно также выдаст ошибку
- Бин не знает, что значения его свойств внедряются из 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>