Andrew has posted 2 posts at DZone. View Full User Profile

Spring Dependencies - Opposite Direction, Please?

06.03.2008
| 4460 views |
  • submit to reddit

Here we'll see how to manage dependencies between beans in Spring framework context using "opposite direction" of such dependencies.

Spring is great in providing inversion of control container, instantiating beans, wiring them as well as managing their lifecycle. But can it be improved there?

Yes, Spring Framework is great. No doubts. I remember that excitement when I played with it first time (that's was several years ago). That's was great to see that after providing proper configuration the magic happened - all beans were instantiated and more importantly, they were wired together by container...

At that moment inversion of control was pretty new concept and things that were handled by Spring impressed us too much. Right at that time we've completed pretty large product that required sophisticated setup of components and dependencies between them and so we were totally disappointed that Spring appeared late..

Ok, Spring is great. But definitely one can be improved in some areas. Let's leave warious holy wars related to Spring alone and take a look to it's basic functionality - the IoC container. After all, that's one of the basic concept of Spring - so probably we'll be able to polish it a little there?

Let's imagine that we have two beans in our Spring context - BeanA and BeanB. And BeanA has property to which BeanB should be wired. If we'll omit autowiring issues there, such a dependency will be described in Spring context XML as follows:

<bean class="..." id="BeanA">
<property name="propertyThatRefersToB" ref="BeanB"/>
</bean>

<bean id="BeanB" class="..."/>


or, it could be even shorter if p: namespace from Spring 2.x is used:

<bean class="..." id="BeanA" 
p:propertyThatRefersToB-ref="BeanB"/>

In general, this way to instruct the Spring how to inject BeanB to BeanA is pretty fine and is more than enough in most situation.

Unfortunately, not in all.

The overall concept of Spring framework assumes that context is assembled when all beans are known (and that's pretty natural). However, that approach does not work well if application should be built using not solid, but rather plugin based architecture.

Recently, in one of projects we develop here in SoftAMIS we've got the same issue - the overall system should support dynamically loaded plugins (actually, the entire application could be considered as set of plugins) and, what is more important, generally speaking, that set of plugins is unknown so new plugins may be added later as well as existing ones may be disabled.

That's was the case were Spring container simply may fail...

Fortunately, in our application, plugins are assembled only during application startup, so we got different challenge - how to compose final Spring context from several configuration files. Since Spring initially supported dividing entire application context by several configuration files, that's was not to hard.

However, here we still had little trouble - in Spring, to make reference to bean, you need to know name of that bean. That's was obviously not acceptable for plugins - and what we needed there is ability to specify that reference not on parent bean (BeanA), but on bean that is referred - (BeanB).

Thus, instead of having top-to-bottom direction of references, we needed opposite one, that assumes that directly on the bean we may specify where one should be injected. The following picture illustrates such a difference between these approaches:

Difference between dependency directions

We've tried to find ready solution for that, but didn't find any that can satisfy our needs (please thing that actually there more complex types of references between beans exists - via list, map and set, for example).

So, necessity is mother of progress - and we've created small library that allows to have such opposite injections in Spring.

Thanks to support of custom namespaces in Spring 2.x, resulting markup was pretty simple. Like that:

<bean class="..." id="BeanA"/>

<bean class="..." id="BeanB">
<inject:to-ref target="BeanA" name="propertyThatRefersToB"/>
</bean>

Pretty simple, right? Please note tag from custom namespace (supported by Spring 2.x):

<inject:to-ref target="BeanA" name="propertyThatRefersToB"/>

Using it now we've just inverted direction in which we declare references between beans in Spring context - BeanA just could be considered as extension point which underlying BeanB may be plugged into. And think about having such ability to dynamically plug bean into list or map (yes, we have them already too) ....

Well, that's was description of generic idea. One of these days I'll post more detailed entry about that technology as well as provide complete source code for it - so stay tuned!

UPDATE:

I've added another entry to my blog that describes this issue more. And, from there the Inject4Spring library is available - it provides support for concepts I've described there.

Please use the following link to get it:

Introducing Inject4Spring
References
Published at DZone with permission of its author, Andrew Sazonov. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Ronald Miura replied on Tue, 2008/06/03 - 10:17am

Have you tried this?

class BeanB implements InializingBean {
   BeanA beanA;
   BeanB(BeanA beanA) {
      this.beanA = beanA;
   }
   void afterPropertiesSet() {
       beanA.register(this);
       beanA = null;
   }
}

or maybe

class BeanB {
   setBeanA(BeanA beanA) {
      beanA.register(this);
   }
}

Andrew Sazonov replied on Tue, 2008/06/03 - 10:57am in response to: Ronald Miura

Hi Roland,


Yes, sure, that will work... But it requires more coding (that's not an issues if there are only couple beans that should be wired, but that additional coding may require significant time if there are many such cases within application). Also, it hides details of registrations within code (for example, if I'd like to register bean in other' bean map under some key), that by my opinion, not too good.

And, in addition, it ties beans to Spring framework (since in your approach it's necessary to implement InitializingBean - that may be not good for some applications.

That's why we've created that small injection library that allows to wire such beans pretty similar to standard Spring way. I suppose I'll make it available one of these days - just need to polish it a little at the moment.

Regards,

Andrew

 

Ronald Miura replied on Tue, 2008/06/03 - 11:49am

It's 'Ronald'.

Well, the second option doesn't require you to implement any interface. Yet another option is to just query the context for beans that implement you 'Plugin' interface.

But nice work! I sometimes also feel that Spring is quite powerful when dealing with static structures, but is somewhat limited when it comes to dynamic discovery/configuration. Maybe OSGi (the latest and greatest silver bullet :)) will help in this.

Anyway, the fact that you were able to code such feature as an extension namespace just shows how the Spring component model is flexible :)

Bruno Borges replied on Tue, 2008/06/03 - 1:01pm

Why aren't you using auto-wire anyway?!

Ronald Miura replied on Tue, 2008/06/03 - 1:50pm

@Bruno: if the property to be injected is a list, the container won't automatically add all the compatible references (and I don't think it would always be desirable), and this would be a pretty common scenario in a plugin architecture.

And, autowire (the XML one, @Autowired is far less error-prone, because of its usage pattern) may cause strange bugs sometimes... For example, I was using the SchedulerFactoryBean for Quartz support. Everything was working fine, I was using the default jobStore in memory, but for some reason I turned the autowiring on, and suddenly the scheduler started to throw JDBC-related errors. But I didn't set up LocalDataSourceJobStore! Only after much research, I found the answer in the LocalDataSourceJobStore javadoc:

<cite>This JobStore will be used if SchedulerFactoryBean's "dataSource" property is set.<cite>

This is not mentioned in the SchedulerFactoryBean javadoc, and was triggered by the application's dataSource being 'autowired' into the scheduler. Solution: turn the autowiring off, either globally and wire everything by hand, or only for the scheduler and any other conflicting bean...

So, autowiring is nice, but use with caution! :)

