Results 1 to 5 of 5

Thread: Java Config for Autowiring a DataSource with PropertyPlaceholderConfigurer

  1. #1
    Join Date
    Apr 2012
    Posts
    3

    Default Java Config for Autowiring a DataSource with PropertyPlaceholderConfigurer

    I want to use Java Config to declare my PropertyPlaceholderConfigurer bean. The bean loads its properties from a database table using CommonsConfigurationFactoryBean with a DatabaseConfiguration bean. A different DataSource bean profile is loaded depending upon the environment in which the application is deployed. The problem I am facing appears to be in the order in which my beans are loaded. The PropertyPlaceholderConfigurer bean seems to be loaded before my DataSource bean, which causes problems because I need a reference to the DataSource bean in order to load my properties. In the following code example, dataSource is null when PropertyPlaceholderConfigurer initializes. I am using Spring 3.1.1.RELEASE

    Code:
    @Configuration
    public class DatabaseConfig {
        @Autowired
        private DataSource dataSource;
    
        @Bean
        public PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() throws Exception {
            PropertyPlaceholderConfigurer p = new PropertyPlaceholderConfigurer();
            p.setProperties((Properties) commonsConfigurationFactoryBean().getObject());
            return p;
        }
    
        @Bean
        public CommonsConfigurationFactoryBean commonsConfigurationFactoryBean() {
            return new CommonsConfigurationFactoryBean(databaseConfiguration());
        }
    
        @Bean
        public DatabaseConfiguration databaseConfiguration() {
            return new DatabaseConfiguration(dataSource, "TABLE", "NAME_COLUMN", "KEY_COLUMN", "VALUE_COLUMN", "NAME");
        }
    
        @Profile({ "dev" })
        static class Dev {
            @Bean
            public DataSource dataSource() {
                return new SimpleDriverDataSource(new OracleDriver(), "jdbc:oracle:thin:@dev-host:port:db", "username",
                        "password");
            }
        }
    
        @Profile({ "prod" })
        static class Prod {
            @Bean
            public DataSource dataSource() {
                return new SimpleDriverDataSource(new OracleDriver(), "jdbc:oracle:thin:@prod-host:port:db", "username",
                        "password");
            }
        }
    }

  2. #2

    Default

    First of all your PropertyPlaceholderConfigurer bean needs to be static. Please see http://static.springsource.org/sprin...tion/Bean.html the section entitled ''A note on BeanFactoryPostProcessor-returning @Bean methods".

    That said the static is not required for your profile classes although it certainly does not hurt anything and is actually more performant.


    You could try to do it during initialization (untested but worth a shot)

    create a class something like this

    Code:
    public class MyWebContextInitializer
        implements ApplicationContextInitializer<ConfigurableWebApplicationContext>
    {
    
        @Override
        public void initialize(ConfigurableWebApplicationContext applicationContext)
        {
            DataSource dataSource = (DataSource) applicationContext.getBean("dataSource");
            DatabaseConfiguration databaseConfiguration = new DatabaseConfiguration(dataSource,
                "TABLE", "NAME_COLUMN", "KEY_COLUMN", "VALUE_COLUMN", "NAME");
            CommonsConfigurationFactoryBean commonsConfigurationFactoryBean = new CommonsConfigurationFactoryBean(
                databaseConfiguration);
             PropertySource<Map<String, Object>> propertySource = new PropertiesPropertySource("nameForMyPropertiesSource",
                (Properties) commonsConfigurationFactoryBean.getObject());
            applicationContext.getEnvironment().getPropertySources().addFirst(propertySource);
        }
    }
    set it up in your web.xml

    Code:
    	<context-param>
    		<param-name>contextInitializerClasses</param-name>
    		<param-value>com.xxx.xxx.MyWebContextInitializer</param-value>
    	</context-param>
    Last edited by wgorder; Apr 27th, 2012 at 01:19 PM.

  3. #3
    Join Date
    Apr 2012
    Posts
    3

    Default

    Some other things I should have mentioned... This is a stand-alone application. The application context initialization is handled by Mule ESB... all I am telling Mule to do is import my applicationContext.xml, which has a spring-configured and component scanner. I also have other bean definitions that are dependent upon the values retrieved from the database by the property placeholder configurer, so performing a reload of application context in a PostConstruct is not an option. I have a working example using XML config which I will post shortly. Ultimately, I would like to get an equivalent solution in Java Config.

  4. #4
    Join Date
    Apr 2012
    Posts
    3

    Default

    Here is my working solution with a combination of XML and Java Config. Again, I would like to see a solution with all Java Config.

    Current Java Config
    Code:
    @Configuration
    public class DatabaseConfig {
        @Profile({ "dev" })
        static class Dev {
            @Bean
            public DataSource dataSource() {
                return new SimpleDriverDataSource(new OracleDriver(), "jdbc:oracle:thin:@dev-host:port:db", "username",
                        "password");
            }
        }
    
        @Profile({ "prod" })
        static class Prod {
            @Bean
            public DataSource dataSource() {
                return new SimpleDriverDataSource(new OracleDriver(), "jdbc:oracle:thin:@prod-host:port:db", "username",
                        "password");
            }
        }
    }
    Current XML Config
    Code:
    <bean name="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    		<property name="location" value="classpath:env.${spring.profiles.active}.properties"/>
    		<property name="properties" ref="commonsConfigurationFactoryBean"/>
    	</bean>
    	
    	<bean name="commonsConfigurationFactoryBean" class="org.springmodules.commons.configuration.CommonsConfigurationFactoryBean">
    		<constructor-arg ref="databaseConfiguration"/>
    	</bean>
    	
    	<bean name="databaseConfiguration" class="org.apache.commons.configuration.DatabaseConfiguration">
    		<constructor-arg name="datasource" ref="dataSource"/>
    		<constructor-arg name="table" value="TABLE"/>
    		<constructor-arg name="nameColumn" value="NAME_COLUMN"/>
    		<constructor-arg name="keyColumn" value="KEY_COLUMN"/>
    		<constructor-arg name="valueColumn" value="VALUE_COLUMN"/>
    		<constructor-arg name="name" value="NAME"/>
    	</bean>
    Last edited by akohring; Apr 27th, 2012 at 02:52 PM.

  5. #5
    Join Date
    Mar 2008
    Posts
    6

    Default Using inheritance should work here, though I have not verified.

    I removed the CommonsConfigurationFactoryBean as it is not supported in Spring 3.x and we can do fine here without it. Because the @Profile extends the abstract Base class the bean context should properly resolve. Hope this works for you!

    Code:
    @Configuration
    public class DatabaseConfig {
        static abstract class Base {
            public abstract DataSource dataSource();
    
            @Bean
            public PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() throws Exception {
                PropertyPlaceholderConfigurer p = new PropertyPlaceholderConfigurer();
                p.setProperties(ConfigurationConverter.getProperties(databaseConfiguration()));
                return p;
            }
    
            @Bean
            public DatabaseConfiguration databaseConfiguration() {
                return new DatabaseConfiguration(dataSource(), "TABLE", "NAME_COLUMN", "KEY_COLUMN", "VALUE_COLUMN", "NAME");
            }
        }
    
    
        @Profile({ "dev" })
        static class Dev extends Base {
            @Bean
            public DataSource dataSource() {
                return new SimpleDriverDataSource(new OracleDriver(), "jdbc:oracle:thin:@dev-host:port:db", "username",
                        "password");
            }
        }
    
        @Profile({ "prod" })
        static class Prod extends Base  {
            @Bean
            public DataSource dataSource() {
                return new SimpleDriverDataSource(new OracleDriver(), "jdbc:oracle:thin:@prod-host:port:db", "username",
                        "password");
            }
        }
    }
    Last edited by dkrieg; May 10th, 2012 at 12:08 AM.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •