问题 jersey-spring3实例化Spring管理的bean(null!)


我首先要指出的是,这是我在职业生涯中曾经处理过的浪费时间的最大问题。 (现在已经过了两天,基本上没有进展。)我尝试的每一个“解决方案”或“解决方案”都没有用,所以我被封锁了,非常渴望得到一些帮助。

简而言之,问题是Jersey / HK2似乎总是实例化我的Spring管理的bean,因为它们已经被Spring实例化了,它告诉我 球衣,spring3 没有完成它的工作,或者至少不能用我当前的设置(或者我到目前为止尝试过的~50种设置排列)。

请注意,当我使用空构造函数时,这些资源字段在运行时为空。

我不明白为什么我当前的设置不起作用,因为我本质上 复制此在线示例

任何帮助都超过赞赏!!

组态

- - - - - pom.xml - - - - -

<!-- ... -->

<dependencies>

    <!-- Spring Dependencies -->

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-instrument</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-instrument-tomcat</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>${spring.version}</version>
        <exclusions>
            <exclusion>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-core</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-ldap</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-parent</artifactId>
        <version>${spring.version}</version>
        <classifier>tests</classifier>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>${spring.version}</version>
        <classifier>tests</classifier>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-acl</artifactId>
        <version>${spring.version}</version>
        <exclusions>
            <exclusion>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.springframework</groupId>
                <artifactId>spring-support</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.springframework</groupId>
                <artifactId>spring-dao</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${spring.version}</version>
        <scope>test</scope>
    </dependency>

    <!-- / Spring Dependencies -->

    <!-- API dependencies -->

    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-client</artifactId>
        <version>${jersey.version}</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
        <version>${jersey.version}</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-processing</artifactId>
        <version>${jersey.version}</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.test-framework.providers</groupId>
        <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
        <version>2.4</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.ext</groupId>
        <artifactId>jersey-spring3</artifactId>
        <version>${jersey.version}</version>
    </dependency>

    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>${gson.version}</version>
    </dependency>

    <!-- / API dependencies -->

    <!-- ... -->

</dependencies>

<!-- ... -->

<properties>

    <!-- ... -->

    <spring.version>3.0.5.RELEASE</spring.version>

    <jersey.version>2.4.1</jersey.version>

    <gson.version>2.2.4</gson.version>

    <!-- ... -->

</properties>

<!-- ... -->

- - - - - web.xml - - - - -

<web-app>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/beans.xml</param-value>
    </context-param>

    <!-- ... -->

    <servlet>
        <servlet-name>Jersey REST Service</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>fubar.rest.FubarJerseyApplication</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Jersey REST Service</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>

    <!-- ... -->

</web-app>

- - - - - beans.xml(上下文配置) - - - - -

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

<!-- ... -->

<!-- beans-outbound-api has configuration for spring-jersey3 to work properly -->
<import resource="beans-api.xml" />

</beans>

- - - - - beans-api.xml - - - - -

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- Services -->

    <bean id="locationServiceV1" class="fubar.rest.v1.services.location.impl.LocationServiceV1" />
    <bean id="locationServiceV2" class="fubar.rest.v2.services.location.impl.LocationServiceV2" />

    <bean id="viewServiceV1" class="fubar.rest.v1.services.view.impl.ViewServiceV1" />
    <bean id="viewServiceV2" class="fubar.rest.v2.services.view.impl.ViewServiceV2" />

    <!-- Resources -->

    <bean class="fubar.rest.resources.location.impl.LocationResource">
        <constructor-arg index="0" ref="locationServiceV1" />
        <constructor-arg index="1" ref="locationServiceV2" />
    </bean>

    <bean class="fubar.rest.resources.view.impl.ViewResource">
        <constructor-arg index="0" ref="viewServiceV1" />
        <constructor-arg index="1" ref="viewServiceV2" />
    </bean>

</beans>

- - - - - 资源(JAX-RS) - - - - -