Bruno Borges replied on Tue, 2008/06/03 - 2:13pm

Yeah, I know the risks when using autowiring. But even for your plugin concept, I see no difference between the normal direction and the opposite one. Either way, one bean must know of other's existence. From my point of view, you went from this: "BeanA, set this BeanB into your setBeanBProperty" to this --> "BeanB, set yourself at BeanA's setBeanBProperty".

Is these ways really that different between them? BeanB must know the id of BeanA anyway. And vice-versa using the usual way Spring suggests. What if BeanA would behave in a different way if the developer coded for an optional BeanB property? There are lots of beans like that, inclusive within Spring itself.  If one bean property is set, the bean will behave as it supposed to work with that dependency; if not it will figure out how to do their stuff without the dependency.

So imagine a BeanA provided from someone with an optional dependency injection. Then you put a BeanB and configure it with an opposite injection. Wow! Wasn't you that configured BeanA, sou you don't know how it works! Even worse: depending on the context, you should have never injected BeanB into BeanA because of some very weird BeanA's behaviour.

Your plugin concept is a little bit wrong IMHO. Your plugin should register itself somehow and just let others decide if they are going to be used or not. You register a plugin to Eclipse this way, and they work this way when they have any other dependency. 

"I depend on you. Are you registered? If yes, give me a hand. If not, I have two options: quit my job, or figure out how to do other's."

m2c 

Ronald Miura replied on Tue, 2008/06/03 - 3:37pm

The difference between 'A knows B' and 'B knows A' is, suppose A is a 'PluginRegistry' class. If every time a new plugin is added, you have to change the definition of the registry. It'd be a kind of 'Open-Close Principle' violation. You don't go changing any XML file when installing new plugins in Eclipse, do you? But the plugin surely knows how to register itself. Thus, 'B knows A' is less coupled than the 'A knows B'.

Sure, you could design a plugin architecture with extreme low-coupling between components (general-purpose APIs like OSGi probably are like that), but this adds complexity to the solution. Many times, it just isn't worth it. And when you do need something like that, just use the solutions available instead of rolling your own...

Bruno Borges replied on Tue, 2008/06/03 - 3:59pm

Indeed, I don't have to change any xml to tell Eclipse there's a new plugin. But in the case of Spring, Spring itself is *the* plugin repository. Who wants to use them, just call them. =)

Hitesh Lad replied on Tue, 2008/06/03 - 5:50pm

I've had similar situations. In this case, couldn't we use the MethodInvokingFactoryBean (org.springframework.beans.factory.config.MethodInvokingFactoryBean) . You can use that to set yourself as a property of BeanA.

Ales Justin replied on Wed, 2008/06/04 - 3:18am

Have a look at what we do in our Microcontainer (MC) project:

  • http://www.jboss.org/jbossmc

Since we're doing exactly what you need. :-)

And we already support Spring beans xml files, handling them via MC (no need for Spring lib in classpath, since we understand its schema):

  • http://anonsvn.jboss.org/repos/jbossas/projects/microcontainer/trunk/spring-int/

So no need to rewrite those config files.

OK, perhaps a small change in namespace si required. ;-)

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.