Search code examples
javaspringspring-annotations

How to configure Spring configuration for List of Beans from different property files?


I have working Spring XML configuration and I want to move it to Annotation Config.

The problem is how to create different beans from a different property file.

Here is the XML snippet:

<bean id="auditorium1" class="net.lelyak.edu.entity.Auditorium"
      c:name="${auditorium1.name}" c:numberOfSeats="${auditorium1.number-of-seats}" 
      c:vipSeats="${auditorium1.vip-seats}"/>
<bean id="auditorium2" class="net.lelyak.edu.entity.Auditorium"
      c:name="${auditorium2.name}" c:numberOfSeats="${auditorium2.number-of-seats}" 
      c:vipSeats="${auditorium2.vip-seats}"/>
<bean id="auditorium3" class="net.lelyak.edu.entity.Auditorium"
      c:name="${auditorium3.name}" c:numberOfSeats="${auditorium3.number-of-seats}" 
      c:vipSeats="${auditorium3.vip-seats}"/>

<util:list id="auditoriumsList">
    <ref bean="auditorium1"/>
    <ref bean="auditorium2"/>
    <ref bean="auditorium3"/>
</util:list>

<bean id="conversionService"
      class="org.springframework.context.support.ConversionServiceFactoryBean" /> 

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:properties/auditorium1.properties</value>
            <value>classpath:properties/auditorium2.properties</value>
            <value>classpath:properties/auditorium3.properties</value>
            <value>classpath:db/dp.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>

Property file example:

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

I want to move it to Annotation configuration, something like:

@Configuration
public class AuditoriumConfiguration {

    @Bean
    public Auditorium auditorium1() {
        return new Auditorium();
    }

    @Bean
    public Auditorium auditorium2() {
        return new Auditorium();
    }

    @Bean
    public Auditorium auditorium3() {
        return new Auditorium();
    }

    @Bean
    public List<Auditorium> auditoriumsList() {
        return Arrays.asList(auditorium1(), auditorium2(), auditorium3());
    }

    @Bean
    public ConversionService conversionService() {
        return new DefaultConversionService();
    }
}

Here is Auditorium POJO:

@Component
public class Auditorium {
    private Integer id;
    private String name;
    private Integer numberOfSeats;
    private Set<Integer> vipSeats;
    // get / set

How can I create different Auditorium instances for each property file?

I guess that I could use @Value, but I can't find approach create object per each property file.

Any suggestion?


Solution

  • First you don't need the list, if you need a list of types just add @Autowired to a collection and spring will inject all types of that bean into that collection.

    To obtain properties you can use the Environment and you probably want to add a helper/factory method for that.

    The conversion service is already configured by default so no need to add that.

    To load the configuration file add @PropertySource to your configuration class. If you need @Value or replacement of placeholders you would need to add a PropertySourcesPlaceholderConfigurer as a static bean.

    Basically, something like this should achieve what you want.

    @Configuration
    @PropertySource({"classpath:properties/auditorium1.properties",
            "classpath:properties/auditorium2.properties",
            "classpath:properties/auditorium3.properties",
            "classpath:db/dp.properties"})
    public class AuditoriumConfiguration {
    
        @Autowired
        private Environment env;
    
        @Bean
        public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
            return new PropertySourcesPlaceholderConfigurer();
        }
    
        private Auditorium createAuditorium(String prefix) {
            String nameString = env.getProperty(prefix + ".name");
            String strNumberOfSeats = env.getProperty(prefix + ".number-of-seats");
            Integer[] integers = env.getProperty(prefix + ".vip-seats", Integer[].class);
            Set<Integer> integerSet = Arrays.stream(integers).collect(Collectors.toSet());
    
            Auditorium auditorium = new Auditorium();
            auditorium.setName(nameString);
            auditorium.setNumberOfSeats(Integer.valueOf(strNumberOfSeats));
            auditorium.setVipSeats(integerSet);
            return auditorium;
        }
    
        @Bean
        public Auditorium auditorium1() {
            return createAuditorium("auditorium1");
        }
    
        @Bean
        public Auditorium auditorium2() {
            return createAuditorium("auditorium2");
        }
    
        @Bean
        public Auditorium auditorium3() {
            return createAuditorium("auditorium3");
        }
    }
    

    Now if you want a list of those classes just add a List<Auditorium> and spring will inject all dependencies into that list.

    public class MyClass {
        @Autowired
        private List<Auditorium> auditoriums;
    }