brad12s
brad12s

Reputation: 409

Spring properites in multiple contexts using PropertySourcesPlaceholderConfigurer

Ok, I have been fighting this too long, time to ask for help. HELP?! I am unable to get my properties to work in one of my contexts using the PropertySourcesPlaceholderConfigurer.

I have 2 contexts: a rootContext:

AnnotationConfigWebApplicationContext rootContext = createContext(InfrastructureContextConfiguration.class);

And a dispatcherContext:

AnnotationConfigWebApplicationContext dispatcherContext = createContext(WebMvcContextConfiguration.class);

these get loaded like so:

public class MyWebApplicationInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
   registerListener(servletContext);
   registerDispatcherServlet(servletContext);
}

private void registerDispatcherServlet(ServletContext servletContext) {
   AnnotationConfigWebApplicationContext dispatcherContext = createContext(WebMvcContextConfiguration.class, WebFlowContextConfiguration.class);
   ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, new DispatcherServlet(dispatcherContext));
   dispatcher.setLoadOnStartup(1);
   dispatcher.addMapping("/");
}

private void registerListener(ServletContext servletContext) {
  AnnotationConfigWebApplicationContext rootContext = createContext(InfrastructureContextConfiguration.class );
  servletContext.addListener(new ContextLoaderListener(rootContext));
  servletContext.addListener(new RequestContextListener());
}

I create the PropertySourcesPlaceholderConfigurer and set the @PropertySource in the dispatcherContext WebMvcContextConfiguration:

@Configuration
@EnableWebMvc
@PropertySource("classpath:my.properties")
@ComponentScan(basePackages = { "com.me.my.web" })
public class WebMvcContextConfiguration extends WebMvcConfigurerAdapter {
@Bean
  public static PropertySourcesPlaceholderConfigurer  propertySourcesPlaceholderConfigurer() {
      return new PropertySourcesPlaceholderConfigurer();
   }
}

and therefore can access properties in this dispatcherContext using:

@Value( "${recaptcha.private.key}" )
private String recaptchaPrivateKey;   

The problem is that I can not get access to these properties from my rootContext. I have tried the @value annotation. I have tried to create a second PropertySourcesPlaceHolderConfigurer in the InfrastructureContextConfiguration class, ugh!

@Configuration
@EnableTransactionManagement
@PropertySource("classpath:my.properties")
@ComponentScan(basePackages = { "com.me.my.service", "com.me.my.repository",
  "com.me.my.domain.support" })
public class InfrastructureContextConfiguration {

//load properties from my.properties file 
@Value( "${mysql.db.driver.class}" )  //this is always null!   
private String mysqlDriverClass ;
...
}

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
   return new PropertySourcesPlaceholderConfigurer();
}  

@Bean
public DataSource dataSource() {
   BasicDataSource dataSource = new BasicDataSource();
   dataSource.setDriverClassName(mysqlDriverClass);
   ...
  }
 ...
}

Update: I've added a PropertySourcesPlaceHolderConfigurer and the @PropertySource("classpath:my.properties") to my InfrastructureContextConfiguration. I changed this class above to reflect my changes. Stepping through the InfrastructureContextConfiguration with the debugger I initially see any injected property is null but eventually they have values. For example in the Datasource dataSource() method the "mysqlDriverClass" is null hence this fails but later on in this class other beans are constructed with other injected properties with good/non-null values. At what point can I safely try to access these property values?

Answer to my update I figured out my issue. I was declaring the @Autowired DataSource member variable before my @Value injected properties and thus the dataSource was being initialized by the class before the injected properties were resolved.

Upvotes: 0

Views: 565

Answers (1)

Jigish
Jigish

Reputation: 1784

As @Patouche mentioned, beans defined in root application context are accessible in all web application contexts but it doesn't work the other way round.

Each DispatcherServlet has an associated web applicationContext that inherits from the root web application context. If you need a value or bean in root web application context, then you'll have to define it there.

See this discussion for more information. It also has a link to the relevant Spring documentation. Spring root WebApplicationContext for Servlet

Upvotes: 1

Related Questions