Announcement Announcement Module
Collapse
No announcement yet.
adding PropertySources to Environment - how to ensure refresh() called after? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • adding PropertySources to Environment - how to ensure refresh() called after?

    I have a Properties object that I'd like add as PropertySource to be used in interpolation throughout my app. ie in any bean within my app I would like to be able to do this:
    Code:
    ctx.getEnvironment.resolvePlaceholders("${myProp}); //myProp is in the above Properties object
    From Environment JavaDoc:
    When an Environment is being used by an ApplicationContext, it is important that any such PropertySource manipulations be performed before the context's refresh() method is called.
    How can the above be accomplished? - within WebApp contexts but also within unit-test env?

    I tried creating a bean that would add PropertySource and calling ctx.refresh() but a unit test with config below seems to use GenericXmlApplicationContext which does not support (repeat) calls to refresh()

  • #2
    I am not sure I am clear on what you are trying to accomplish. But if you add a PropertySource to the PropertySourcesPlaceholderConfigurer you can access those properties through Spring's Environment. If you want refreshable properties take a look at ReloadableResourceBundleMessageSource.

    Comment


    • #3
      Profiles with properties files

      I really don't now if is this user case apply, but I saw a lot of people with the some problem: how to set a active profile without messing with bash variables or java system.properties?
      The most common case: you have a "jndi" connection to your database in your production code, but the integration tests runs with a local driver.
      Until now (Spring 3.1) you have a lot of xml files and with some profiles in Maven (don't confuse them with Spring profiles) you copy the desired one to the default if you are in production, or in dev, etc.
      When I read about profiles in Spring I thought that mess is over. A simple property file with my active profile et voilá. Well not so fast.

      A sample test file with context in @Configuration classes
      Code:
      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = {MongoTemplateConfig.class, LazVirtualMongoConfig.class, ProductionMongoConfig.class})
      public class MongoTest {
      
          @Autowired
          private MongoTemplate mongoTemplate;
      
          @Test
          public void crudTest() {
      
              mongoTemplate.dropCollection(PersonTrack.class);
             ...
      The configuration classes
      Ex:
      Code:
      @Configuration
      @Profile("dev")
      public class LazVirtualMongoConfig implements MongoConfig {
      
          @Override
          public @Bean
          MongoFactoryBean mongo() {
              MongoFactoryBean mongo = new MongoFactoryBean();
              mongo.setHost("lazvirtual.iol.pt");
              mongo.setWriteConcern(WriteConcern.SAFE);
              return mongo;
          }
      }
      are annotated with different profiles and everything works fine if I put the @ActiveProfile("dev") or @ActiveProfile("prd") in the test class.

      But that gives me again a hard coded configuration!
      What I need is the possibility of reading a external property file and set my active profile before the AnnotationConfigContextLoader registries the configuration classes.
      After reading everything Google gives me about the subject I find the solution in... the javadoc of AbstractGenericContextLoader:
      Code:
                /**
      	 * Prepare the {@link GenericApplicationContext} created by this<code>ContextLoader</code>.
      	 * Called <i>before</i> bean definitions are read.
      	 * <p>The default implementation is empty. Can be overridden in subclasses to
      	 * customize <code>GenericApplicationContext</code>'s standard settings.
      	 * @param context the context that should be prepared
      	 * @see #loadContext(MergedContextConfiguration)
      	 * @see #loadContext(String...)
      	 * @see GenericApplicationContext#setAllowBeanDefinitionOverriding
      	 * @see GenericApplicationContext#setResourceLoader
      	 * @see GenericApplicationContext#setId
      	 * @since 2.5
      	 */
      	protected void prepareContext(GenericApplicationContext context) {
      	}
      The AnnotationConfigContextLoader extends this class and mine become:

      Code:
      public class MyAnnotationConfigContextLoader extends AnnotationConfigContextLoader{
      
          
          @Override
          protected void prepareContext(GenericApplicationContext context){
              try {
                  context.getEnvironment().getPropertySources().addFirst(new ResourcePropertySource("classpath:env.properties"));
              } catch (IOException ex) {
                  
              }
              context.getEnvironment().setActiveProfiles(context.getEnvironment().getProperty("env"));
          }
      
      }
      And it works like a champion.
      The only thing we have to do is change the annotation to
      Code:
      @ContextConfiguration(loader = MyAnnotationConfigContextLoader.class, classes = {MongoTemplateConfig.class, LazVirtualMongoConfig.class, ProductionMongoConfig.class})
      If someone has a better aproach....
      Last edited by fsoares; Feb 28th, 2012, 08:46 AM.

      Comment

      Working...
      X