同一提供者的多个实例

时间:2013-11-18 06:48:47

标签: guice

我创建了一个DataSourceProvider来查找容器管理的dataSource:

public class ContainerDataSourceProvider implements Provider<DataSource> {
    private final DataSource ds;

    @Inject
    ContainerDataSourceProvider (String dataSourceName) throws NamingException {
        Context initCtx = new InitialContext();
        Context envCtx = (Context) initCtx.lookup("java:comp/env");
        ds = (DataSource) envCtx.lookup("jdbc/" + dataSourceName);
    }

    @Override
    public DataSource get() {
        return ds;
    }
}

我不能在提供者上使用@Named注释,因为我希望能够根据dataSourceName提供不同的数据源。

在我的模块中,我想使用提供程序提供多个dataSource绑定。 jdni datasorce的名称来自已绑定到Names的属性文件。

//How do I configure ContainerDataSourceProvider with jndi name "userDataSource"????
binder.bind(DataSource.class).annotatedWith(UserDS.class)
                .toProvider(ContainerDataSourceProvider.class);

//How do I configure ContainerDataSourceProvider with jndi name "sessionDataSource"????
binder.bind(DataSource.class).annotatedWith(SessionDS.class)
                .toProvider(ContainerDataSourceProvider.class);

然后在我的代码中,我将能够执行类似

的操作
public class UserDSClient {
       @Inject UserDSClient (@UserDS DataSource ds) {}
}

public class SessionDSClient {
       @Inject SessionDSClient (@SessionDS DataSource ds) {}
}

我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:1)

这很简单。手动创建提供程序,将数据源名称传递给其构造函数:

public class ContainerDataSourceProvider implements Provider<DataSource> {
    private final String dataSourceName;

    @Inject
    ContainerDataSourceProvider (String dataSourceName) {
        this.dataSourceName = dataSourceName;
    }

    @Override
    public DataSource get() {
        try {
            Context initCtx = new InitialContext();
            Context envCtx = (Context) initCtx.lookup("java:comp/env");
            return (DataSource) envCtx.lookup("jdbc/" + dataSourceName);
        } catch (NamingException e) {
            throw new RuntimeException(e);
        }
    }
}

我还将上下文查找代码移到get()方法。如果将绑定放在单例范围内,这在性能方面是完全安全的 - 在这种情况下,Guice足够聪明,只能调用provider方法一次。这是绑定:

binder.bind(DataSource.class).annotatedWith(UserDS.class)
    .toProvider(new ContainerDataSourceProvider("userDataSource"))
    .in(Singleton.class);

binder.bind(DataSource.class).annotatedWith(SessionDS.class)
    .toProvider(new ContainerDataSourceProvider("sessionDataSource"))
    .in(Singleton.class);

就是这样。

BTW,因为某些原因查找可能会失败,在异常被抛出时,您的代码中的依赖关系解析时间(在Guice.createInjector()调用或injector.getInstance()调用中)都会出现异常来自构造函数,以及我的变体。如果您需要处理此错误,请考虑使用throwing providers扩展名。

答案 1 :(得分:0)

强烈建议您使用Private Modules。私有模块将隐藏环境中的所有绑定信息。因此,您可以在不使用Annotations的情况下将不同的实现注入同一个接口。

好吧,我做了一个演讲。也许它会帮助你了解私有模块的想法。 http://slid.es/milanbaran/dec