泽西岛:1.12 春天:3.11 JDK:1.6.0_35 Tomcat:6..0.33
我正在尝试为在SpringServlet的上下文中由Spring IoC容器实例化的Jersey servlet注册ExceptionMapper实例,并且正在运行“在组件类X的范围必须是单例”异常期间Jersey servlet初始化。我现在无法发布实际的代码,因此我将提供实现的基本知识,看看是否有人明显跳出某人,或者我是否可以指出我的某些文档错过。
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定义如下,默认为singleton范围(添加显式范围说明符似乎不会改变行为):
<bean id="myExceptionMapper" class="my.package.MyExceptionMapper" />
web.xml中的Spring上下文加载器侦听器和SpringServlet配置本质上是样板文件,当从ApplicationContext.xml中注释掉MyExceptionMapper的bean定义时,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拾取,并且在单独的包层次结构中,结果不会改变。
对此的任何帮助或指导将不胜感激。
答案 0 :(得分:4)
我的ExceptionMapper
属于我正在进行组件扫描的结构,而我的简单注释为@Component
用于Spring注册表,@Provider
用于Jersey。
我的组件扫描看起来像:
<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();
}
}
答案 1 :(得分:4)
在spring配置中显式添加范围对我来说很有用:
<bean id="exceptionMapper" class="my.pkg.MyExceptionMapper" scope="singleton" />
答案 2 :(得分: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。
答案 3 :(得分:1)
在Spring 3.2.3和Jersey 2.3.1集成方面遇到同样的问题。
对我有用的是两个组合:
使用@Provider
注释jersey @Service
类或在app-context xml中明确单例化
@Service //implies a singleton-scope
@Provider
public class UnhandledExceptionMapper implements ExceptionMapper<Throwable> {
@Override
public Response toResponse(Throwable exception) { //...
将包含提供程序类的包添加到jersey包中,我更喜欢在MyApplication类中执行此操作:
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("com.mycompany.api.controller", "com.mycompany.api.jersey");
//....
}
}
答案 4 :(得分:0)
在我看来,必须将ExceptionMapper配置为Spring的“singleton”。如果你想使用注释配置,你必须注意,因为球衣也有一个“@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();
}
}
答案 5 :(得分:0)
我还发现某些时候,ExceptionMapper不起作用,而且它并不总是有效或不起作用。
所以我调试了球衣的源代码。
class:org.glassfish.jersey.server.ServerRuntime,methed:mapException
...
final long timestamp = tracingLogger.timestamp(ServerTraceEvent.EXCEPTION_MAPPING);
**ExceptionMapper mapper = runtime.exceptionMappers.findMapping(throwable);**
if (mapper != null) {
request.getRequestEventBuilder().setExceptionMapper(mapper);
... 如果mapper为null,那么coustom ExceptionMapper将无效。
class:org.glassfish.jersey.internal.ExceptionMapperFactory methed: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中:
@覆盖 public boolean configure(final FeatureContext context){ final config 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