在混合租赁环境中生成EntityManager

时间:2017-06-06 18:07:12

标签: java jpa java-ee cdi

我有这样的要求,即每个客户必须将他的数据单独存储在一个单独的数据库中。

我想实现以下结构:

  1. 全局微服务处理身份验证,并提供有关存储客户端数据的数据库的信息。
  2. 其他微服务,在请求时,查询auth服务以了解客户端数据库信息,然后才生成实体管理器。
  3. 我正在努力正确管理EntityManagerFactory个实例的状态。

    我试图在WeakHashMap中存储,但是一些错误的事情开始发生。就像简单的findById抛出异常一样。

    我实际上正在使用JEE和在Payara服务器上运行的DeltaSpike数据。

    任何人都曾使用过类似的堆栈吗?

1 个答案:

答案 0 :(得分:-1)

如果您使用bean managed transaction,那么使用CDI来管理此类实体管理器工厂资源变得更加容易。

首先创建一个数据源上下文注释。

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE, PARAMETER, FIELD, METHOD})
public @interface Datasource {

    /**
     * This may be the database url or whatever.
     */
    @Nonbinding
    String value() default "";

}

@SuppressWarnings("AnnotationAsSuperInterface")
public class DatasourceLiteral extends AnnotationLiteral<Datasource> implements Datasource {

    private static final long serialVersionUID = 7485753390480718735L;

    private final String dbName;

    public DatasourceLiteral(final String dbName) {
        this.dbName = dbName;
    }

    @Override
    public String value() {
        return dbName;
    }

}

@ApplicationScoped
public class EntityManagerFactoryProvider {

    @Produces
    @Datasource
    @ApplicationScoped
    public EntityManagerFactory entityManagerFactory(final InjectionPoint ip) {
        final Annotated annotated = ip.getAnnotated();
        final Datasource datasource = annotated.getAnnotation(Datasource.class);

        /**
         * Add relevant jpa properties
         */
        final Map<String, String> jpaProperties = new HashMap<>();

        /**
         * The main point is here.
         */
        jpaProperties.put("javax.persistence.jdbc.url", datasource.value());

        return Persistence.createEntityManagerFactory("persistence-unit-jpa", jpaProperties);
    }

    public void dispose(@Disposes @Datasource final EntityManagerFactory emf) {
        emf.close();
    }

}

@ApplicationScoped
public class ExampleUserDatasource {

    @Any
    @Inject
    private Instance<EntityManagerFactory> entityManagerFactories;

    public void doSomething(final String user) {
        final UserInfo userInfo = authenticationService.getUser(user);
        final Datasource datasource = new DatasourceLiteral(userInfo.getDatasource());
        final EntityManagerFactory entityManagerFactory = entityManagerFactories.select(datasource).get();

        /**
         * You could also actually inject this.
         * Do whatever you want with it inside a transaction and close it too.
         */
        final EntityManager entityManager = entityManagerFactory.createEntityManager();
    }

}