Spring Bean Substitution

If we ever try to import a spring configuration from a packaged jar and need to customize some of the bean definitions, we would find ourselves having to do these things:

  1. extract the packaged configuration to somewhere we can actually edit;
  2. change the bean definition according to our needs;
  3. import the new configuration and exclude the original one.

Even though this works just fine, we will have to maintain the configuration copy and synchronize it with any updates made to the original one. This feels like forking our own branch from the spring configuration.

I think spring configuration can be a lot more flexible and powerful if we can substitute beans instead of having to redefine the whole bean dependency tree. Currently spring provides no such mechanism, so I tried a little hack utilizing the BeanFactoryPostProcessor and the BeanPostProcessor.

The idea comprises three parts:

  • BeanSubstitutionMapping
    • Users define which bean to be substituted and which bean is substituting.
  • BeanSubstitutionConfigurer implements BeanFactoryPostProcessor
    • When spring application context is created, it reads the substitution mappings and store them.
  • BeanSubstitutionProcessor implements BeanPostProcessor
    • Everytime a bean is requested, it reads the substitution mappings, checks if the bean to be loaded has been defined for substitution.
    • If the bean to be loaded has been mapped for substitution, it returns the substituting bean defined in the mapping instead.

Here is the difference when we use bean substitution:

  1. don’t need to extract the original packaged configuration;
  2. don’t need to exclude the original configuration;
  3. define our substituting bean;
  4. define the substitution mapping;
  5. no longer need to maintain and synchronize with jar updates, only need to maintain our own configuration.

I ran a simple test case described below. I was trying to substitute the “helloWorld” bean with “helloWorld2” bean.

In real world scenario, the bean definition for “helloWorld”, java class for HelloWorld, and HelloTaipei would be packaged in jar where we can only read but not modify. The bean definitions for “helloWorld2”, “config”, “mapping”, and java class HelloIrvine would be defined in our project where we are able to modify.

HelloWorld.java

public interface HelloWorld {
  public String print();
}

HelloTaipei.java

public class HelloTaipei implements HelloWorld {
  public String print() {
    return "Hello Taipei!";
  }
}

HelloIrvine.java

public class HelloIrvine implements HelloWorld {
  public String print() {
    return "Hello Irvine!";
  }
}

applicationContext.xml

<beans>
  <bean id="config" class="my.sandbox.beans.factory.config.BeanSubstitutionConfigurer"/>
  <bean id="helloWorld" class="my.sandbox.substitution.HelloTaipei"/>
  <bean id="helloWorld2" class="my.sandbox.substitution.HelloIrvine"/>
  <bean id="mapping" class="my.sandbox.beans.factory.config.BeanSubstitutionMapping">
<property name="targetBean" value="helloWorld"/>
<property name="sourceBean" value="helloWorld2"/>
  </bean>
</beans>

BeanSubstitutionTest.java

public class BeanSubstitutionTest extends
AbstractDependencyInjectionSpringContextTests {
  private HelloWorld helloWorld;
  public BeanSubstitutionTest() {
    setAutowireMode(AUTOWIRE_BY_NAME);
  }
  @Override
  protected String[] getConfigLocations() {
    return new String[] {
      "classpath*:META-INF/applicationContext.xml"
    };
  }
  public void testHelloWorld() {
    System.out.print(helloWorld.print());
  }
  ...
}

The BeanSubstitutionTest ran successfully and printed out “Hello Irvine!” instead of “Hello Taipei!”.

Note that even though BeanSubstitutionProcessor returns the substitution source bean instead of the substitution target bean, the target bean is already created by the application context when BeanSubstitutionProcessor kicks in. This means that we have an unused instance of the target bean in the application context.

Advertisements

3 Responses to “Spring Bean Substitution”

  1. hola~ found this when googling ur name hehe…are u writing a book here? jk, g’luck with everything…take cares

  2. springuser Says:

    this looks fantastic. Do you mind posting the sourcecode here?

  3. Hey, what does this syntax mean:
    “classpath*:META-INF/applicationContext.xml”
    what asterisks means?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: