当@Context用于setter / field / constructor注入时,HK2 Factory在Jerseyfilter之前调用
我已经能够根据如何将对象注入到jersey请求上下文中从filter注入我的jersey资源? 。 这允许我成功注入方法参数:
@GET public Response getTest(@Context MyObject myObject) { // this works
但是,对于setter / field / constructor注入,HK2 Factory在jerseyfilter之前调用,这意味着provide()方法返回null:
@Override public MyObject provide() { // returns null because the filter has not yet run, // and the property has not yet been set return (MyObject)context.getProperty("myObject"); }
有没有办法定义何时运行HK2 Factory以便在filter运行后调用它? 如果没有,则解决方法是将MyObject定义为接口,并定义在其构造函数中采用ContainerRequestContext的其他实现; 任何实际使用该实例的尝试都将懒惰地委托给在ContainerRequestContext属性上设置的实现(可能在filter运行之前你不会实际使用该实例 – 此时将设置该属性)。
但我想了解是否有可能延迟HK2工厂运行的点,使其在filter之后运行(在方法参数注入的情况下,它已在filter之后运行)。 如果不可能,那么我想了解是否存在根本原因。
奇怪的是,它只适用于我在filter上使用@PreMatching
(这限制了对您可能需要或可能不需要的某些内容的访问)。 不太确定引擎盖下发生了什么,如果没有它就不能工作:-(。以下是使用Jersey Test Framework的完整测试。
import java.io.IOException; import javax.inject.Inject; import javax.inject.Singleton; 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.container.PreMatching; import javax.ws.rs.core.Application; import javax.ws.rs.core.Context; import javax.ws.rs.ext.Provider; import org.glassfish.hk2.utilities.binding.AbstractBinder; import org.glassfish.jersey.process.internal.RequestScoped; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory; import org.glassfish.jersey.test.JerseyTest; import org.junit.Assert; import org.junit.Test; public class FilterInjectionTest extends JerseyTest { private static final String MESSAGE = "Inject OK"; private static final String OBJ_PROP = "myObject"; public static class MyObject { private final String value; public MyObject(String value) { this.value = value; } public String getValue() { return value; } } @PreMatching @Provider public static class MyObjectFilter implements ContainerRequestFilter { @Override public void filter(ContainerRequestContext context) throws IOException { MyObject obj = new MyObject(MESSAGE); context.setProperty(OBJ_PROP, obj); } } public static class MyObjectFactory extends AbstractContainerRequestValueFactory { @Override @RequestScoped public MyObject provide() { return (MyObject) getContainerRequest().getProperty(OBJ_PROP); } @Override public void dispose(MyObject t) { } } @Path("method-param") public static class MethodParamResource { @GET public String getResponse(@Context MyObject myObject) { return myObject.getValue(); } } @Path("constructor") public static class ConstructorResource { private final MyObject myObject; @Inject public ConstructorResource(@Context MyObject myObject) { this.myObject = myObject; } @GET public String getResponse() { return myObject.getValue(); } } @Path("field") public static class FieldResource { @Inject private MyObject myObject; @GET public String getResponse() { return myObject.getValue(); } } @Override public Application configure() { ResourceConfig config = new ResourceConfig(); config.register(MethodParamResource.class); config.register(MyObjectFilter.class); config.register(ConstructorResource.class); config.register(FieldResource.class); config.register(new AbstractBinder() { @Override protected void configure() { bindFactory(MyObjectFactory.class) .to(MyObject.class).in(Singleton.class); } }); return config; } @Test public void methoParamInjectionOk() { String response = target("method-param").request().get(String.class); Assert.assertEquals(MESSAGE, response); System.out.println(response); } @Test public void costructorInjectionOk() { String response = target("constructor").request().get(String.class); Assert.assertEquals(MESSAGE, response); System.out.println(response); } @Test public void fieldInjectionOk() { String response = target("field").request().get(String.class); Assert.assertEquals(MESSAGE, response); System.out.println(response); } }
UPDATE
解决方案,无需使其成为@PreMatching
filter,是使用javax.inject.Provider
注入。 这将允许您懒惰地检索对象。 我想构造函数和字段注入会在匹配资源类之后发生,它会立即创建并注入。 由于尚未调用filter,因此工厂没有对象。 它适用于方法注入,因为它就像任何其他方法调用一样。 调用该方法时,该对象将传递给它。 下面是javax.inject.Provider
的示例
@Path("constructor") public static class ConstructorResource { private final javax.inject.Provider myObjectProvider; @Inject public ConstructorResource(javax.inject.Provider myObjectProvider) { this.myObjectProvider = myObjectProvider; } @GET public String getResponse() { return myObjectProvider.get().getValue(); } } @Path("field") public static class FieldResource { @Inject private javax.inject.Provider myObjectProvider;; @GET public String getResponse() { return myObjectProvider.get().getValue(); } }
- 如何在spring boot中使用应用程序上下文获取bean
- 可以在JSR 330中使@Inject成为可选项(如@Autowire(required = false)吗?
- Android使用dependency injection简单的自定义类
- Glassfish 4,CDI中的简单示例因WELD-001408不满意的依赖性而失败
- 如何以静态方法以编程方式将Java CDI托管bean注入局部变量
- JavaConfig中的Spring Bean别名
- 如何在jersey / hk2应用程序中正确配置EntityManager?
- 在静态方法中使用注入bean的正确方法是什么?
- 使用自定义参数注入变量而不创建2个guice helper接口?