perdian
perdian

Reputation: 2843

Customizable @Autowired

Let's assume I have an annotated bean property setter like this:

public class Foo {
  ...
  @Autowired 
  public void setBar(Bar bar) {
    ...
}

The Springframework will lookup the matching Bar property as usual. However, I'd like to intercept the default bean resolving process and add a little bit of "magic" myself. I'd like to introduce a resolver like this:

public interface SomeResolverInterface<T> {
  public T resolve(Class<T> beanClass);
}

public class BarResolver implements SomeResolverInterface<Bar> {

  @Override
  public Bar resolve(Class<Bar> beanClass) {
    if(someCondition) {
      return someBean;
    } else {
      return anotherBean;
    }
  }

  ...

I know I could alway introduce some kind of wrapper bean and move the resolving logic into this but I'd prefer a more generic way using a resolver like described above to make Foo completely independent of the resolving logic.

Is there a way within the Springframework to achieve something like this?

Upvotes: 3

Views: 250

Answers (3)

Bozho
Bozho

Reputation: 597124

Apart from the @Configuration option provided by Tomasz, you can use a simple FactoryBean. Just implement the interface, and declare the factory bean. In the getObject() method perform your custom logic.

Upvotes: 2

Tomasz Nurkiewicz
Tomasz Nurkiewicz

Reputation: 340763

From your description it looks like you only need to perform additional logic at startup time (autowiring). There are several ways to tackle this problem (from worst to best):

  • AOP - bad idea, introduces runtime overhead by intercepting every call

  • custom scope - see: Custom spring scopes? Also works at runtime and also a bad idea

  • @Profile - define two matching beans and enable only one based on active profile. Pretty clean and introduces overhead only at startup time

  • @Configuration - defining beans in Java has an extra benefit of having full control over how are they created:


@Configuration
public class Config {

    @Autowired
    private Bar someBean;

    @Autowired
    private Bar anotherBean;

    @Bean
    @Primary
    public Bar primaryBean() {
        if(someCondition) {
          return someBean;
        } else {
          return anotherBean;
        }
      }

}

As you can see in this case we have three beans of Bar type: someBean, anotherBean and primaryBean. The first two can also be configured using @Bean or via component scan with @Service. But to make autowiring possible the last primaryBean is marked as @Primary. This way it will be preferred over other two.

This is my recommended solution as the resolving logic is clean, maintainable and readable. IMHO this is the situation where Java-based @Configuration really shines.

Upvotes: 4

maximdim
maximdim

Reputation: 8169

Although I have never tried this I think you could look at plugging your logic via

AnnotationConfigUtils

Or look at

AutowiredAnnotationBeanPostProcessor

and see if it allows for simple extension/pluggability of your logic

Upvotes: 0

Related Questions