如何将数据源传递给库?

how to pass a datasource to a library?

我正在编写一个从特定数据模式检索数据的库。这个库包含一个可以是任何东西的数据源对象。现在我已经在我想避免的库中定义了数据源的名称。

import javax.sql.DataSource

public class MyLibraryDao.java {
   private static final DS_NAME = "MY_DS_NAME";

   @Resource(name = "default", lookup = DS_NAME , type = DataSource.class)
   protected DataSource dataSource;
}

DAO class 不直接暴露给客户端。中间有一个服务层:

import javax.inject.Inject;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Model;

@ApplicationScoped
@Model
public class MyLibraryService {

    @Inject
    MyLibraryDao dao;
}

现在,我如何将数据源对象传递给库?

我假设我需要在 DAO 中创建一个带有 DataSource 的构造函数,但是服务呢? 该库将在 CDI 环境中使用。

首先你的库需要一个数据源,让我们声明依赖关系:

public class MyLibraryDao {
   @Inject
   protected DataSource dataSource;
}

现在使用该库的应用程序的其余部分负责向 CDI 提供数据源;一个简单的方法是:

// Example; your implementation may vary
public class AppDatasourceProducer {
    private static final DS_NAME = "MY_APP_DS_NAME";

    @Resource(name = "default", lookup = DS_NAME , type = DataSource.class)
    protected DataSource dataSource;

    @Produces
    @ApplicationScoped
    public DataSource getDatasource() {
        return dataSource;
    }
}

有什么变化?现在 您的应用程序 负责了解数据源名称 AND 提供数据源本身。上面的示例可以在支持 @Resource 注释的 JEE 环境中工作。为提供者使用不同的实现可以在例如桌面环境(独立应用程序),使您的库可重用。

确切的数据源名称可能是固定的,就像在示例中一样,或者从配置中读取,例如来自系统属性(如评论中所述);例如:

// Example 2, DS name from system properties
@ApplicationScoped
public class AppDatasourceProducer {
    protected DataSource dataSource;

    @PostConstruct
    void init() throws Exception {
        String dsName = System.getProperty("XXXXX");
        InitialContext ic = new InitialContext();
        dataSource = (DataSource) ic.lookup(dsName);
    }

    @Produces
    @ApplicationScoped
    public DataSource getDatasource() {
        return dataSource;
    }
}

更进一步:

  1. 无论出于何种原因,使用您的库的应用程序可能正在使用多个数据源。您可能需要提供一个限定符来指定您的应用程序要使用的数据源。
  2. 为了简单起见,我在 MyLibraryDao 中使用了字段注入。如果您更改为构造函数注入,那么至少 MyLibraryDao 也可以在非 CDI 环境中使用,即如果您以某种方式获得了 DataSource,您现在可以 new MyLibraryDao(datasource)。更高的可重用性。