开发者

A question about qualifier in Spring DI

Normally, a qualified component will be injected to annotated fields with the same qualifier:

@Component        class Apple1 implements IApple {}
@Component @Black class Apple2 implements IApple {}

class User {
    @Inject        IApple apple;        // -> Apple1
    @Inject @Black IApple blackApple;   // -> Apple2
    @Inject @Red   IApple redApple;     // -> Error: not defined
}

What I want is, if a component with specific qualifier isn't de开发者_JAVA技巧fined, I'd like to give a default one, so the redApple in above example will be injected with an instance of Apple1.

Is it possible? Or can I implement a specific qualifier matching strategy for Spring DI?

** EDIT **

I know subclass will work, but this is an example to describe the question, so subclass isn't applicable here.


If you try to inject something with a qualify where no bean exists for: like @Inject @Red IApple redApple; then you will get an: NoSuchBeanDefinitionException.

This exception occures no matter if you use:

  • @Inject
  • @Resource
  • @Autowire

The reason is simple: Spring DI first search determine all autowire candidates.

  • if there is exactly one, the it uses this candidate
  • if there is no candidate, it raise a NoSuchBeanDefinitionException
  • if there is more then one, it tryes to determine the primery candidate out of the candiates.

@See org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency

line 785..809 (3.0.4.RELEASE)

So what you need to do is putting the fall back (Apple) one in the set of candiates, but make sure that it is only used if there is no other candidate. Because there is no way to mark a bean as fall back or less importend, you need to mark the normal bean as more important: @primary.

So the (proved) solution would be annotating

  • the Black and Red Apple with @Black and @Red and with @Primary.
  • the default fallback Apple (Apple1) with with @Red and @Black, but without @Primary.

Example:

@Component @Red @Black public class Apple1 implements IApple {} //fall back
@Component @Black @Primary public class Apple2 implements IApple {}

@Component public class AppleEater {
  @Inject @Black IApple blackApple; // -> Apple2
  @Inject @Red IApple redApple; // -> Apple1
}

Possible improvement: If you don't like to add all annotations (@Black, @Red, @AllOtherStangeColors) to your fall back bean, you could try to implment your your own AutowireCandiateResolver so that it adds the fall back bean to all candiate lists of the required type (Apple) @see Reference Documentation: 3.9.4 CustomAutowireConfigurer

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