Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用Spring初始化Jersey应用程序(ResourceConfig)?_Spring_Jersey_Jersey 2.0 - Fatal编程技术网

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

如何使用Spring初始化Jersey应用程序(ResourceConfig)?,spring,jersey,jersey-2.0,Spring,Jersey,Jersey 2.0,我使用的是Jersey 2和Spring,我试图用Spring上下文中的参数初始化Jersey应用程序(即从ResourceConfig派生的类) 背景:我构建了一个Jersey应用程序(即一个WAR),并在不同服务器上使用不同的Spring配置跨服务器集群部署它,以启用或禁用服务器的不同部分,例如,一些服务器启用了/search资源,等等,这在泽西1.0中真的很容易:我刚才说 <context:component-scan base-package="com.mycompany.reso

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

背景:我构建了一个Jersey应用程序(即一个WAR),并在不同服务器上使用不同的Spring配置跨服务器集群部署它,以启用或禁用服务器的不同部分,例如,一些服务器启用了
/search
资源,等等,这在泽西1.0中真的很容易:我刚才说

<context:component-scan base-package="com.mycompany.resources.search"/>
到目前为止还不错,但我需要有条件地扫描该包,我不知道如何将任何Spring配置放入
MyApplication
类。我认为构造函数注入可能会起作用:

public class MyApplication extends ResourceConfig {

    @Autowired
    public MyApplication(@Qualifier("my-config") MyConfiguration myConfiguration) {
        if (myConfiguration.isEnabled()) {
            packages("com.mycompany.resources.search");
        }
    }
}
然而HK2抱怨说它找不到默认的构造函数来使用。。。所以这向我表明DI在这个类的构造中起作用,但是DI没有使用Spring

类似地,在SpringBean生命周期中使用

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");
        }
    }
}
(未调用
afterPropertieSet
方法。)

所以现在我被卡住了:有没有办法使用Spring配置Jersey
ResourceConfig
应用程序对象?

更新:

我在下面接受了@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");
        }
    }
}
我们让Jersey/HK2初始化它,而不是让对象初始化两次,然后从Spring检索依赖项

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

所以现在我陷入了困境:有没有办法配置球衣 使用Spring的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;
    }
}

再说一次,这是相当骇人听闻的。您需要确保Spring在Jersey之前已初始化,并仔细查看初始化过程中可能出现的任何线程问题。

展开我之前的评论:

如果您不知道自己在做什么,那么尝试扩展ResourceConfig是危险的。Jersey变得不可预测,如果您试图将其子类化为抽象类,Jersey将崩溃

相反,JAX-RS规范为我们提供了一个非常有用的接口,名为Feature:它允许您注册所需的任何类,就像您正在配置自己的应用程序一样。此外,您不需要使用笨拙的AbstractBinder,只需指定注册类时使用的契约即可

import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;

// Don't use @Component here, we need to inject the Spring context manually.
public class MySpringFeature implements Feature {

    @Context
    private ServletContext servletContext;

    private ApplicationContext applicationContext;

    @Autowired
    private MySecurityDAO mySecurityDAO;

    @Autowired
    private MySpringResponseFilter myResponseFilter;

    @Override
    public boolean configure(FeatureContext context) {
        if(this.servletContext == null) {
            return false; // ERROR!
        }
        this.applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        if(this.applicationContext == null) {
            return false; // ERROR!
        }

        // This is where the magic happens!
        AutowireCapableBeanFactory bf = applicationContext.getAutowireCapableBeanFactory();
        bf.autowireBean(this);

        // From here you can get all the beans you need

        // Now we take a Spring bean instance,
        // and register it with its appropriate JAX-RS contract
        context.register(myResponseFilter, ContainerResponseFilter.class);

        // Or, we could do this instead:
        SomeSecurityFilter mySecurityFilter = new SomeSecurityFilter();
        mySecurityFilter.setSecurityDAO(mySecurityDAO);
        context.register(mySegurityFilter, ContainerRequestFilter.class);

        // Or even this:
        SomeOtherSpringBean someOtherBean = applicationContext.getBean(SomeOtherSpringBean.class);
        context.register(someOtherBean, SomeOtherJerseyContract.class);

        // Success!
        return true;
    }
}
在您的资源配置中:

public class MyApplication extends ResourceConfig() {

    public MyApplication() {
        register(MySpringFeature.class);
    }
}

塔达

我在泽西2+春季遇到了类似的问题。最后,我完成了自己的集成。帮助?这是一个很好的答案。非常不幸的是,你不得不推出自己的球衣/春桥。可悲的是,我的经历也很相似:在泽西2和春天浪费了很多时间。我现在已经开始跑步了,但jersey2 spring bridge似乎有一条狭窄的“快乐之路”,如果你迷路了,会有很多陷阱。我对其他从事泽西2号和斯普林号的人的建议是:遵循规则,不要尝试做任何不同的事情,因为它不会起作用。我已经设法解决了这个问题。如果您确实需要使用Spring类配置应用程序,请不要扩展ResourceConfig,这是一项专有功能。相反,实现javax.ws.rs.core.Feature,从中可以使用@Context ServletContext字段获取Spring的ApplicationContext。这会帮你省去很多麻烦。然后您只需从ResourceConfig类注册您的功能,然后ta da!(您可以使用Jersey-Spring4依赖项,但在我的情况下,我不能使用,因为我被迫使用Jersey 2.21,但没有这样的包。)
public class MyApplication extends ResourceConfig() {

    public MyApplication() {
        register(MySpringFeature.class);
    }
}