将对象注入过滤器
Posted
技术标签:
【中文标题】将对象注入过滤器【英文标题】:Injecting Objects into Filters 【发布时间】:2015-07-14 17:23:59 【问题描述】:我创建了一个扩展 jersey 的 ContainerRequestFilter 的服务器过滤器,我想在这个自定义过滤器中注入一个 (EntityManager) 对象。为此,我创建了一个实现 jersey 的 hk2.api.Factory 和配置的工厂。此设置成功地将对象注入到资源中,但是无法将对象注入到过滤器中。
有谁知道如何配置 jersey 以?
原始错误:
一个 MultiException 有 3 个异常。他们是:
java.lang.IllegalStateException:不在请求范围内。 java.lang.IllegalArgumentException: 在尝试解决 co.example.filters.Filter 的依赖项时发现错误 java.lang.IllegalStateException:无法执行操作:在 co.example.filters.Filter 上解析
错误消息:
警告:已检测到以下警告:警告:未知 检测到 HK2 故障:MultiException 堆栈 1 of 2 javax.persistence.PersistenceException:[PersistenceUnit:egunit] 无法在以下位置构建 Hibernate SessionFactory org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl。 在 org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.access$600(EntityManagerFactoryBuilderImpl.java:120) 在 org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:860) 在 org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850) 在 org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:425) 在 org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:849) 在 org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:75) 在 org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:54) 在 javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55) 在 javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:39) 在 co.example.factories.ExampleEntityManagerFactory.(ExampleEntityManagerFactory.java:21)
...
...
...
MultiException 堆栈 2 of 2 java.lang.IllegalStateException:无法执行操作:创建 在 co.example.factories.ExampleEntityManagerFactory 上 org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:395) 在 org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:471) 在 org.jvnet.hk2.internal.PerLookupContext.findOrCreate(PerLookupContext.java:69) 在 org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2064) 在 org.jvnet.hk2.internal.ServiceHandleImpl.getService(ServiceHandleImpl.java:105) 在 org.jvnet.hk2.internal.ServiceHandleImpl.getService(ServiceHandleImpl.java:87) 在 org.jvnet.hk2.internal.FactoryCreator.create(FactoryCreator.java:117) 在 org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:471) 在 org.glassfish.jersey.process.internal.Reque.findOrCreate(RequestScope.java:162) 在 org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2064) 在 org.jvnet.hk2.internal.ServiceLocatorImpl.internalGetService(ServiceLocatorImpl.java:711) 在 org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:661) 在 org.jvnet.hk2.internal.IterableProviderImpl.get(IterableProviderImpl.java:108) 在 co.example.filters.Filter.filter(Filter.java:35)
自定义过滤器:
@Provider
public class Filter implements ContainerRequestFilter
@Inject private javax.inject.Provider<EntityManager> entityManagerProvider;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException
EntityManager entityManager = entityManagerProvider.get();
EntityDao ed = new EntityDao(entityManager);
...
工厂:
public class ExampleEntityManagerFactory implements Factory<EntityManager>
private final CloseableService closeableService;
private final EntityManagerFactory entityManagerFactory;
@Inject
public ExampleEntityManagerFactory(CloseableService closeableService)
this.closeableService = closeableService;
this.entityManagerFactory = Persistence.createEntityManagerFactory("egunit");
@Override
public EntityManager provide()
final EntityManager instance = entityManagerFactory.createEntityManager();
//closeableService.add(new Closeable()
// @Override
// public void close() throws IOException
// if (instance.isOpen()) instance.close();
//
//);
return instance;
@Override
public void dispose(EntityManager instance)
if (instance.isOpen()) instance.close();
绑定:
public class Configuration extends ResourceConfig
public Configuration()
...
register(new AbstractBinder()
@Override
protected void configure()
bindFactory(ExampleEntityManagerFactory.class).to(EntityManager.class).in(RequestScoped.class);
);
【问题讨论】:
编辑后,您现在遇到的问题(异常)与在我的回答中建议的更改之前是否相同? 编辑前和编辑后的例外情况不一样。预编辑异常是不在请求范围内,而后编辑似乎提供者无法返回正确的EntityManagerFactory
和随后的EntityManager
实例。关于如何进行的想法/想法?
看看this post。可能有关系。请注意,EMF 不是在 EM 工厂内部创建的,而是作为单例注入的。尝试做出改变,看看会发生什么。另外,不要在provide
中创建 EM,而是尝试在构造函数中创建它,也如帖子中所示。似乎它是在每次查找中调用的,它的范围比请求范围小。不知道为什么会这样。
【参考方案1】:
如果没有看到一些代码(和验证),很难确定,但我只是做一个有根据的猜测,并说这是一个范围界定问题。 EntityManager
应该本来就在请求范围内,所以我猜这就是你设置它的方式。所以它在你的资源类中运行良好,我猜它也是请求范围的(默认行为)。
另一方面,您的 ContainerRequestFilter
在单例范围内。因此,尝试将范围为 EntityManager
的请求注入单例范围的过滤器是不可能的,并且您可能会在启动时收到消息“不在请求范围内”。
一个简单的解决方法是简单地注入javax.inject.Provider<EntityManager>
。它在 javadoc 中声明了关于 Provider
的一件事:
相比直接注入
抽象范围,以便您可以从包含范围内的实例中查找较小范围内的实例。T
,注入Provider<T>
:
就这样吧
@Provider
public static class Filter implements ContainerRequestFilter
@Inject
private javax.inject.Provider<EntityManager> emProvider;
@Override
public void filter(ContainerRequestContext request) throws IOException
EntityManager em = emProvider.get();
鉴于其他所有功能都正常,这应该可以工作(经测试)。如果这不是问题/解决方案,请发布一些代码和完整的堆栈跟踪。
对于任何感兴趣的人,这里是完整的测试,使用Jersey Test Framework。
仅需要 Maven 依赖项
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.17</version>
<scope>test</scope>
</dependency>
测试(如果你想看到它失败,删除过滤器中的javax.inject.Provider
,然后简单注入EntityManager
)
import java.io.IOException;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import junit.framework.Assert;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
public class FilterScopeTest extends JerseyTest
public static class EntityManager
public String getEntity()
return "Some Entity";
public void close()
public static class EntityManagerFactory implements Factory<EntityManager>
EntityManager em = new EntityManager();
public EntityManagerFactory()
System.out.println("+++++ EntityManagerFactory Created +++++");
@Override
public EntityManager provide()
return em;
@Override
public void dispose(EntityManager t)
em.close();
public static class Binder extends AbstractBinder
@Override
protected void configure()
bindFactory(EntityManagerFactory.class).to(EntityManager.class).in(RequestScoped.class);
@Provider
public static class Filter implements ContainerRequestFilter
@Inject
private javax.inject.Provider<EntityManager> em;
public Filter()
System.out.println("+++++ Filter Created +++++");
@Override
public void filter(ContainerRequestContext request) throws IOException
System.out.println("+++++ In filter EM is null: " + (em.get() == null) + " +++++");
System.out.println("+++++ EM entity value: " + (em.get().getEntity()) + " +++++");
@Path("em")
public static class EmResource
@Inject
EntityManager em;
@GET
public String getStuff()
return em.getEntity();
@Override
public Application configure()
return new ResourceConfig(EmResource.class, Filter.class).register(new Binder());
@Test
public void doIt()
Response response = target("em").request().get();
Assert.assertEquals(200, response.getStatus());
System.out.println(response.readEntity(String.class));
response.close();
@Test
public void doIt2()
Response response = target("em").request().get();
Assert.assertEquals(200, response.getStatus());
System.out.println(response.readEntity(String.class));
response.close();
【讨论】:
在对自定义过滤器类进行建议的更改后,当执行 Provider 的get
方法时,Hibernate Session Factory 无法构建,进而导致 EntityManagerFactory 的创建失败。有什么建议/想法吗?我已在原帖中添加了相关代码和堆栈跟踪。以上是关于将对象注入过滤器的主要内容,如果未能解决你的问题,请参考以下文章