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”。作为一名干净的编码员,我的第一个冲动是为这些字符串创建常量。
但我应该把它们放在哪里呢?
将它们放入 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)
将它们放入实现中似乎也不是重点,重新引入依赖注入首先想要删除的消费者知道实现依赖:
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)
最干净的解决方案似乎是将常量放入单独的开发对象中。然而,这看起来有点开销:
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)
我会选择E:标准方式。
添加这种间接来识别beans名称会增加样板代码,这不是标准的(您的同行会感到惊讶),而且也不健壮。
为什么没有健壮?限定符需要一个字符串,而不是一个强限制的枚举值。这意味着您可以传递不正确的字符串,例如@Component @Qualifier(OtherImplementationVariant.B),它仍然可以正常编译。
实现这一目标的更强大的替代方案是支持@Bean具有并使用的 bean 的方法工厂@Qualifier,以便通过调用该@Bean方法来设置 bean 之间的依赖关系。但是,将它们概括为这样的要求仍然很冗长,而且根本不标准。所以也不是一个好主意。
所以我认为你应该坚持标准,因为如果发生不匹配并且无法解决依赖关系,那么在 spring boot 启动时就会检测到该问题。