如何从属性文件转换数据并设置为List属性(使用PropertyPlaceholderConfigurer)?

时间:2016-02-10 13:05:47

标签: java spring properties-file

我有一个实体:

public class Auditorium {
    private Integer id;
    private String name;
    private Integer numberOfSeats;
    private List<String> vipSeats;

    public Auditorium(String name, Integer numberOfSeats, List<String> vipSeats) {
        this.name = name;
        this.numberOfSeats = numberOfSeats;
        this.vipSeats = vipSeats;
    }

我想从属性文件中创建Auditorium实例,例如:

auditorium1.name=yellow hall
auditorium1.number-of-seats=150
auditorium1.vip-seats=1,2,3,4,5,6,7,8,9

我有几个不同的文件,我想创建不同的Auditorium bean。

以下是spring.xml

的摘录
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:auditorium1.properties</value>
            <value>classpath:auditorium2.properties</value>
            <value>classpath:auditorium3.properties</value>
        </list>
    </property>
    <property name="ignoreResourceNotFound" value="true"/>
    <property name="systemPropertiesMode">
        <util:constant
                static-field="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
    </property>
</bean>

<util:list id="auditorium1" value-type="java.lang.String">
    <value></value>
</util:list>

<util:list>
    <bean class="net.lelyak.edu.entity.Auditorium"
          p:name="${auditorium1.name}" p:numberOfSeats="${auditorium1.number-of-seats}" p:vipSeats="${auditorium1.vip-seats}"/>
</util:list>

但我得到一个错误:

enter image description here

因为No matching constructor found

更好的是List<Integer> vipSeats。在这种情况下是否可能?

如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

这里有两个方面需要涵盖,所以让我们一次一个:

1)IJ(IntelliJ Idea的简称)建议根据你的bean声明,Spring将尝试调用一个no-arg构造函数,由于你已经定义了public Auditorium(String name, Integer numberOfSeats, List<String> vipSeats),它显然不存在

因此,您可以将其配置为根据spring docs调用上述构造函数传递正确的参数:

<bean class="com.example.Auditorium">
    <constructor-arg name="name" value="${auditorium1.name}"/>
    <constructor-arg name="numberOfSeats" value="${auditorium1.number-of-seats}"/>
    <constructor-arg name="vipSeats" value="${auditorium1.vip-seats}"/>
</bean>

除此之外,Spring不需要特殊处理来注入您的列表,正如您在下面的日志片段中所看到的,通过简单的toString() IJ自动生成方法输出:

16:13:56.569 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'com.example.Auditorium#0'
16:13:56.601 [main] DEBUG com.example.Auditorium - Auditorium{id=null, name='yellow hall', numberOfSeats=150, vipSeats=[1,2,3,4,5,6,7,8,9]}

<小时/>

