2009-01-26 24 views
8

Mùa xuân có một lớp tiện lợi rất tiện dụng được gọi là PropertyPlaceholderConfigurer, có tệp tiêu chuẩn .properties và đưa các giá trị từ nó vào cấu hình bean.xml của bạn.Có một lớp thuộc tính PropertyPlaceholderConfigurer để sử dụng với Spring chấp nhận XML không?

Có ai biết một lớp thực hiện chính xác điều tương tự không, và tích hợp với Spring theo cùng một cách, nhưng chấp nhận tệp XML cho cấu hình. Cụ thể, tôi đang nghĩ về các tệp cấu hình kiểu máy phân loại Apache. Nó sẽ dễ dàng đủ để làm điều này, tôi chỉ tự hỏi nếu có ai đã có.

Đề xuất?

Trả lời

7

Tôi vừa thử nghiệm điều này và nó chỉ hoạt động.

Thuộc tínhPlaceholderConfigurer chứa phương thức setPropertiesPersister, vì vậy bạn có thể sử dụng lớp con của riêng mình là PropertiesPersister. PropertiesPersister mặc định đã hỗ trợ các thuộc tính ở định dạng XML.

Chỉ cần để hiển thị cho bạn mã làm việc đầy đủ:

JUnit trường hợp 4.4 thử nghiệm:

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

Các tập tin mùa xuân cấu hình 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> 

Các thuộc tính XML nộp properties.xml - xem here cho mô tả cách sử dụng.

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

Và cuối cùng là đậu:

package org.nkl; 

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

Hope this helps ...

+0

Đó là chắc chắn tiện dụng để biết, và sẽ là một bản sao lưu tiện dụng.Tôi đoán nó dễ dàng, đủ để ghi đè PropertiesPersister để thực hiện phân tích kiểu phân tích Apache Digester, thay vì định dạng xml thuộc tính tiêu chuẩn. – GaryF

+0

nó sẽ làm gì để tạo thứ gì đó tải các tệp xml tùy chỉnh (không thuộc tính) bằng trình tải tài nguyên? –

4

Tìm thấy ra rằng mùa xuân Modules cung cấp integration between Spring and Commons Configuration, trong đó có một phong cách cấu hình XML hierarchial. Điều này liên kết trực tiếp với PropertyPlaceholderConfigurer, đó chính xác là những gì tôi muốn.

+0

Đẹp một GaryF - +1 :-) – toolkit

+0

liên kết không trỏ đến ví dụ cụ thể nữa? –

2

Tôi không chắc về tệp cấu hình kiểu máy phân loại Apache, nhưng tôi đã tìm thấy giải pháp không khó thực hiện và phù hợp với tệp cấu hình xml của tôi. Bạn có thể sử dụng PropertyPlaceholderConfigurer bình thường từ mùa xuân, nhưng để đọc cấu hình tùy chỉnh của bạn, bạn phải tạo PropertiesPersister của riêng bạn, nơi bạn có thể phân tích cú pháp xml (với XPath) và tự đặt các thuộc tính bắt buộc.

Dưới đây là một ví dụ nhỏ:

Đầu tiên tạo PropertiesPersister của riêng bạn bằng cách mở rộng mặc định một:

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

Sau đó tiêm CustomPropertiesPersister đến PropertyPlaceholderConfigurer trong bối cảnh ứng dụng:

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

Sau đó, bạn có thể sử dụng các thuộc tính của mình như sau:

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

Được cố gắng để tìm ra một giải pháp tốt đẹp này bản thân mình rằng

  1. xoay quanh việc tạo ra một XSD cho tập tin cấu hình - vì trong tâm trí của tôi toàn bộ lợi ích của việc sử dụng XML là bạn có thể mạnh mẽ gõ tệp cấu hình, về kiểu dữ liệu và trường nào là bắt buộc/tùy chọn
  2. Sẽ xác thực XML đối với XSD, vì vậy nếu giá trị bị thiếu, nó sẽ ném lỗi ra ngoài thay vì bean của bạn được chèn bằng 'null '
  3. Không dựa vào chú thích mùa xuân (như @Value - trong tâm trí của tôi, đó là cung cấp kiến ​​thức về hạt cà phê abo ut + mối quan hệ của họ với các hạt khác, do đó, phá vỡ IOC)
  4. Sẽ xác thực XML mùa xuân dựa vào XSD, vì vậy nếu bạn cố gắng tham chiếu một trường XML không có trong XSD, nó sẽ ném ra một lỗi quá
  5. Đậu không có kiến ​​thức về giá trị tài sản của nó đang được tiêm từ XML (tức là Tôi muốn tiêm các thuộc tính riêng lẻ, và không phải toàn bộ đối tượng XML)

Điều tôi nghĩ ra là như sau, xin lỗi đây là một cuộn dài, nhưng tôi thích nó như một giải pháp vì tôi tin nó bao gồm mọi điều. Hy vọng rằng điều này có thể hữu ích cho ai đó. mảnh nhỏ đầu tiên:

bean Tôi muốn giá trị tài sản tiêm vào:

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

class Test để tạo ra đậu trên và đổ ra các giá trị tài sản đó có:

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> 

Tệp MyConfig.xml mẫu dựa trên 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> 

Snippet của tập tin pom.xml để chạy xsd2java (đã không có nhiều khác ở đây ngoài việc thiết để Java 1.6, và phụ thuộc vào mùa xuân-ngữ cảnh):

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

Bây giờ XML mùa xuân riêng của mình. Điều này tạo ra một sơ đồ/validator, sau đó sử dụng JAXB để tạo ra một unmarshaller để tạo ra một POJO từ tập tin XML, sau đó sử dụng lò xo # chú thích để bơm giá trị tài sản bằng quering 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> 
Các vấn đề liên quan