6

泽西岛:1.12 春季:3.11 JDK:1.6.0_35 Tomcat:6..0.33

我正在尝试为由 Spring IoC 容器在 SpringServlet 的上下文中实例化的 Jersey servlet 注册 ExceptionMapper 实例,并且在 Jersey servlet 期间遇到了旧的“组件类 X 的范围必须是单例”异常初始化。我目前无法发布实际代码,所以我将提供实现的要点,看看是否有明显的东西跳出来,或者我是否可以指出我拥有的一些文档错过了。

ExceptionMapper 实例本质上如下:

// ... package definitions omitted ...

@Provider
@Singleton
public class MyExceptionMapper
    implements ExceptionMapper<MyException>
{
    // ... injected attributes omitted ...

    @Override
    public Response toResponse(MyException exception)
    {
        // ... specific handling logic omitted ...

       return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build();
    }
}

applicationContext.xml 中的 bean 定义如下,默认为单例范围(并且添加显式范围说明符似乎不会改变行为):

<bean id="myExceptionMapper" class="my.package.MyExceptionMapper" />

web.xml 中的 Spring 上下文加载器侦听器和 SpringServlet 配置本质上是样板文件,当 MyExceptionMapper 的 bean 定义从 applicationContext.xml 注释掉时,servlet 将加载、初始化和正确操作其他注入属性。但是,当 applicationContext.xml 中存在 bean 定义时,我会收到以下日志消息:

SpringProviderFactory - Registering Spring bean, myExpectionMapper, of type my.package.MyExceptionMapper as a provider class
SpringProviderFactory - Registering Spring bean, myServiceController, of type my.package.MyServiceController as a root resource class
... other root resource classes loading ...
SpringServlet - Exception occurred when initialization
java.lang.RuntimeException: The scope of the component class my.package.MyExceptionMapper must be a singleton
  at som.sun.jersey.core.spi.component.ioc.IoCProviderFactory.wrap(...)

我尝试将 MyExceptionMapper 放在扫描包层次结构中,以便在初始化期间由 SpringServlet 拾取,并放在单独的包层次结构中,结果不会改变。

对此的任何帮助或指导将不胜感激。

4

6 回答 6

4

ExceptionMapper的 s 在我正在执行组件扫描的结构下,而我的只是@Component为 Spring 注册表和@ProviderJersey 进行了注释。

我的组件扫描看起来像:

<context:component-scan base-package="com.company.web"/>

ExceptionMapper看起来很像你的:

package com.mycompany.web.provider;

import com.mycompany.exception.SpecialException;
import com.mycompany.exception.Error;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Provider
@Component
public class SpecialExceptionMapper implements ExceptionMapper<SpecialException> {

    @Autowired
    private MessageSource messageSource;

    @Override
    public Response toResponse(SpecialException exception) {

        Error error = new Error();


        error.errorMessage = messageSource.getMessage(exception.getResourceBundleKey(), exception.getArgs());

        return Response.status(Response.Status.BAD_REQUEST).
                entity(error).
                type(MediaType.APPLICATION_JSON).
                build();
    }
}
于 2013-02-18T19:18:29.593 回答
4

在 spring 配置中显式添加范围对我来说是诀窍:

<bean id="exceptionMapper" class="my.pkg.MyExceptionMapper" scope="singleton" />
于 2013-04-15T15:49:39.403 回答
1

我有同样的问题,但有一个 MessageReaderWriterProvider 类:

package my.provider.package;
...
@Provider
@Consumes({MediaType.APPLICATION_JSON, "text/json"})
@Produces({MediaType.APPLICATION_JSON, "text/json"})
public class ReRwProvider extends AbstractMessageReaderWriterProvider<Object> {
...
}

解决方案是将此类的包添加到 web.xml 中 Jersey 的 SpringServlet 的 init-param 标记中:

<init-param>
    <param-name>com.sun.jersey.config.property.packages</param-name>
    <param-value>my.provider.package</param-value>
</init-param>

请注意,您不应在 Spring 上下文中定义此 bean。

于 2013-02-18T14:26:46.020 回答
1

在 Spring 3.2.3 和 Jersey 2.3.1 集成中遇到了同样的问题。

对我有用的是两者的结合:

  1. 在 app-context xml 中使用或使其显式单例注释球衣@Provider@Service

    @Service //implies a singleton-scope
    @Provider
    public class UnhandledExceptionMapper implements ExceptionMapper<Throwable> {
    
        @Override
        public Response toResponse(Throwable exception) { //...
    
  2. 将包含提供程序类的包添加到球衣包中,我更喜欢在 MyApplication 类中执行此操作:

    public class MyApplication extends ResourceConfig {
    public MyApplication() {
        packages("com.mycompany.api.controller", "com.mycompany.api.jersey");
                //....
        }
    }
    
于 2013-10-09T09:42:02.840 回答
0

在我看来,必须将 ExceptionMapper 配置为 Spring 的“单例”。如果你想使用注解配置,你必须注意,因为球衣也有一个“@Singleton”注解(与 spring 解释的 javax.inject.Singleton 的不同含义)为了避免任何混淆,我更喜欢使用 spring @Service注释,这意味着一个单例范围......所以:

import org.springframework.stereotype.Service;

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Service //implies a singleton-scope
@Provider
public class UnhandledExceptionMapper implements ExceptionMapper<Throwable> {

    @Override
    public Response toResponse(Throwable exception) {
        return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                .entity(new ErrorBean(false, exception.getMessage(), null))
                .build();
    }
}
于 2013-07-08T11:06:28.890 回答
0

我还发现有时自定义的 ExceptionMapper 不起作用,而且它并不总是起作用或不起作用。

所以我调试了球衣的源代码。

类:org.glassfish.jersey.server.ServerRuntime,方法:mapException

 ...
 final long timestamp = tracingLogger.timestamp(ServerTraceEvent.EXCEPTION_MAPPING);
 **ExceptionMapper mapper = runtime.exceptionMappers.findMapping(throwable);**
 if (mapper != null) {
      request.getRequestEventBuilder().setExceptionMapper(mapper);

...如果映射器为空,则自定义的 ExceptionMapper 将不起作用。

类:org.glassfish.jersey.internal.ExceptionMapperFactory 方法:ExceptionMapperFactory

异常映射器:(有两个异常映射一个相同的异常:java.lang.Exception)

org.glassfish.jersey.server.mvc.internal.ErrorTemplateExceptionMapper@6473fc2,class java.lang.Exception

...

com.baidu.ssp.web.ws.exception.BaseExceptionMapper@7a84639c,class java.lang.Exception

这是因为在 MvcFeature 中:

@Override public boolean configure(final FeatureContext context) { final Configuration config = context.getConfiguration();

if (!config.isRegistered(ErrorTemplateExceptionMapper.class)) {
    context.register(ErrorTemplateExceptionMapper.class);
    context.register(new MvcBinder());

    return true;
}

return false;

} ErrorTemplateExceptionMapper 也被添加到 ExceptionMapper。

所以我改变了我的自定义 MapperException 的泛型类型: ExceptionMapper 到 ExceptionMapper

可能是我的分辨率不适合你,主要问题是 ExceptionMapper

于 2014-11-26T10:32:29.963 回答