Spring Jersey 在请求范围内注入 ContainerRequestContext class

Spring Jersey to inject ContainerRequestContext on request scoped class

我已经看了很多帖子,但似乎没有什么能像我喜欢的那样工作。

我想从过滤器中将对象注入到 ContainerRequestContext 属性中,稍后在其他 classes 中检索它。

这是我的过滤器:

@Priority(Priorities.AUTHENTICATION)
public class AuthorizationFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext containerRequestContext) throws IOException {

        containerRequestContext.setProperty("myObject", new Object());
    }
}

这里是 class 我想访问 ContainerRequestContext:

@Provider
public class SessionContextProvider implements ISessionContextProvider {
    @Context
    private ContainerRequestContext request;

    @Override
    public Object getSessionContext() {
        return request.getProperty("mySessionContext");
    }
}

和我的 spring 配置:

@Bean(name="sessionContextProvider")
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
public ISessionContextProvider sessionContextProvider() {
    return new SessionContextProvider();
}

如果我将 ContainerRequestContext 注入我的 Web 资源,一切都会按预期进行。但是,如果调用我的提供商 class ContainerRequestContext 始终为 null。

我不明白为什么这行不通。

评论 乔纳斯

问题在于,通过 Jersey/Spring 集成,它允许我们成功地将 Spring beans 注入 Jersey 组件,但反过来并不总是如此。

Jersey 有自己的 DI 框架 HK21,它负责处理 Jersey 组件的注入。通过 Jersey Spring 集成,Jersey 将查找 Spring Bean,并按原样使用它,它不会注入任何依赖项,我想假设 Spring 应该处理它是自己注射。

也就是说,如果您不要求 ISessionContextProvider 成为一个 Spring bean,那么您可以将其设为 HK2 服务.这很简单。如果你不需要任何特殊的初始化,你可以让 HK2 创建它。这里简单配置一下

public JerseyConfig extends ResourceConfig {
    public JerseyConfig() {
        register(new AbstractBinder() {
            bind(SessionContextProvider.class)
                    .to(ISessionContextProvider.class)
                    .in(RequestScoped.class);
        });
    }
}

就是这样。您有一个可注射 ISessionContextProvider2

如果您要求 ISessionContextProvider 提供者是一个 Spring bean,那么另一种选择是从 Spring ApplicatinContext 中获取 bean 并显式注入它你自己,使用 HK2 的 ApplicationContext 模拟,它的 ServiceLocator。为此,我们需要使用 Factory 透明地完成所有工作,因此您仍然可以注入 bean,而无需在外部做任何额外工作

import javax.inject.Inject;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.ServiceLocator;
import org.springframework.context.ApplicationContext;

public class SessionContextProviderFactory 
        implements Factory<SessionContextProvider> {

    private final ISessionContextProvider provider;

    @Inject
    public SessionContextProviderFactory(ApplicationContext ctx,
                                         ServiceLocator locator) {
        provider = ctx.getBean(ISessionContextProvider.class);
        locator.inject(provider);
    }

    @Override
    public ISessionContextProvider provide() {
        return provider;
    }

    @Override
    public void dispost(ISessionContextProvider provider) { /* noop */ }
}

那就注册工厂

public JerseyConfig extends ResourceConfig {
    public JerseyConfig() {
        register(new AbstractBinder() {
            bindFactory(SessionContextProviderFactory.class)
                    .to(ISessionContextProvider.class)
                    .in(RequestScoped.class);
        });
    }
}

1 -
2 - 另见

我找到了解决方法。我可以将 Spring HttpServletRequest 注入我的 AuthorizationFilter 并在此设置 SessionContext。

@Autowired
private HttpServletRequest request;

....

request.setAttribute("mySessionContext", sessionContext);

然后因为 HttpServletRequest 为 spring 所知,并且在我的 SessionContextProvider 中基本上代表相同的东西,所以我也这样做:

@Autowired
private HttpServletRequest request;

@Override
public SessionContext getSessionContext() {
    return (SessionContext) request.getAttribute("mySessionContext");
}

我认为这不是最佳解决方案。但它有效。如果有更好的解决方案,我会等待 peeskillet 的任何其他输入。

问候 乔纳斯