views:

535

answers:

3

I'm considering using Spring to assemble the components of my application, but I've got a problem. Our application uses a configuration repository that is global to the VM, and is similar (but not precisely) to the system properties.

This configuration API is accessed like so:

Configuration.getDb ().get ("some_property_name")

Is there any way to use values from this global configuration in Spring xml bean files? getDb may return a different value depending on the current state of the configuration library (it has context), but I'm willing to make the statement that the Spring configuration will be fully-loaded at application context initialization time. Still, something more flexible would be fantastic.

Given that I'm a Spring newbie, code examples would make my life a great deal easier.

+3  A: 

You can do this, although it's not the advised method of handling configuration data. Refer to 3.7 Container extension points of the Spring reference documentation.

Basically you will want to create a custom BeanFactoryPostProcessor implementation that will replace an expression like:

${some_property_name}

with the appropriate value based on the callback.

Look at the implementation of the PropertyPlaceholderConfigurer as a starting point.

cletus
+1  A: 

To expand on cletus' suggesrion, I'd say you want a custom subclass of PropertyPlaceholderConfigurer, and override the resolvePlaceholder() method, which would call your Configuration.getDb() code. If you can't resolve the value, then delegate back to the superclass.

For example:

public class MyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
    @Override
    protected String resolvePlaceholder(String placeholder, Properties props) {
        String value = Configuration.getDb().get(placeholder)
        if (value == null) {
            value = super.resolvePlaceholder(placeholder, props);
        }
        return value;
    }
}

Then just define a bean of type MyPlaceholderConfigurer in your application context, and spring will automagically consult your class to resolve the placeholder values.

If your Configuration.getDb() component can't resolve the value, then delegating back to the superclass allows spring to look up the value as a system property instead. Alternatively, you can inject a properties file into the bean, and it can check that also.

Read the ref docs on the basic usage of PropertyPlaceholderConfigurer, to get a feel for how it works. It's quite flexible.

skaffman
A: 

You could do this in configuration entirely (I am not saying this is really pretty ;):

<bean id="database" class="com.acme.Configuration" factory-method="getDb" />

<bean class="com.acme.YourHost">
  <property name="yourProperty">
    <bean factory-bean="database" factory-method="get">
      <constructor-arg value="some_property_name" />
    </bean>
  </property>
</bean>

Glad Spring 3.0 will contain an expression language for such cases (see blog post) :).

Oliver Gierke