关于Java:如何使用Google Guice在运行时基于注释注入接口实现

How to inject an interface implementation based on annotations at runtime using Google Guice

我有以下情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public interface ServiceClientAdapter {
    SomeData getSomeData()
}

@LegacyServiceClientAdapter
public class MyLegacyServiceClientAdapterImpl implements ServiceClientAdapter {
    public SomeData getSomeData() {
        // implementation          
    }
}

@NewServiceClientAdapter
public class MyNewServiceClientAdapterImpl implements ServiceClientAdapter  {
    public SomeData getSomeData() {
        // implementation          
    }    
}

public class BusinessLogic {
    @Inject
    private ServiceClientAdapter serviceClientAdapter;
}

LegacyServiceClientAdapter和NewServiceClientAdapter是自定义注释。

serviceClientAdapter字段的实现将在运行时根据用户是否已从旧版迁移到新服务来

使用Google Guice完成此依赖项注入的最佳方法是什么?

考虑到将存在不同的BusinessLogic类,每个类都具有自己的(不同的)类似于ServiceClientAdapter的接口以及相应的旧版和新实现类。

理想情况下,这应该使用可在所有用例中使用的一段框架代码来完成。


我将假设LDAP调用的结果可以表示为字符串,例如"legacy""new"。 如果没有,希望您仍然可以改编这个例子。

在您的模块中,使用MapBinder:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class BusinessLogicModule {
    @Override
    protected void configure() {
        // create empty map binder
        MapBinder<String, ServiceClientAdapter> mapBinder =
                MapBinder.newMapBinder(
                        binder(), String.class, ServiceClientAdapter.class);

        // bind different impls, keyed by descriptive strings
        mapBinder.addBinding("legacy")
                .to(MyLegacyServiceClientAdapterImpl.class);
        mapBinder.addBinding("new")
                .to(MyNewServiceClientAdapterImpl.class);
    }
}

现在,您可以将实例映射(如果需要继续创建新实例,则可以注入实例提供者的映射)到您的主类中,并使用在运行时发现的字符串来控制您获得哪种类型的实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class BusinessLogic {
    @Inject
    private ServiceClientAdapter serviceClientAdapter;

    @Inject
    private Map<String, ServiceClientAdapter> mapBinder;

    public void setupAndUseClientAdapter() {
        String userType = getUserTypeFromLdapServer();
        serviceClientAdapter = mapBinder.get(userType);
        if (serviceClientAdapter == null) {
            throw new IllegalArgumentException(
                   "No service client adapter available for" +
                    userType +" user type.";
        }
        doStuffWithServiceClientAdapter();
    }
}