5

I have spring application configured via annotations. Here is part of my config

@Configuration
@EnableTransactionManagement
public class JpaSpringConfiguration {

    @Bean(destroyMethod = "close")
    @Lazy
    @Primary
    public BasicDataSource dataSource(@Value("${statistics.hostname}") String statisticsHostname) { 
        final BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("org.postgresql.Driver");
        String url = String.format("jdbc:postgresql://%s:5432/statistics-db", statisticsHostname);
        dataSource.setUrl(url);
        ....
        return dataSource;
    }

    @Bean
    public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
        final PropertyPlaceholderConfigurer placeholderConfigurer = new PropertyPlaceholderConfigurer();
        placeholderConfigurer.setSystemPropertiesMode(SYSTEM_PROPERTIES_MODE_OVERRIDE);
        Properties properties = new Properties();
        properties.setProperty("statistics.hostname", "localhost");

        placeholderConfigurer.setProperties(properties);
        return placeholderConfigurer;
    }

Until recently we had xml configuration

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
    <property name="properties">
        <props>
            <prop key="statistics.hostname">localhost</prop>
        </props>
    </property>
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" lazy-init="true" destroy-method="close">
    <property name="driverClassName" value="org.postgresql.Driver" />
    <property name="url" value="jdbc:postgresql://${statistics.hostname}:5432/statistics-db" />
    <property name="username" value="user" />
    <property name="password" value="password" />
</bean>

When user selected different server to connect to we set system property and closed application context and refreshed

System.setProperty("statistics.hostname", hostname)
applicationContext.close()
applicationContext.refresh()

This does not work when I use annotation configuration. My questions are:

  1. why it does not work now?
  2. how to get rid of setting hostname via system property altogether?

EDIT: I just found out that I forgot ${} around the name of the parameter in method dataSource(). So it works now but question 2 still remains.

Martin Barnas
  • 185
  • 1
  • 13

1 Answers1

0

not sure why it doesnt work, but you may try to do couple more things:

  1. Is closing context before refresh really needed? Try to only refresh it.
  2. You can mark your bean as @RefreshScope ( but it requires spring cloud ) and refresh it using /refresh endpoint. That would require another endpoint to actually update your host on a bean before calling refresh.

"how to get rid of setting hostname via system property altogether?"

pass that to property file which is the way it is normally configured. If you are using spring boot, then you only have to configure:

spring.datasource.url=
spring.datasource.username=
spring.datasource.password=
...

properties. Datasource bean would be created using those values for you.

hi_my_name_is
  • 4,894
  • 3
  • 34
  • 50
  • I can't use property file because the hostname is entered by user and user also often change server which they are connected to. – Martin Barnas Jul 29 '15 at 12:10
  • then try to add controller which will be called when user types in hostname (pass it to controller), save this hostname on a dataSource() bean and try to refresh with taking my point 1/2 under consideration :) .properties file can be used to store default hostname value which is going to be used in case of app restart. – hi_my_name_is Jul 29 '15 at 12:15