3

我在使用应用程序时遇到了一些问题,我使用 Guice 进行注入,其中一些后台任务由 Quartz 处理。

文档所述,我正在使用 PersistFilter 来处理我的事务并启动我的 JPAService。问题是我的作业第一次执行时,JPAService 还没有启动,我unitOfWork.begin()抛出了一个异常:

2013-07-01 11:45:05,527 [DefaultQuartzScheduler_Worker-1] ERROR com.foo.core.synchronization.impl.Result.notifyListener(Result.java:65) - Error while notifying synchronization listener
java.lang.NullPointerException
        at com.google.inject.persist.jpa.JpaPersistService.begin(JpaPersistService.java:70)
        at com.foo.convert.DiscoveryService.parsedElement(DiscoveryService.java:148)
        at com.foo.convert.DiscoveryService.parsedElement(DiscoveryService.java:67)
        at com.foo.core.synchronization.impl.Result.notifyListener(Result.java:62)
        at com.foo.core.synchronization.impl.Synchronizer.synchronize(Synchronizer.java:68)
        at com.foo.convert.DiscoveryService.execute(DiscoveryService.java:128)
        at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:557)

对该任务的所有下一次调用均成功。我敢打赌,persist 服务还没有启动,所以我尝试注入一个初始化程序:

public class MyInitializer { 
        @Inject MyInitializer(PersistService service) {
                service.start(); 
        } 
}

注入此初始化程序时,Quartz 作业立即运行,但第二次PersistFilter调用service.start()并且我的 Web 应用程序中断:

SEVERE: Exception starting filter Guice Filter
java.lang.IllegalStateException: Persistence service was already initialized.
    at com.google.inject.internal.util.$Preconditions.checkState(Preconditions.java:142)
    at com.google.inject.persist.jpa.JpaPersistService.start(JpaPersistService.java:88)
    at com.google.inject.persist.PersistFilter.init(PersistFilter.java:77)
    at com.google.inject.servlet.FilterDefinition.init(FilterDefinition.java:114)
    at com.google.inject.servlet.ManagedFilterPipeline.initPipeline(ManagedFilterPipeline.java:98)
    at com.google.inject.servlet.GuiceFilter.init(GuiceFilter.java:172)

注入PersistFilter我的QuartzInitializer也无济于事。

到目前为止,我实施的解决方法是在开始 Quartz 作业之前等待一分钟,但这不是一个长期的解决方案。

以前有人遇到过这个问题吗?

编辑:这似乎与这个问题有关问题 598:持久扩展:PersistService.start() 不能被多次调用

4

3 回答 3

4

通过覆盖默认的持久过滤器实现,我找到了另一种解决方法:

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.persist.PersistService;
import com.google.inject.persist.UnitOfWork;

/**
 * Overrides Guice implementation to handle when the persistence service is
 * already started
 * 
 * See http://stackoverflow.com/questions/17402081/how-to-start-jpa-in-a-guice-
 * quartz-web-application
 */
@Singleton
public final class PersistFilter implements Filter {
    private final UnitOfWork unitOfWork;
    private final PersistService persistService;

    @Inject
    public PersistFilter(UnitOfWork unitOfWork, PersistService persistService) {
        this.unitOfWork = unitOfWork;
        this.persistService = persistService;
    }

    public void init(FilterConfig filterConfig) throws ServletException {
        try {
            persistService.start();
        } catch (IllegalStateException e) {
            // Ignore exception is the persist service was already started
        }
    }

    public void destroy() {
        persistService.stop();
    }

    public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
            final FilterChain filterChain) throws IOException, ServletException {
        unitOfWork.begin();
        try {
            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            unitOfWork.end();
        }
    }
}

这样,我MyInitializer可以persistService.start()QuartzInitializer使用PersistFilter.

于 2013-07-01T10:35:32.690 回答
1

在将 Ugo 的解决方法用于 JPA + Guice + Shiro 时,我遇到了问题MyInitializer,使用自定义领域通过 jpa/hibernate 从数据库获取权限。每当出现映射错误时,都会导致一百万次注入失败。以下可靠地产生了单个堆栈跟踪并立即退出。它似乎也更干净一些,明确地启动服务而不是依赖注入......我担心注入的顺序可能会改变并把事情搞砸。

protected void configureServlets() {
    super.configureServlets();
    install(new JpaPersistModule("com.hcdware.jpa.persistence.unit"));

    final InjectionListener<PersistService> injectionListener = PersistService::start;

    TypeListener persistServiceListener = new TypeListener() {
        public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
            if (PersistService.class.isAssignableFrom(type.getRawType())) {
                @SuppressWarnings("unchecked") 
                TypeEncounter<PersistService> disposableEncounter = (TypeEncounter<PersistService>) encounter;
                disposableEncounter.register(injectionListener);
            }
        }
    };

    bindListener(new AbstractMatcher<TypeLiteral<?>>() {
        @Override
        public boolean matches(TypeLiteral<?> typeLiteral) {
            return PersistService.class.isAssignableFrom(typeLiteral.getRawType());
        }
    }, persistServiceListener); 

    // proceed with the bindings...

}

从那里,使用 Ugo Méda 建议的修改后的 PersistFilter

这是基于这里的一篇不错的文章:http: //developer.vz.net/2012/02/08/extending-guice-2/

于 2016-07-11T02:57:10.727 回答
0

为什么以及如何最终使用持久过滤器?Quartz 应该使用与 PersistFilter 运行的 http 上下文无关的单独线程池。覆盖 persistfilter 以忽略异常对我来说是一种代码味道。我刚开始工作单元

execute(JobExecutionContext context) 

@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
    try {
        unitOfWork.begin();
        //use classes that  have em manager provider and decorated with        //@Transaction.
    } finally {
        unitOfWork.end();
    }
}
于 2016-10-24T11:58:59.550 回答