Вот что я в конечном итоге придумал, основываясь на отзывах GWT Google Group и БобВ.
Создайте локальный держатель потока для EntityManager; ссылайтесь на это в своих объектах, когда им нужно получить EntityManager:
public class ThreadLocalEntityManager
{
private static ThreadLocal<EntityManager> holder = new ThreadLocal<EntityManager>();
private ThreadLocalEntityManager()
{
}
public static EntityManager get()
{
return holder.get();
}
public static void set(EntityManager em)
{
holder.set(em);
}
}
Затем создайте фильтр, который установит начальный EntityManager для запроса:
public class PersistenceFilter implements Filter
{
protected static final Logger log = Logger.getLogger(PersistenceFilter.class.getName());
private EntityManagerFactory factory;
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
factory = Persistence.createEntityManagerFactory("my_persistence");
}
@Override
public void destroy()
{
factory.close();
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
{
EntityManager em = factory.createEntityManager();
ThreadLocalEntityManager.set(em);
EntityTransaction tx = em.getTransaction();
tx.begin();
try
{
chain.doFilter(req, res);
tx.commit();
}
catch (Exception e)
{
tx.rollback();
}
finally
{
log.info("closing EntityManager: " + EMF.entityManager());
em.close();
}
}
}
Затем примените фильтр к шаблону URL /gwtRequest:
<filter>
<filter-name>PersistenceFilter</filter-name>
<filter-class>com.example.PersistenceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>PersistenceFilter</filter-name>
<url-pattern>/gwtRequest</url-pattern>
</filter-mapping>
Обратите внимание, что здесь есть недостаток — EntityManager создается для каждого запроса, проходящего через этот сервлет, независимо от того, используется ли он вашим базовым кодом или нет. Вероятно, его можно было бы сделать более надежным и каким-то образом лениво создавать EntityManager (и транзакцию) только по запросу.
Но пока этот код работает хорошо с RequestFactory
. Предложения по улучшению приветствуются.
Примечание: этот опыт научил меня тому, что, вероятно, стоит перейти на полноценный CDI, а не пытаться реализовать его части, подобные этому. У меня просто не было времени на такой ход во время этого проекта.
person
George Armhold
schedule
15.02.2011