Spring项目@Context注入UriInfo报无公共构造函数异常排查
故障原因
- 核心问题是JAX-RS规范注解与Spring MVC注解体系混用不兼容:
@Context、javax.ws.rs.core.UriInfo都是JAX-RS(Jersey、RESTEasy等JAX-RS实现)的标准组件,不属于Spring MVC原生支持的注解和类型- 当前控制器使用
@RestController、@GetMapping这类Spring MVC原生注解,Spring MVC无法识别@Context注解的注入语义,会把标注了@Context的UriInfo方法参数当成普通请求参数,尝试通过默认构造函数实例化后绑定参数值 - 由于
UriInfo是接口,没有公开的无参构造方法,就直接抛出你看到的构造函数找不到的异常,请求根本进不到控制器方法逻辑里
- 其他未使用
@Context的接口走Spring MVC原生参数解析流程,因此可以正常运行 - 额外注意原代码存在两处会直接导致运行/编译失败的笔误:
@GetMapping("/activate")的路径中没有配置{service}路径占位符,和方法上的@PathVariable("service")不匹配,就算解决注入问题也会报路径参数找不到的错- 方法内定义的账户ID列表变量名为
accountIdList,调用mgr.activateAccounts(accIdList)时传的变量名不存在,会直接编译失败
修复方案
优先选方案1,和现有Spring MVC技术栈完全适配,没有额外依赖冲突风险。
方案1:替换为Spring MVC原生API(推荐)
完全移除JAX-RS的@Context和UriInfo依赖,使用Spring MVC原生支持的参数注入方式:
- 最简单的实现:直接用Spring MVC自带的参数绑定能力接收
accId,不需要自己写解析逻辑,Spring会自动处理逗号分割、类型转换:
@RestController // 补全路径里的{service}占位符 @RequestMapping(APIConstants.API_BASE_URI + APIConstants.MYCONTROLLER + "/{service}") public class MyController extends APIRESTResource { @GetMapping("/activate") public ResponseEntity<String> activateAccount( @PathVariable("service") String srvc, // Spring自动解析逗号分割的accId参数为Long列表,自动做类型转换 @RequestParam("accId") List<Long> accountIdList ) { HttpStatus status = HttpStatus.OK; MediaType type = MediaType.TEXT_PLAIN; String payload = "Activated"; try { String datasource = getDatasourceForService(srvc); AccountsServiceImpl mgr = new AccountsServiceImpl(datasource); // 修正原代码的变量名笔误 mgr.activateAccounts(accountIdList); HttpHeaders headers = new HttpHeaders(); headers.setContentType(type); return new ResponseEntity<>(payload, headers, status); } catch (Exception ex) { return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } } }
- 如果你确实需要保留自定义参数解析逻辑,把
UriInfo替换为Spring原生的HttpServletRequest即可,类上注入的@Context UriInfo也一并替换:
// 类上注入的写法 @Autowired private HttpServletRequest request; // 自定义解析方法修改入参类型 private List<Long> extractAccountIdsAsList(HttpServletRequest request) throws Exception { String fieldName = "accId"; // 从request对象获取查询参数 String accIdStr = request.getParameter(fieldName); validateRequiredField(fieldName, accIdStr); // 原有解析逻辑不需要改动 accIdStr = accIdStr.replace(" ", ""); String[] accIds = accIdStr.contains(",") ? accIdStr.split("\\,") : new String[]{accIdStr}; List<Long> accIdList = new ArrayList<>(); for (String accId : accIds) { validateFieldValueType(fieldName, accId, Long.TYPE); accIdList.add(Long.parseLong(accId)); } return accIdList; }
方案2:配置JAX-RS与Spring整合(不推荐)
如果项目必须保留JAX-RS的@Context注解使用,需要引入对应JAX-RS实现与Spring的整合依赖(比如jersey-spring),并配置JAX-RS注解解析器让Spring能识别@Context的注入语义。但这种方案容易出现依赖冲突、请求处理链冲突的问题,在已经以Spring MVC为主要web栈的项目中不建议使用。
内容的提问来源于stack exchange,提问作者JackTheKnife
相关产品推荐
相关产品推荐