@Path(RESTLocationResourceV1.PathFields.PATH_ROOT)
@Produces({V1_JSON, APPLICATION_JSON})
public class LocationResource
    extends ResourceBase<LocationResource, ILocationServiceV1, ILocationServiceV2> {

  private static final Logger logger = Logger.getLogger(LocationResource.class);

  @Inject
  public LocationResource(final LocationServiceV1 v1Loc, final LocationServiceV2 v2Loc) {
    super(v1Loc, v2Loc);
    logger.info(format(Messages.INF_INSTANTIATED, "LocationResource"));
  }

  @GET
  @Path(PathFields.SUBPATH_LIST)
  public LocationListV1 listV1(@HeaderParam(HEADER_API_KEY) String apiKey)
      throws ApplicationException {
    // Implementation
  }

  @GET
  @Path(PathFields.SUBPATH_SEARCH)
  public LocationListV1 searchV1(@HeaderParam(HEADER_API_KEY) String apiKey,
      @QueryParam(QueryFields.QUERY) String likeText) throws ApplicationException {
    // Implementation
  }
}

- - - - - 服务(春豆) - - - - -

public class LocationServiceV1 extends ServiceBaseV1<LocationBean, LocationV1, LocationListV1>
    implements
      ILocationServiceV1 {

  @Autowired
  private LocationDao daoLoc;

  public LocationServiceV1() {
    super(new LocationBeanToJsonTranslatorV1());
  }

  @Override
  public LocationListV1 listV1() throws ApplicationException {
    // Implementation
  }

  @Override
  public LocationListV1 searchV1(String likeText) throws ApplicationException {
    // Implementation
  }
}

(对于版本2基本相同)

- - - - - 申请表(泽西岛) - - - - -

public class FubarJerseyApplication extends ResourceConfig {

  private static final class Messages {
    static final String INF_STARTING_APPLICATION = "Starting %s!";
  }

  private static final Logger logger = Logger.getLogger(FubarJerseyApplication.class);

  public FubarJerseyApplication() {
    packages("fubar.rest");
    logger.info(format(Messages.INF_STARTING_APPLICATION, this.getClass().getName()));
  }
}

调用(客户)

curl http://my-ip-address/fubar/api/location/list

(500内部服务器错误)

错误(服务器)

org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object
available for injection at Injectee(requiredType=LocationServiceV1,parent=
LocationResource,qualifiers={}),position=0,optional=false,self=false,
unqualified=null,344016971)
at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)
at org.jvnet.hk2.internal.ClazzCreator.resolve(ClazzCreator.java:208)
at org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:225)
at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:329)
at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:456)
at org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:158)
at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2350)
at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:612)
at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:597)
at org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:173)
at org.glassfish.jersey.server.model.MethodHandler$ClassBasedMethodHandler.getInstance(MethodHandler.java:185)
at org.glassfish.jersey.server.internal.routing.PushMethodHandlerRouter.apply(PushMethodHandlerRouter.java:103)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:128)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:110)
at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:65)
at org.glassfish.jersey.process.internal.Stages.process(Stages.java:197)
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:250)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:318)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:983)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:361)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:372)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:218)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at fubar.server.springframework.SessionFilter.doFilter(SessionFilter.java:44)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at fubar.server.springframework.loader.ContextLoaderHttpInterceptor$LoaderState.filter(ContextLoaderHttpInterceptor.java:75)
at fubar.server.springframework.loader.ContextLoaderHttpInterceptor$StartedState.filter(ContextLoaderHttpInterceptor.java:120)
at fubar.server.springframework.loader.ContextLoaderHttpInterceptor.doFilter(ContextLoaderHttpInterceptor.java:62)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:190)
at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:311)
at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:776)
at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:705)
at org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:898)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690)
at java.lang.Thread.run(Thread.java:662)

API日志

Dec 10, 2013 13:36:28 INFO  [main] fubar.rest.FubarJerseyApplication
     - Starting fubar.rest.FubarJerseyApplication!
Dec 10, 2013 13:38:06 INFO  [pool-1-thread-1] resources.location.impl.LocationResource
     - LocationResource has been instantiated
Dec 10, 2013 13:38:06 INFO  [pool-1-thread-1] resources.view.impl.ViewResource
     - ViewResource has been instantiated

更新 - 发现这个:

卡塔利娜日志

Dec 10, 2013 1:36:42 PM org.glassfish.jersey.server.ApplicationHandler initialize
INFO: Initiating Jersey application, version Jersey: 2.4.1 2013-11-08 12:08:47...
Dec 10, 2013 1:36:43 PM org.glassfish.jersey.server.spring.SpringComponentProvider initialize
SEVERE: Spring context lookup failed, skipping spring component provider initialization.
Dec 10, 2013 1:38:00 PM com.sun.xml.bind.v2.runtime.reflect.opt.Injector inject

