klausch
klausch

Reputation: 662

Spring MVC, how to read and access application.properties?

I am working on an application with Spring MVC (and Hibernate) and feel a bit confused about configuration issues. It does not make it simpler that there are so many ways of setting up and configuring Spring application, which are sometimes even mixed throughout tutorials...

I use Spring 4 with a pure Java-based configuration, so free of XML configuration files. The entry point for the application is a subclass of AbstractAnnotationConfigDispatcherServletInitializer:

public class MvcWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

@Override
protected Class<?>[] getRootConfigClasses() {
    return new Class[] {
            HibernateConfig.class, 
            ServiceConfig.class };
}

@Override
protected Class<?>[] getServletConfigClasses() {
    return new Class[] {MvcConfig.class};
}

@Override
protected String[] getServletMappings() {
    return new String[] {"/"};
}
}

We see that there are 2 root configuration classes, for loading the Hibernate and the Service config classes respectively, and one for loading the Service config class (which actually does nothing more than scanning for conponents under the ~.service package).

The HibernateConfig is the only one which needs properties from the application.properties file, so this file is read as a PropertySource and used in the class as follows:

package nl.drsklaus.activiteitensite.configuration;

//imports

@Configuration
@EnableTransactionManagement
@ComponentScan({"nl.mydomain.activiteitensite.dao"})
@PropertySource(value= {"classpath:application.properties"})
public class HibernateConfig {

@Autowired
private Environment environment;

@Bean
public LocalSessionFactoryBean sessionFactory() {
  //code
  return sessionFactory;
}

@Bean
public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
    dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
    dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
    dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));

    return dataSource;
}

@Bean
@Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
    HibernateTransactionManager txManager = new HibernateTransactionManager();
    txManager.setSessionFactory(s);
    return txManager;
}

private Properties hibernateProperties() {
    Properties properties = new Properties();
    properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
    properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
    properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
    properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
    //TODO connection pooling configuration

    return properties;
}
}

As we see, the properties are used in the configuration file containing the @PropertySource annotation. But it is very well possible that also other configuration files will need to accesss application.properties. And moreover, I plan to define more properties in this file, for example the directory where user images will be stored. This information will be needed in Controller methods, so I need to have a more global way of acceessing application.properties.

So my questions are:

In the future, there will possibly multiple versions of the property file for testing and live deployment.

Upvotes: 7

Views: 36510

Answers (1)

Ken Bekov
Ken Bekov

Reputation: 14015

In order of questions:

  • No. @PropertyResource added to you configuration gives you access to this property file from any bean of application. Before beans creation, Spring collects all property sources of all configurations, and puts it into single Environment of Application context.
  • No, we don't need to add the @PropertyResources to all of them. You can add property source to one configuration and use it in the another one. So, you don't need to repeat name of the property file. Declare it once, and use anywhere.
  • As you guessed in controllers it works as well as in other beans. You need just declare @PropertyResources in config, add this config to you context, and use properties in controller. Of cause, you can autowire Environment, as you did in your example, and get properties from it. But in my opinion using of @Value annotation little bit more convenient:

    @Configuration
    @PropertySource(value= {"classpath:application.properties"})
    public class MyConfig{
    
        //spring will automatically bind value of property
        @Value("${my.property}")
        private String myProperty;
    
        //this bean needed to resolve ${property.name} syntax
        @Bean
        public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
            return new PropertySourcesPlaceholderConfigurer();
        }
    }
    

Same way in controllers:

    @Controller
    public class MyController{

        //spring will automatically bind value of property
        @Value("${my.property}")
        private String myProperty;

        @RequestMapping("/mapping")
        public String controllerMethod(){
             ...
        }
    }

Upvotes: 13

Related Questions