我如何通过 Spring 中的 bean 名称自动装配接口的特定实现
How can I autowire a specific implementation of an interface by its bean name in Spring
我有 classes 实现了 MyInterface,它们的名字例如是:
MyClassA
、MyClassB
等
如何通过 bean 名称获取 class 的实例?类似于:
context.getBean("myClassA")
context.getBean("myClassB")
我可以不在 XML 中配置 beans 吗?
我想使用注释
您可以使用qualifiers,例如:
@Component
@Qualifier("classA")
public MyInterface ClassA {
return new ClassA();
}
@Component
@Qualifier("classB")
public MyInterface ClassB {
return new ClassB();
}
并像这样使用它:
public class SomeClass {
@Autowired
@Qualifier("classA")
private MyInterface classA;
}
这里有多种选择。最简单的方法是使用 @Autowire
:
将字段名称用作组件名称
@Component("testClassA") // It is possible to omit explicit bean name declaration here since Spring will use a class name starting from lower case letter as a bean name by default. So just `@Component` should be sufficient here and below.
public TestClassA implements MyInterface {
}
@Component("testClassB")
public TestClassB implements MyInterface {
}
/*
* Note that field names are the same as the component names.
*/
@Component
public class TestClassWithDependencies {
@Autowired
private MyInterface testClassA;
@Autowired
private MyInterface testClassB;
}
另一种选择是使用 qualifiers:
@Component
@Qualifier("testClassA")
public TestClassA implements MyInterface {
}
@Component
@Qualifier("testClassB")
public TestClassB implements MyInterface {
}
@Component
public class TestClassWithDependencies {
@Autowired
@Qualifier("testClassA")
private MyInterface testClassA;
@Autowired
@Qualifier("testClassB")
private MyInterface testClassB;
}
当您需要反复使用相同的限定符时,您甚至可以创建自己的 meta-annotations:
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier("testClassA")
public @interface TestClassACustomQualifier {
String value();
}
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier("testClassB")
public @interface TestClassBCustomQualifier {
String value();
}
@Component
public class TestClassWithDependencies {
@Autowired
@TestClassACustomQualifier
private MyInterface testClassA;
@Autowired
@TestClassBCustomQualifier
private MyInterface testClassB;
}
漂亮多了,不是吗?另一种选择是使用 JSR-250 规范中的 @Resource。正如@hovanessyan 所指出的,它更像是 JavaEE 的做事风格,但我仍然认为这是一种在许多项目中使用的可行方法:
@Component("testClassA")
public TestClassA implements MyInterface {
}
@Component("testClassB")
public TestClassB implements MyInterface {
}
@Component
public class TestClassWithDependencies {
@Resource(name="testClassA")
private MyInterface testClassA;
@Resource(name="testClassB")
private MyInterface testClassB;
}
您可以在 https://www.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/ 上获得更多信息,其中讨论了添加了测试的不同方法。
希望对您有所帮助!
我认为如果以上选项还不够,那么 factory implementation
是动态获取实例的一种方法 -
@Component
public TestClassA implements MyInterface {
}
@Component
public TestClassB implements MyInterface {
}
以这种方式定义您的工厂 -
public class MyInterfaceFactory extends AbstractFactoryBean<MyInterface> {
private String filter;
@Override
public Class<?> getObjectType() {
return MyInterface.class;
}
@Override
protected MyInterface createInstance() throws Exception {
MyInterface myInterface;
switch (filter)
{
case "1":
myInterface = new TestClassA();
break;
case "2":
myInterface = new TestClassB();
break;
default: throw new IllegalArgumentException("No such type.");
}
return myInterface;
}
}
and then your bean config -
@Configuration
public class FactoryBeanConfig {
@Bean(name = "myInterface")
public MyInterfaceFactory myInterfaceFactory() {
MyInterfaceFactory factory = new MyInterfaceFactory();
factory.setFilter("7070");
return factory;
}
}
我有 classes 实现了 MyInterface,它们的名字例如是:
MyClassA
、MyClassB
等
如何通过 bean 名称获取 class 的实例?类似于:
context.getBean("myClassA")
context.getBean("myClassB")
我可以不在 XML 中配置 beans 吗? 我想使用注释
您可以使用qualifiers,例如:
@Component
@Qualifier("classA")
public MyInterface ClassA {
return new ClassA();
}
@Component
@Qualifier("classB")
public MyInterface ClassB {
return new ClassB();
}
并像这样使用它:
public class SomeClass {
@Autowired
@Qualifier("classA")
private MyInterface classA;
}
这里有多种选择。最简单的方法是使用 @Autowire
:
@Component("testClassA") // It is possible to omit explicit bean name declaration here since Spring will use a class name starting from lower case letter as a bean name by default. So just `@Component` should be sufficient here and below.
public TestClassA implements MyInterface {
}
@Component("testClassB")
public TestClassB implements MyInterface {
}
/*
* Note that field names are the same as the component names.
*/
@Component
public class TestClassWithDependencies {
@Autowired
private MyInterface testClassA;
@Autowired
private MyInterface testClassB;
}
另一种选择是使用 qualifiers:
@Component
@Qualifier("testClassA")
public TestClassA implements MyInterface {
}
@Component
@Qualifier("testClassB")
public TestClassB implements MyInterface {
}
@Component
public class TestClassWithDependencies {
@Autowired
@Qualifier("testClassA")
private MyInterface testClassA;
@Autowired
@Qualifier("testClassB")
private MyInterface testClassB;
}
当您需要反复使用相同的限定符时,您甚至可以创建自己的 meta-annotations:
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier("testClassA")
public @interface TestClassACustomQualifier {
String value();
}
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier("testClassB")
public @interface TestClassBCustomQualifier {
String value();
}
@Component
public class TestClassWithDependencies {
@Autowired
@TestClassACustomQualifier
private MyInterface testClassA;
@Autowired
@TestClassBCustomQualifier
private MyInterface testClassB;
}
漂亮多了,不是吗?另一种选择是使用 JSR-250 规范中的 @Resource。正如@hovanessyan 所指出的,它更像是 JavaEE 的做事风格,但我仍然认为这是一种在许多项目中使用的可行方法:
@Component("testClassA")
public TestClassA implements MyInterface {
}
@Component("testClassB")
public TestClassB implements MyInterface {
}
@Component
public class TestClassWithDependencies {
@Resource(name="testClassA")
private MyInterface testClassA;
@Resource(name="testClassB")
private MyInterface testClassB;
}
您可以在 https://www.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/ 上获得更多信息,其中讨论了添加了测试的不同方法。
希望对您有所帮助!
我认为如果以上选项还不够,那么 factory implementation
是动态获取实例的一种方法 -
@Component
public TestClassA implements MyInterface {
}
@Component
public TestClassB implements MyInterface {
}
以这种方式定义您的工厂 -
public class MyInterfaceFactory extends AbstractFactoryBean<MyInterface> {
private String filter;
@Override
public Class<?> getObjectType() {
return MyInterface.class;
}
@Override
protected MyInterface createInstance() throws Exception {
MyInterface myInterface;
switch (filter)
{
case "1":
myInterface = new TestClassA();
break;
case "2":
myInterface = new TestClassB();
break;
default: throw new IllegalArgumentException("No such type.");
}
return myInterface;
}
}
and then your bean config -
@Configuration
public class FactoryBeanConfig {
@Bean(name = "myInterface")
public MyInterfaceFactory myInterfaceFactory() {
MyInterfaceFactory factory = new MyInterfaceFactory();
factory.setFilter("7070");
return factory;
}
}