【问题标题】:Transferring CDI qualifier to injected field将 CDI 限定符转移到注入字段
【发布时间】:2015-05-16 14:38:19
【问题描述】:

我正在 Wildfly 8.2 容器中开发 Java EE 7 应用程序,该容器包含一些存在于两个数据源中的实体。示例:

我有一个带有Setting 实体的罐子:

@Entity
public class Setting {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @NotNull
    private String name;
    private String value;

    getters/setters...
}

还有一个 bean,它有几个方法可以通过条件查询从数据库中检索和保存这个实体:

@Stateless
public class SettingRepository {
    @Inject
    private Logger logger;

    @Inject
    private EntityManager entityManager;

    public Setting findByName(@NotNull String name) {
        logger.trace("Getting setting by name: name=" + name);
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<Setting> cq = cb.createQuery(Setting.class);
        Root<Setting> table = cq.from(Setting.class);
        cq.where(cb.equal(table.get(Setting_.name), name));

        TypedQuery<Setting> query = entityManager.createQuery(cq);
        List<Setting> results = query.getResultList();
        Setting setting = null;

        if (results.size() > 0)
            setting = results.get(0);

        logger.trace("Got setting: " + setting);
        return setting;
    }

    ...
}

我不想在一个应用程序中通过@Producer 提供EntityManagerLogger 实例,该应用程序在类路径中包含这个jar,如下所示:

@Produces @DataSource1 @PersistenceContext(unitName = "pu1")
private EntityManager entityManager1;

@Produces @DataSource2 @PersistenceContext(unitName = "pu2")
private EntityManager entityManager2;

@Produces
private Logger produceLogger(InjectionPoint injectionPoint) {
    return LogManager.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}

有没有办法在注入点配置 SettingRepository 并告诉它使用特定的实体管理器(@DataSource1@DataSource2)?

与此类似:

@Inject @DataSource1
private SettingRepository settingRepository;

【问题讨论】:

    标签: java jakarta-ee cdi java-ee-7


    【解决方案1】:

    我选择的路线是这样的:

    我创建了一个限定符

    @Qualifier
    @Retention(RUNTIME)
    @Target({ METHOD, FIELD, PARAMETER })
    public @interface DataSource {
        @Nonbinding DataSourceName value() default DataSourceName.D1;
    }
    

    注意@Nonbinding注解,它告诉容器我在注解生产者方法(尤其是这个,因为我可以实现通用生产者,稍后会详细介绍)或注入点时不必指定此参数。

    还有DataSourceName枚举,它简单地列出了所有数据源:

    public enum DataSourceName {
        D1, D2
    }
    

    我还更改了SettingRepository 实现并添加了一个公共初始化方法。

    @Dependent
    public class SettingRepository {
        @Inject
        private Logger logger;
    
        private EntityManager entityManager;
    
        public void initialize(EntityManager entityManager) {
            this.entityManager = entityManager;
        }
    
        ...
    }
    

    请注意,EntityManager 不再由容器注入。

    当我不想注入 SettingRepository 时,我只是用这个限定符来装饰它,如下所示:

    @Inject @DataSource(DataSourceName.D1)
    private SettingRepository settingRepository;
    

    我现在只需要为SettingRepository 定义一个生产者:

    @Stateless
    public class TestResourcesForSettings {
        @PersistenceContext(unitName = "pu1")
        private EntityManager entityManager1;
    
        @PersistenceContext(unitName = "pu2")
        private EntityManager entityManager2;
    
        @Inject
        private SettingRepository settingRepository;
    
        @Produces @DataSource
        public SettingRepository produceSettingRepository(InjectionPoint ip) {
            DataSource annotation = ip.getAnnotated().getAnnotation(DataSource.class);
    
            if (annotation.value() == DataSourceName.D1)
                settingRepository.initialize(entityManager1);
            else if (annotation.value() == DataSourceName.D2)
                settingRepository.initialize(entityManager2);
    
            return settingRepository;
        }
    

    瞧,我可以在一个存储库实现中使用两个数据源(注意:数据源必须是 XA)。 如果有人发现此选择有任何问题,请告诉我。

    【讨论】:

      【解决方案2】:

      是的!

      事实上,就生产者方法和限定符而言,您已经完成了所有艰苦的工作 :-) 您需要做的就是在注入的 EntityManager 实例上使用您的限定符(@DataSource1 等)

      @Inject @DataSource1
      private EntityManager entityManager;
      

      这将确保附加到持久性单元“pu1”的 JPA 实体管理器由容器注入。

      【讨论】:

      • 谢谢,但我第一次知道我需要哪个数据源是SettingsRepository注入点而不是EntityManager注入点。所以我想知道是否有一种方法可以将限定符从父注入点(SettingsRepository)“转移”到子注入点(EntityManager),或者在每种方法上使用参数更好。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-22
      • 2023-04-07
      • 1970-01-01
      • 2011-11-26
      • 2019-05-26
      • 1970-01-01
      相关资源
      最近更新 更多