Home > Java > Spring beans overwriting strategy

Spring beans overwriting strategy

I find myself working more and more with Spring these days, and what I find raises questions. This week, my thoughts are turned toward beans overwriting, that is registering more than one bean with the samee name.

In the case of a simple project, there’s no need for this; but when building a a plugin architecture around a core, it may be a solution. Here are some facts I uncovered and verified regarding beans overwriting.

Single bean id per file
The id attribute in the Spring bean file is of type ID, meaning you can have only a single bean with a specific ID in a specific Spring beans definition file.
Overwriting bean dependent on context fragments loading order
As opposed to classpath loading where the first class takes priority over those others further on the classpath, it’s the last bean of the same name that is finally used. That’s why I called it overwriting. Reversing the fragment loading order proves that.
Fragment assembling methods define an order
Fragments can be assembled from statements in the Spring beans definition file or through an external component (e.g. the Spring context listener in a web app or test classes). All define a deterministic order.
As a side note, though I formerly used import statements in my projects (in part to take advantage of IDE support), experience taught me it can bite you in the back when reusing modules: I’m in favor of assembling through external components now.
Names
Spring lets you define names in addition to ids (which is a cheap way of putting illegals characters fors ID). Those names also overwrites ids.
Aliases
Spring lets you define aliases of existing beans: those aliases also overwrites ids.
Scope overwriting
This one is really mean: by overwriting a bean, you also overwrite scope. So, if the original bean had a specified scope and you do not specify the same, tough luck: you just probably changed the application behavior.

Not only are perhaps not known by your development team, but the last one is the killer reason not to overwrite beans. It’s too easy to forget scoping the overwritten bean.

In order to address plugins architecture, and given you do not want to walk the OSGi path, I would suggest what I consider a KISS (yet elegant) solution.

Let us use simple Java properties in conjunction with ProperyPlaceholderConfigurer. The main Spring Beans definition file should define placeholders for beans that can be overwritten and read two defined properties file: one wrapped inside the core JAR and the other on a predefined path (eventually set by a JVM property).

Both property files have the same structure: fully-qualified interface names as keys and fully-qualified implementations names as values. This way, you define default implementations in the internal property file and let uses overwrite them in the external file (if necessary).

As an added advantage, it shields users from Spring so they are not tied to the framework.

Sources for this article can be found in Maven/Eclipse format here.

email
Send to Kindle
Categories: Java Tags:
  1. Michael
    February 18th, 2013 at 12:31 | #1

    Actually, there are even more ways of “overwriting” Spring beans. The two that came into my mind immediately are profiles and the attribute “primary”.

    Profiles can be used to distinguish between deployment environments, build variations etc. However, you have to ensure that profiles using the same bean name are mutually exclusive if you want to achieve a selection of either bean A or bean B (or C or D or…), otherwise you might run into unexpected behavior.

    In addition to that, you can always add the attribute primary=”true” (or @Primary if you are using Java configuration) to the bean you would like to be used. An example: You have a bean called someService defined in your production ApplicationContext, which resolves to an implementation which uses other production services, databases etc. This bean can easily be replaced with a mock implementation in a text context by simply defining another bean with the name someService and the primary attribute being set.

  2. Ringo
    February 27th, 2013 at 15:41 | #2

    I’ve sometimes used the @Primary annotation as Michael suggests. I think it’s a simple way to extend a bean… you can subclass a @Service, override and/or add new methods, mark it as @Primary and that’s it.

    The problem comes when you need to extend a @Controller… suppose you want to subclass an existing controller and override some method (which is annotated with a @RequestMapping). Controllers are not injected, so the @Primary trick does not work here and there will be two working controllers (the original and your subclass), and as you can’t use the same @RequestMapping more than once for the same url, the subclass is going to make a conflict.
    I’m still looking for a simple way to tell spring to map the url to my subclass method, and ignore the parent’s :-)

  1. No trackbacks yet.