我如何通过 Spring 中的 bean 名称自动装配接口的特定实现

How can I autowire a specific implementation of an interface by its bean name in Spring

我有 classes 实现了 MyInterface,它们的名字例如是: MyClassAMyClassB

如何通过 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;
    }
}