如何使用Spring初始化Jersey应用程序(ResourceConfig)?

Mic*_*les 8 spring jersey jersey-2.0

我正在使用Jersey 2和Spring,我正在尝试使用Spring上下文中的参数初始化我的Jersey应用程序(即从ResourceConfig派生的类).

背景:我有一个我构建的Jersey应用程序(即单个WAR),我将它部署在不同服务器上具有不同Spring配置的服务器集群中,以启用或禁用服务器的不同部分,例如,某些服务器已经转换了/search资源在泽西岛1.0这真的很容易:我只是把,

<context:component-scan base-package="com.mycompany.resources.search"/>
Run Code Online (Sandbox Code Playgroud)

在Spring配置中让Jersey扫描该特定包,并在其中启用JAX-RS资源提供程序.

现在在Jersey 2.0中Spring <context:component-scan ... />不起作用,因此资源必须以编程方式在从ResourceConfig以下派生的派生类中注册:

public class MyApplication extends ResourceConfig {

    public MyApplication() {
        packages("com.mycompany.resources.search");
    }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止一切顺利,但我需要有条件地扫描该包,我无法弄清楚如何将任何Spring配置放入MyApplication类中.我认为构造函数注入可能有效:

public class MyApplication extends ResourceConfig {

    @Autowired
    public MyApplication(@Qualifier("my-config") MyConfiguration myConfiguration) {
        if (myConfiguration.isEnabled()) {
            packages("com.mycompany.resources.search");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是HK2抱怨它找不到默认的构造函数......所以这向我表明DI在构造这个类时起作用,但是DI没有使用Spring.

同样,使用Spring bean生命周期不起作用:

public class MyApplication extends ResourceConfig implements InitializingBean {

    @Autowired
    private MyConfiguration myConfiguration;

    public MyApplication() {
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (myConfiguration.isEnabled()) {
            packages("com.mycompany.resources.search");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

(该afterPropertiesSet方法未被调用.)

所以现在我陷入困境:有没有办法ResourceConfig使用Spring 配置Jersey 应用程序对象?

更新:

我在下面接受了@ JohnR的答案,但我还要包括我认为更清洁的最终解决方案.@ JohnR的答案是将对象初始化两次:首先是Spring,然后是Jersey/HK2.当Spring初始化对象时,您将依赖项缓存在静态成员中,然后当Jersey/HK2稍后初始化它时,您可以检索依赖项.

我最终这样做了:

public class MyApplication extends ResourceConfig {

    public MyApplication() {
        ApplicationContext rootCtx = ContextLoader.getCurrentWebApplicationContext();
        MyConfiguration myConfiguration = rootCtx.getBean(MyConfiguration.class);

        if (myConfiguration.isEnabled()) {
            packages("com.mycompany.resources.whatever");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我们让Jersey/HK2初始化它,而不是让对象初始化两次,然后我们从Spring中检索依赖项.

这两种解决方案都容易受到时间限制:它们都假设Spring在Jersey/HK2之前初始化.

Joh*_*n R 0

所以现在我陷入了困境:有没有办法使用 Spring 配置 Jersey ResourceConfig 应用程序对象?

我认为您无法配置 Jersey 以从 Spring 获取 ResourceConfig 作为 Spring 托管 bean。这有点黑客,但你可以做这样的事情。请注意,您最终会得到 ResourceConfig 的两个实例:一个由 Spring 管理,另一个由 Jersey 管理:

public class MyApplication extends ResourceConfig {

    // static, available to all instances
    private static MyConfiguration myConfiguration;

    public MyApplication() {
        // when Spring creates the first instance of MyApplication, myConfiguration
        // will be null because the setter wasn't called yet
        if (myConfiguration != null)
        {
            // second instance created by jersey... Spring will have autowired
            // the first instance, and myConfiguration is static
            if (myConfiguration.isEnabled()) 
                packages("com.mycompany.resources.search");
        }
    }

    @Autowired
    public void setMyConfiguration(MyConfiguration config)
    {
        // instance level setter saves to a static variable to make it available for
        // future instances (i.e. the one created by jersey)
        MyApplication.myConfiguration = config;
    }
}
Run Code Online (Sandbox Code Playgroud)

再说一遍,这是相当黑客的。您需要确保 Spring 在 Jersey 之前初始化,并仔细查看初始化期间可能发生的任何线程问题。