我应该在哪里为 Spring 的 @Qualifier 注解定义常量?

Flo*_*ian 5 spring dependency-injection

Spring 的依赖注入允许使用注释区分同一接口的多个实现@Qualifier("<flavor>")

例如,我们可以有:

public class Consumer {
  @Autowired("b") private SomeInterface dependency;
}

public interface SomeInterface { }

@Component @Qualifier("a")
public class VariantA implements SomeInterface { }

@Component @Qualifier("b")
public class VariantB implements SomeInterface { }
Run Code Online (Sandbox Code Playgroud)

这要求消费者和实现都使用相同的常量字符串来标识变体,在本例中为“a”和“b”。作为一名干净的编码员,我的第一个冲动是为这些字符串创建常量。

但我应该把它们放在哪里呢?

A、消费者

将它们放入 Consumer 中是不可能的,因为这会将依赖关系反转到非法方向,要求实现了解其消费者:

public class Consumer {
  public final static String VARIANT_B = "b";
  @Autowired(Consumer.VARIANT_B) private SomeInterface dependency;
}

@Component @Qualifier(Consumer.VARIANT_B)
public class VariantB implements SomeInterface { }
Run Code Online (Sandbox Code Playgroud)

B. 实施

将它们放入实现中似乎也不是重点,重新引入依赖注入首先想要删除的消费者知道实现依赖:

public class Consumer {
  @Autowired(VariantB.VARIANT_B) private SomeInterface dependency;
}

@Component @Qualifier(VariantB.VARIANT_B)
public class VariantB implements SomeInterface {
  public final static String VARIANT_B = "b";
}
Run Code Online (Sandbox Code Playgroud)

三、接口

将它们放在界面中似乎是一种选择,但只有当界面是我的并且我可以自由更改它时才可能。另外,让接口事先“知道”其所有实现变体的概念听起来有点奇怪。

public class Consumer {
  @Autowired(SomeInterface.VARIANT_B) private SomeInterface dependency;
}

public interface SomeInterface {
  public final static String VARIANT_A = "a";
  public final static String VARIANT_B = "b";
}

@Component @Qualifier(SomeInterface.VARIANT_A)
public class VariantA implements SomeInterface { }

@Component @Qualifier(SomeInterface.VARIANT_B)
public class VariantB implements SomeInterface { }
Run Code Online (Sandbox Code Playgroud)

D、常量类

最干净的解决方案似乎是将常量放入单独的开发对象中。然而,这看起来有点开销:

public class Consumer {
  @Autowired(ImplementationVariant.B) private SomeInterface dependency;
}

public interface SomeInterface { }

public class ImplementationVariant {
  public final static String A= "a";
  public final static String B= "b";
}

@Component @Qualifier(ImplementationVariant.A)
public class VariantA implements SomeInterface { }

@Component @Qualifier(ImplementationVariant.B)
public class VariantB implements SomeInterface { }
Run Code Online (Sandbox Code Playgroud)

dav*_*xxx 0

我会选择E:标准方式。

添加这种间接来识别beans名称会增加样板代码,这不是标准的(您的同行会感到惊讶),而且也不健壮。
为什么没有健壮?限定符需要一个字符串,而不是一个强限制的枚举值。这意味着您可以传递不正确的字符串,例如@Component @Qualifier(OtherImplementationVariant.B),它仍然可以正常编译。

实现这一目标的更强大的替代方案是支持@Bean具有并使用的 bean 的方法工厂@Qualifier,以便通过调用该@Bean方法来设置 bean 之间的依赖关系。但是,将它们概括为这样的要求仍然很冗长,而且根本不标准。所以也不是一个好主意。

所以我认为你应该坚持标准,因为如果发生不匹配并且无法解决依赖关系,那么在 spring boot 启动时就会检测到该问题