在最近的项目中,我遇到了一个有趣的问题:采用被赋予一个对象的服务方法,并在一个夜进程的上下文中重用相同的代码,该夜进程将独立于应用程序运行在数千个相同类型的对象上。
试图在两个地方维护如此大小和复杂性的相同过程真是荒谬的,所以我需要找到一种共享代码的方法。 一种可能的解决方案是使用DeltaSpike (Apache的CDI扩展集合)提供一种从主要Java / JPA / Hibernate应用程序访问实体和类的简单方法。
似乎有足够的文档来使DeltaSpike在网络上以类似情况运行,但是人们对该应用程序的可行性表示怀疑。 我的团队无法让它在项目的另一部分工作,因此继续使用Spring Batch。
最大的障碍是无法创建功能性的EntityManager,无论他们如何紧密地遵循可以找到的文档和示例。 该项目的较小部分为实现DeltaSpike提供了另一个很好的候选者,但是在对以下教程非常熟悉之后,找到了操作方法,并阅读了正式的实现说明,我被困在同一个地方:EntityManager只是将无法工作,至少不能与我面前的技术和版本组合使用。
幸运的是,我能够将弗兰肯斯坦的一些教程和示例中的部分放在一起,以针对我的情况获得可行的DeltaSpike实施,因此我想我将分享我发现的内容,以便下次其他人可能会更轻松一些。
基础
首先,我正在使用Maven,因此这里是您需要添加的依赖项:
<dependency>
<groupId>org.apache.deltaspike.cdictrl</groupId>
<artifactId>deltaspike-cdictrl-api</artifactId>
<version>1.2.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se</artifactId>
<version>1.1.16.Final</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.cdictrl</groupId>
<artifactId>deltaspike-cdictrl-weld</artifactId>
<version>1.2.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.core</groupId>
<artifactId>deltaspike-core-api</artifactId>
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.modules</groupId>
<artifactId>deltaspike-jpa-module-api</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.modules</groupId>
<artifactId>deltaspike-jpa-module-impl</artifactId>
<version>1.4.0</version>
</dependency>
如您所见,我们正在考虑在一个也需要JBoss / Weld的项目中实现DeltaSpike。 我所依赖的其他依赖项包括javax.enterprise,Hibernate和JPA。 根据最终的实现,您可能不需要所有这些DeltaSpike依赖项,因此请确保在完成后清理pom.xml。
应用程式
对于我的示例,我将使用一个基本的Application类,该类遵循您在其他DeltaSpike示例中可能看到的模式:
import javax.enterprise.context.ApplicationScoped;
import org.apache.deltaspike.cdise.api.CdiContainer;
import org.apache.deltaspike.cdise.api.CdiContainerLoader;
import org.apache.deltaspike.cdise.api.ContextControl;
import org.apache.deltaspike.core.api.config.ConfigResolver;
public class Application {
public static void main(String[] args) {
CdiContainer cdiContainer = CdiContainerLoader.getCdiContainer();
cdiContainer.boot();
ContextControl contextControl = cdiContainer.getContextControl();
contextControl.startContext(ApplicationScoped.class);
//Your code here
cdiContainer.shutdown();
}
}
特别注意这一行:
contextControl.startContext(ApplicationScoped.class);
该行查找带有@ApplicationScoped批注的类,这些类需要包含在上下文中。
EntityManagerProducer
这是棘手的地方。 遵循典型的DeltaSpike教程,将为您提供一个类似于以下内容的EntityManagerProducer:
@ApplicationScoped
public class EntityManagerProducer
{
@PersistenceUnit
private EntityManagerFactory entityManagerFactory;
@Produces
@Default
@RequestScoped
public EntityManager create()
{
return this.entityManagerFactory.createEntityManager();
}
public void dispose(@Disposes @Default EntityManager entityManager)
{
if (entityManager.isOpen())
{
entityManager.close();
}
}
}
考虑到我要处理的各种因素,我唯一遇到的问题是根本不起作用。 无论我尝试了什么,EntityManager始终为null。 我怀疑EntityManagerFactory不能正常工作,所以我做了一些挖掘,发现这种获取EntityManagerFactory的方法:
private EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory("PERSISTENCE_UNIT", setProperties());
使用此方法,我可以基于在persistence.xml中定义的持久性单元(它具有我在参数中提供的名称)来获得一个有效的EntityManagerFactory。 在这里,我定义了应用程序需要成为EntityManagerFactory一部分的实体,以便能够执行诸如运行之类的小事情。
这是新的和改进的EntityManagerProducer的外观:
@ApplicationScoped
public class EntityManagerProducer {
private EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("PERSISTENCE_UNIT", setProperties());
private EntityManager entityManager;
protected void closeEntityManager(@Disposes EntityManager entityManager) {
if (entityManager.isOpen()) {
entityManager.close();
}
}
@Produces
protected EntityManager createEntityManager() {
if (entityManager == null) {
entityManager = entityManagerFactory.createEntityManager();
}
return entityManager;
}
protected Properties setProperties() {
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect");
properties.setProperty("hibernate.show_sql", "false");
properties.setProperty("hibernate.hbm2ddl.auto", "none");
properties.setProperty("hibernate.enable_lazy_load_no_trans", "true");
properties.setProperty("hibernate.jdbc.batch_size", "20");
properties.setProperty("hibernate.connection.driver_class", "oracle.jdbc.driver.OracleDriver");
properties.setProperty("hibernate.connection.url", "JDBC_URL");
properties.setProperty("hibernate.default_schema", System.getProperty("SCHEMA_NAME"));
properties.setProperty("javax.persistence.jdbc.user", System.getProperty("USER"));
properties.setProperty("javax.persistence.jdbc.password", System.getProperty("PASSWORD"));
properties.setProperty("org.hibernate.flushMode", "ALWAYS");
return properties;
}
}
注意@ApplicationScoped标签; 这样可以确保在启动CDI容器时将此类包含在上下文中。 还要注意,您可以设置属性以将其传递到您创建的EntityManagerFactory中,包括从服务器参数中的系统属性中获取它们,如果环境变量可能会更改应用程序的功能,这将非常有用。
最后的想法
希望这为如何设置和实现DeltaSpike提供了一个简单有效的示例。 旁注:我最终无法使用这种方法来解决问题,因为要处理的对象数量比预期的要大得多(几百万),但是我认为分享我发现的内容仍然有用。
翻译自: https://www.javacodegeeks.com/2016/01/working-deltaspike-tutorial.html