4

我正在尝试定义一个自定义的 DeltaSpike ConfigSource。自定义配置源将具有最高优先级,并检查数据库中的配置参数。

我有一个 ConfigParameter 实体,它只有一个键和一个值。

@Entity
@Cacheable
public class ConfigParameter ... {

      private String key;
      private String value;

}

我有一个@Dependent可以找到所有配置参数的 DAO。

我现在要做的是定义一个自定义 ConfigSource,它能够从数据库中获取配置参数。因此,我想在 ConfigSource 中注入我的 DAO。所以基本上像

@ApplicationScoped
public class DatabaseConfigSource implements ConfigSource {

    @Inject
    private ConfigParameterDao configParameterDao;

    ....
}

但是,当通过META-INF/services/org.apache.deltaspike.core.spi.config.ConfigSource注册 ConfigSource 时,该类将被实例化,CDI 将不起作用。

有没有办法让 CDI 在这种情况下工作?

在此先感谢您,如果您需要任何进一步的信息,请告诉我。

4

3 回答 3

1

即使这篇文章已经得到了回答,我还是想为这个问题提出另一种可能的解决方案。

我设法通过创建一个@Signleton @StartupEJB 从我的数据库服务加载属性,该 EJB 扩展org.apache.deltaspike.core.impl.config.BaseConfigSource并注入我的 DAO 作为委托,然后我将其注册到org.apache.deltaspike.core.api.config.ConfigResolver.

@Startup
@Singleton
public class DatabaseConfigSourceBean extends BaseConfigSource {

    private static final Logger logger = LoggerFactory.getLogger(DatabaseConfigSourceBean.class);

    private @Inject PropertyService delegateService;

    @PostConstruct
    public void onStartup() {
        ConfigResolver.addConfigSources(Collections.singletonList(this));
        logger.info("Registered the DatabaseConfigSourceBean in the ConfigSourceProvider ...");
    }

    @Override
    public Map<String, String> getProperties() {
        return delegateService.getProperties();
    }

    @Override
    public String getPropertyValue(String key) {
        return delegateService.getPropertyValue(key);
    }

    @Override
    public String getConfigName() {
        return DatabaseConfigSourceBean.class.getSimpleName();
    }

    @Override
    public boolean isScannable() {
        return true;
    }
}

我知道为此目的创建一个 EJB 基本上会产生太大的开销,我认为这是一个更清洁的解决方案,而不是通过一些带有静态访问器的标记布尔值来处理这个问题......

于 2019-04-13T09:19:59.097 回答
0

DS 正在为此使用不是 CD'Injectable'的 java se spi机制。一种解决方案是使用BeanProvider来获取您的 DatabaseConfigSource 并将操作委托给它。

于 2016-05-18T13:52:18.420 回答
0

主要问题是,当 BeanManager 尚不可用时,ConfigSource 很早就被实例化了。即使是 JNDI 查找在那个时间点也不起作用。因此,我需要延迟注入/查找。

我现在所做的是向我的配置源添加一个静态布尔值,这是我手动设置的。我们有一个 InitializerService 来确保系统设置正确。在初始化过程结束时,我调用allowInitialization()以告诉配置源,该 bean 现在是可注入的。下次询问 ConfigSource 时,它​​将能够使用BeanProvider.injectFields.

public class DatabaseConfigSource implements ConfigSource {

    private static boolean allowInit;

    @Inject
    private ConfigParameterProvider configParameterProvider;

    @Override
    public int getOrdinal() {
        return 500;
    }

    @Override
    public String getPropertyValue(String key) {
        initIfNecessary();

        if (configParameterProvider == null) {
            return null;
        }

        return configParameterProvider.getProperty(key);
    }

    public static void allowInitialization() {
        allowInit = true;
    }

    private void initIfNecessary() {
        if (allowInit) {
            BeanProvider.injectFields(this);
        }
    }

}

我有一个请求范围的 bean,它包含我所有的配置变量以进行类型安全访问。

@RequestScoped
public class Configuration {

    @Inject
    @ConfigProperty(name = "myProperty")
    private String myProperty;

    @Inject
    @ConfigProperty(name = "myProperty2")
    private String myProperty2;

    ....

}

当在不同的 bean 中注入 Configuration 类时,每个 ConfigProperty 都会被解析。由于我的自定义 DatabaseConfigSource 具有最高序数 (500),因此它将首先用于属性解析。如果找不到该属性,它会将解析委托给下一个 ConfigSource。

对于每个 ConfigProperty,getPropertyValue都会调用 DatabaseConfigSource 中的函数。由于我不想从数据库中检索每个配置属性的参数,因此我将配置属性解析移至请求范围的 bean。

@RequestScoped
public class ConfigParameterProvider {

    @Inject
    private ConfigParameterDao configParameterDao;

    private Map<String, String> configParameters = new HashMap<>();

    @PostConstruct
    public void init() {
        List<ConfigParameter> configParams = configParameterDao.findAll();
        configParameters = configParams.stream()
            .collect(toMap(ConfigParameter::getId, ConfigParameter::getValue));
    }

    public String getProperty(String key) {
        return configParameters.get(key);
    }

}

我可以肯定将请求范围的 ConfigParameterProvider 更改为 ApplicationScoped。但是,我们有一个多租户设置,并且需要根据请求解析参数。

如您所见,这有点 hacky,因为我们需要明确告诉 ConfigSource,何时允许正确实例化(注入 bean)。

我更喜欢 DeltaSpike 的标准化解决方案,以便在 ConfigSource 中使用 CDI。如果您对如何正确实现这一点有任何想法,请告诉我。

于 2016-05-19T13:28:28.243 回答