2)我看到您尝试使用p-namespace将参数传递给构造函数,但是在bean实例化之后用于设置属性/属性。您可以使用c-namespace获得与使用<constructor-arg>标记相同的效果,并且不那么详细(请注意,根据spring文档,p&amp; c命名空间未在XSD文件中定义并且仅存在于Spring的核心中:

<beans ...
       xmlns:c="http://www.springframework.org/schema/c"
       ...>

    <bean id="myAuditorium" class="com.example.Auditorium" c:name="${auditorium1.name}" c:numberOfSeats="${auditorium1.number-of-seats}" c:vipSeats="${auditorium1.vip-seats}"/>

这次再次为这两个定义生成了日志片段:

16:26:52.258 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'com.example.Auditorium#0'
16:26:52.287 [main] DEBUG com.example.Auditorium - Auditorium{id=null, name='yellow hall', numberOfSeats=150, vipSeats=[1,2,3,4,5,6,7,8,9]}
...
16:26:52.287 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'com.example.Auditorium#1'
16:26:52.288 [main] DEBUG com.example.Auditorium - Auditorium{id=null, name='yellow hall', numberOfSeats=150, vipSeats=[1,2,3,4,5,6,7,8,9]}

<小时/>
注意:取决于您使用的Spring版本&amp;您的需求,也值得检查annotation-based configs。这可能是个人偏好,但我发现它们更清洁,更易于维护,并且IJ对这两种配置都有出色的Spring支持。

<小时/>

特殊要求更新:简要注释介绍

首先,它取决于您的项目设置,是否使用基本 Spring Core或Spring Boot等等。对于此介绍:我只是从...开始你现在在哪里:

启用组件扫描,以便Spring可以发现和创建组件,服务等

<?xml version="1.0" encoding="UTF-8"?>
<beans ...
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="...
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.example" />

然后改变我们的课程。如果您不需要在构造函数中执行任何其他操作,那么我们只需删除它并注释字段即可。 当注释字段时,请考虑Spring只能在实例化bean之后填充它们,因此在构造函数中使用然后最有可能导致NPE。在这种情况下,您可以使用@PostConstruct

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;

@Component
public class Auditorium {
    private static final Logger log = LoggerFactory.getLogger(Auditorium.class);
    private Integer id;

    @Value("${auditorium1.name}")
    private String name;

    @Value("${auditorium1.number-of-seats}")
    private Integer numberOfSeats;

    @Value("${auditorium1.vip-seats}")
    private List<String> vipSeats;

    @PostConstruct
    private void doAfterConstruction() {
        log.debug(this.toString());
    }

    @Override
    public String toString() {
        return "Auditorium{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", numberOfSeats=" + numberOfSeats +
                ", vipSeats=" + vipSeats +
                '}';
    }
}

正如您在日志中看到的那样,Spring将实例化bean,然后为其字段注入值,最后后处理器将调用@PostConstruct带注释的方法:

12:20:34.037 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'auditorium'
12:20:34.038 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'auditorium'
12:20:34.045 [main] DEBUG o.s.c.a.CommonAnnotationBeanPostProcessor - Found init method on class [com.example.Auditorium]: private void com.example.Auditorium.doAfterConstruction()
12:20:34.045 [main] DEBUG o.s.c.a.CommonAnnotationBeanPostProcessor - Registered init method on class [com.example.Auditorium]: org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement@1ec4fbf0
12:20:34.060 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Registered injected element on class [com.example.Auditorium]: AutowiredFieldElement for private java.lang.String com.example.Auditorium.name
12:20:34.060 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Registered injected element on class [com.example.Auditorium]: AutowiredFieldElement for private java.lang.Integer com.example.Auditorium.numberOfSeats
12:20:34.060 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Registered injected element on class [com.example.Auditorium]: AutowiredFieldElement for private java.util.List com.example.Auditorium.vipSeats
12:20:34.060 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'auditorium' to allow for resolving potential circular references
12:20:34.062 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Processing injected element of bean 'auditorium': AutowiredFieldElement for private java.lang.String com.example.Auditorium.name
12:20:34.067 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Processing injected element of bean 'auditorium': AutowiredFieldElement for private java.lang.Integer com.example.Auditorium.numberOfSeats
12:20:34.072 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Processing injected element of bean 'auditorium': AutowiredFieldElement for private java.util.List com.example.Auditorium.vipSeats
12:20:34.084 [main] DEBUG o.s.c.a.CommonAnnotationBeanPostProcessor - Invoking init method on bean 'auditorium': private void com.example.Auditorium.doAfterConstruction()
12:20:34.085 [main] DEBUG com.example.Auditorium - Auditorium{id=null, name='yellow hall', numberOfSeats=150, vipSeats=[1,2,3,4,5,6,7,8,9]}
12:20:34.094 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'auditorium'

或者,如果您想保留构造函数,我们只需将其标记为@Autowired并注释参数:

@Component
public class Auditorium {
    private static final Logger log = LoggerFactory.getLogger(Auditorium.class);
    private Integer id;
    private String name;
    private Integer numberOfSeats;
    private List<String> vipSeats;

    @Autowired
    public Auditorium(@Value("${auditorium1.name}") String name,
                      @Value("${auditorium1.number-of-seats}") Integer numberOfSeats,
                      @Value("${auditorium1.vip-seats}") List<String> vipSeats) {
        this.name = name;
        this.numberOfSeats = numberOfSeats;
        this.vipSeats = vipSeats;
        log.debug(this.toString());
    }
}

日志,这次更简单

12:29:09.492 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'auditorium'
12:29:09.492 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'auditorium'
12:29:09.525 [main] DEBUG com.example.Auditorium - Auditorium{id=null, name='yellow hall', numberOfSeats=150, vipSeats=[1,2,3,4,5,6,7,8,9]}
12:29:09.526 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'auditorium' to allow for resolving potential circular references
12:29:09.548 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'auditorium'