...所以找不到ApplicationContext SpringComponentProvider#初始化


11114
2017-12-10 22:26


起源

欢迎来到俱乐部! :(在我最初的障碍之后,我正在考虑放弃Jersey 2.7并使用Apache CXF或Spring MVC(遗憾的是不是JAX-RS ......)。我想在此期间我们应该坚持使用泽西岛1.x的? - Hendy Irawan
这篇文章很老了,但我已经通过小道消息告诉我,jersey-spring3的最新更新解决了这个问题。 - Ryan


答案:


先加载什么?春天还是泽西岛?可能是SpringComponentProvider调用时没有初始化Spring上下文 WebApplicationContextUtils.getWebApplicationContext(sc);。尝试使用Spring的ContextLoaderListener,以便Spring在部署应用程序后立即进行初始化。

我遇到了很多你在使用jersey-spring3库时遇到的问题。它在查找我的Spring ApplicationContext时遇到了问题(看起来这就是你被困住的地方)并且它炸毁了注入以一个泛型参数作为参数的setter。

如果您超越了应用程序上下文问题,我认为您的内容无论如何都不会有效。您在XML中定义了ViewResource和LocationResource bean。据我所知,如果资源类使用@Component注释,Jersey将只从Spring获取资源实例。具体来说,请查看org.glassfish.jersey.server.spring.SpringComponentProvider component.isAnnotationPresent(Component.class)

// detect JAX-RS classes that are also Spring @Components.
// register these with HK2 ServiceLocator to manage their lifecycle using Spring.
@Override
public boolean bind(Class<?> component, Set<Class<?>> providerContracts) {

    if (ctx == null) {
        return false;
    }

    if(component.isAnnotationPresent(Component.class)) {
        DynamicConfiguration c = Injections.getConfiguration(locator);
        String[] beanNames = ctx.getBeanNamesForType(component);
        if(beanNames == null || beanNames.length != 1) {
            LOGGER.severe(LocalizationMessages.NONE_OR_MULTIPLE_BEANS_AVAILABLE(component));
            return false;
        }
        String beanName = beanNames[0];

        ServiceBindingBuilder bb = Injections.newFactoryBinder(new SpringComponentProvider.SpringManagedBeanFactory(ctx, locator, beanName));
        bb.to(component);
        Injections.addBinding(bb, c);
        c.commit();

        LOGGER.config(LocalizationMessages.BEAN_REGISTERED(beanName));
        return true;
    }
    return false;
}

一个不相关的问题是我们还希望将所有JAX-RS注释移动到接口。每当我尝试它时,我得到“无法为com.foo.ResourceInterface找到合适的构造函数”。

最后,我通过不使用jersey-spring3并将自己的Jersey连接到Spring连接器解决了我的所有问题。这是我做的:

  1. 将我的所有资源配置为常规Spring bean。如果需要,您可以使用XML。
  2. 在我的应用程序中,我添加了绑定到HK2容器,以便在需要其中一个资源的实例时使用工厂。我的工厂类只返回资源的Spring托管实例。
  3. 在工厂返回Spring管理的bean之前,我使用Jersey / HK2 ServiceLocator注入Jersey提供的东西。例如,任何使用@Context注释的内容。

我的javax.ws.rs.Application看起来像这样:

public class RestConfig extends ResourceConfig {
private static final Log log = LogFactory.getLog(RestConfig.class);


@Inject
public RestConfig(ServiceLocator locator) {
    super();
    // specific to my app. get your spring beans however you like
    Collection<Object> beans = BeanLocator.beansByAnnotation(RestResource.class);

    DynamicConfiguration c = Injections.getConfiguration(locator);


    for (Object bean : beans)
    {
                    // tell jersey to use a factory for any interface that the bean implements.  since your resources don't implement interfaces, 
                    // you'll want to do something a bit different here.
        for (Class<?> currentInterface : bean.getClass().getInterfaces())
        {
            if (log.isTraceEnabled())
                log.trace("binding " + currentInterface.getSimpleName() + " to Spring managed bean");

            ServiceBindingBuilder<Object> bb = Injections.newFactoryBinder(new StaticLookupFactory(locator, bean));
            bb.to(currentInterface);
                    Injections.addBinding(bb, c);
        }
    }

            // commit the changes to the HK2 container (don't skip this step!)
            c.commit();

    property("jersey.config.disableMoxyJson.server", true);
    packages("com.foo.web.rest");

    register(MoxyXmlFeature.class);
}


// a "factory" where the provide() method returns the spring managed bean
    // that was passed to the constructor.
private static class StaticLookupFactory implements Factory<Object> {

    private ServiceLocator locator;
    private Object bean;

    StaticLookupFactory(ServiceLocator locator, Object bean)
    {
        this.locator = locator;
        this.bean = bean;
    }

    @Override
    public Object provide() {
                    // inject this annotated with @Context, @Inject, etc
        locator.inject(bean);
        return bean;
    }

    @Override
    public void dispose(Object instance) {
    }

}
}

BeanLocator 是我编写的实用程序类,当自动装配不可用时,可以使用静态方法轻松获取bean实例。例如,在Spring托管bean之外工作时。没有那么多:

public static Collection<Object> beansByAnnotation(Class<? extends Annotation> annotation)
{
    return applicationContext.getBeansWithAnnotation(annotation).values();
}

RestResource 也是我们的应用程序特有的。它是一个定制的构造型,像@ Component,@ Service等一样:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface RestResource {
    String value() default "";
}

请注意,Jersey允许您注册org.glassfish.jersey.server.spring.ComponentProvider的自定义实现,以自行管理资源的生命周期。我尝试过但无论我做了什么都无法识别我的实现。

另一个注意事项...... locator.inject(bean) 激活Jersey依赖注入机制的调用将处理用@Inject标记的任何内容。在类中使用@Autowired或使用XML配置bean,以避免让Spring和Jersey尝试解析使用@Inject注释的内容的值。


9
2017-12-14 01:01



谢谢你的回复 - 我会看看你后来做了什么。只是想评论“一个不相关的问题是我们还想将所有JAX-RS注释移动到接口。每当我尝试它时,我得到了”无法为com.foo.ResourceInterface找到合适的构造函数“。 - 我能够通过手动注册所有提供者和资源来解决这个问题。通过程序包扫描注册资源时,会发生此错误。 (肯定是泽西岛的一个小虫...) - Ryan
非常感谢!这救了我。我将ContextLoaderListener放置为web.xml中的第一个侦听器。这显然已经解决了我的问题。但后来我将web.xml中的servlet-api版本从2.5更新到3.0,并再次遇到了同样的问题。然后我还重新排序了web.xml中的servlet,以便spring servlet(WSSpringServlet)处于第一位置。否则,其他一些库导致SpringComponentProvider首先被初始化。 - avidD


我们有一个自定义的,异步的 通过ContextLoader因此,临时解决方案需要完全破解 新泽西州Spring3 在自定义组件提供程序初始化之前等待应用程序初始化的源。

附:对于发现自己必须做这样的事情的任何可怜的灵魂,确保META-INF /设置包含 SpringComponentProvider 组态。


(2014-04-18)为@Scott撰写

请注意,这是一个 可怕 黑客和我只会尝试这样的事情作为最后的手段,所有其他尝试都失败,就像在我的情况下。在尝试这样的事情之前,我会咨询Jersey邮件组,了解你的问题。

那就是说......这就是我为解决问题而采取的措施:

  • 将spring-jersey3的源代码直接复制到我的应用程序/服务器中,根据许可证使用适当的标签修改每个文件的标题;

  • 创建了以下课程 -

===>

  /**
   * Hack class for RN-8979.
   *
   * @author ryan
   *
   */
  public class ContextLoadWaiter {

    private static final Logger logger = Logger.getLogger(ContextLoadWaiter.class);

    public void doWait() {

      try {
        while (ContextLoaderHttpInterceptor.isNotStarted()) {
          logger.info("Waiting for ContextLoader to start...");
          Thread.sleep(1000);
        }
      } catch (InterruptedException e) {
        logger.error("SpringComponentProvider was interrupted!");
      }
    }
  }

请注意,这特定于* my * code-base as ContextLoaderHttpInterceptor 是一个http servlet在哪里 isNotStarted 回报 true 如果我们的习惯 ContextLoader (它恰好是异步的)尚未加载。

自定义异步 ContextLoader 由于某种原因某个时候由于某些原因允许UI在服务器启动时显示“加载”页面。 (可能不是添加此UI“功能”的正确方法,但代码在那里,UI依赖于它,所以我不得不处理它...)

由于这部分不会直接适用于您,关键是要通过调试 SpringComponentProvider(从 这里)并看看的价值 ClassPathXmlApplicationContext。如果是 null,就像我们的情况一样,那么你需要弄清楚它为什么 null 并等待什么 ContextLoader 在初始化此组件之前使用加载。

  • 放置这个hacky线 SpringComponentProvider  -

==>

  ...

  private final ContextLoadWaiter waiter = new ContextLoadWaiter();

  ...

  @Override
  public void initialize(ServiceLocator locator) {

    waiter.doWait(); // Wait on our asynchronous context loader.

    this.locator = locator;

    if (LOGGER.isLoggable(Level.FINE)) {
      LOGGER.fine("Context lookup started");
    }

    ...
  • 创建此文件: META-INF/services/org.glassfish.jersey.server.spi.ComponentProvider 内容是SpringComponentProvider的完全限定类路径,例如 com.company.server.nbi.rest.internal.jspring.SpringComponentProvider

  • 添加了自定义Jersey-spring3包作为包在应用程序中扫描;见下文...

==>

/**
 * Application configuration.
 *
 * @author ryan
 *
 */
public class MyJerseyApplication extends ResourceConfig {

  private static final class Messages {
    static final String INF_STARTING_APPLICATION = "Starting %s!";
  }

  private static final Logger logger = Logger.getLogger(MyJerseyApplication.class);

  public MyJerseyApplication() {

    packages(
    /* Internal providers */
    "com.company.server.nbi.rest.providers",
    /* Internal filters */
    "com.company.server.nbi.rest.filters",
    /* Spring injection support */
    "com.company.server.nbi.rest.internal.jspring", // HERE!!!
    /* Json providers */
    "com.fasterxml.jackson.jaxrs.json",
    /* Jackson exception mappers */
    "com.fasterxml.jackson.jaxrs.base");

    /* Resources */
    register(ResourceA.class);
    register(ResourceB.class);
    register(ResourceC.class);

    /* Miscellaneous features */
    register(MultiPartFeature.class);
    register(LoggingFilter.class);

    logger.info(format(Messages.INF_STARTING_APPLICATION, this.getClass().getName()));
  }
}

而已”。绝对不是一个值得骄傲的解决方案,但如果你像我一样处于绝望的模式,那么试一试可能并没有什么坏处。


3
2017-12-11 01:18



编辑了我犯的错误 - 你需要的文件名为META-INF / services / org.glassfish.jersey.server.spi.ComponentProvider - Ryan
我可以问一下,泽西春天会给你什么?注入Autowired spring bean的能力?没有其他方法可以合法地使用spring api获取它们吗? - Kalpesh Soni
@KalpeshSoni就“泽西春天”而言,是的...注入Autowired bean的能力。至于泽西岛本身......我工作的公司在我开始从事该项目时使用的是古老的Spring版本,而泽西似乎是兼容性噩梦的一个很好的替代品。 - Ryan


这是了解问题的关键信息。它表明Spring无法正确初始化:

SEVERE: Spring context lookup failed, skipping spring component provider initialization.

(旁注:因为Spring无法初始化,所以尝试解决问题的唯一JSR-330实现 @Inject 是HK2 - 这就是你看到另一个问题的原因)。

无论如何,问题可能是你的容器没有对所有的注释进行扫描 jersey-spring3 魔术发生了。

此行为是Servlet 3.0规范(JSR-33,第1.6.2节)的一部分,因此您应该仔细检查容器是否支持此操作。

对于Tomcat - 除非您运行的是Tomcat 7.0.29或更高版本,否则您实际上需要确保在web.xml中指定了Servlet版本。

http://tomcat.apache.org/tomcat-7.0-doc/changelog.html#Tomcat_7.0.29_(markt) 

我最近遇到了这个问题,它让我疯了,修复web.xml比从Ubuntu / Precise升级更容易!

希望这可以帮助!


1
2018-05-16 13:22



胜利:我也遭受了一次微妙的失败,接着是吵闹的失败。你的帖子首先关注我的微妙 - 谢谢! - Rob
不用担心,不幸的是Jetty似乎甚至没有正确支持servlet 3.0扫描(如果你正在使用它)。 Dropwizard白天看起来越来越好:) - heretik
Dropwizard 看起来不错,谢谢你指出这一点。 - Ryan