2013-07-01 51 views
3

我在應用程序中遇到了一些麻煩,我使用Guice進行Quartz處理的一些後臺任務的注入。如何在Guice + Quartz Web應用程序中啓動JPA?

正如documentation所述,我使用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) 

所有的任務的下一個電話是全成。我的賭注是,堅持服務尚未開始,所以我試圖注入一個初始化:

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

當注射這種初始化,石英工作正在向右走,但PersistFilter電話service.start()第二次,我的網站應用程序中斷:

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) 

注入在我QuartzInitializer也沒有幫助的PersistFilter

到目前爲止,我實現的解決方法是在開始Quartz作業之前等待一分鐘,但這不是一個長期的解決方案。

以前有人有過這個問題嗎?

編輯:這似乎堅持過濾器實現對與此有關的問題Issue 598: Persist Extension: PersistService.start() cannot be called multiple times

回答

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

+0

鑑於thiat這是從吉斯類,你可能應該提供屬性名稱相同的代碼的90%逐字複製,這是受到來自ASL 2.0,你會繼承這些限制當你修改一個ASL 2.0的工作時......另外,你正在重新實現,而不是重寫,因爲你沒有從他們的類繼承。 – Gus

1

我對Ugo的MyInitializer解決方法存在問題,將其用於JPA + Guice + Shiro,並使用自定義領域通過jpa/hibernate從db獲取權限。無論何時出現映射錯誤,結果都會導致一百萬次注入失敗。以下內容可靠地生成一個堆棧跟蹤並立即退出。它似乎也更清潔一些,明確地啓動服務而不是依靠注入......我擔心注入的順序可能會改變並拋棄。

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... 

} 

從那裏,使用由烏戈梅達

建議修改PersistFilter這是基於一個不錯的文章在這裏:http://developer.vz.net/2012/02/08/extending-guice-2/

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(); 
    } 
} 
相關問題