注入到 spring 控制器中的服务在其中一项功能中不可用

Are*_*inu 1 java rest spring dependency-injection controller

我正在编写 spring 控制器,它注入一个 bean。

\n\n

bean 添加到配置中(我们使用 java 配置来完成所有操作):

\n\n
@Bean\npublic NotificationService notificationService() {\n    return new NotificationService();\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

该服务本身几乎没有注入的依赖项和功能:

\n\n
public class NotificationService {\n\n    @Inject\n    NotificationRepository notificationRepository;\n\n    @Inject\n    ProjectRepository projectRepository;\n\n    @Inject\n    ModelMapper modelMapper;\n\n    public NotificationDto create(NotificationDto notificationDto) {\n        //convert to domain object, save, return dto with updated ID\n        return notificationDto;\n    }\n\n    public void markAsRead(Long id, String recipientNip) {\n        //find notification, update status\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

模型映射器几乎没有任何配置,只是设置为严格。JpaRepository同时,存储库是没有自定义功能的扩展接口。他们是由 找到的@EnableJpaRepositories

\n\n

最后我有控制器尝试使用上面的代码:

\n\n
@RestController\n@RequestMapping("/notifications")\npublic class NotificationController extends ExceptionHandlerController {\n\n    @Autowired\n    private NotificationService notificationService;\n\n    @PreAuthorize("isFullyAuthenticated() and hasRole(\'create_notification\')")\n    @RequestMapping(method = RequestMethod.POST, consumes = MediaTypeExtension.APPLICATION_JSON_UTF8_VALUE)\n    public ResponseEntity<?> createNotification(@Valid @RequestBody(required = true) final NotificationDto notification) {\n        this.notificationService.create(notification);\n        final HttpHeaders headers = new HttpHeaders();\n        return new ResponseEntity<>(headers, HttpStatus.CREATED);\n    }\n\n    @PreAuthorize("isFullyAuthenticated() and hasRole(\'update_notification\')")\n    @RequestMapping(value = "/{id}/read", method = RequestMethod.PUT)\n    private ResponseEntity<?> markNotificationAsRead(@PathVariable("id") Long id, @AuthenticatedContractor ContractorDto contractor) {\n        this.notificationService.markAsRead(id, contractor.getNip());\n        final HttpHeaders headers = new HttpHeaders();\n        return new ResponseEntity<>(headers, HttpStatus.OK);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

所有控制器都是根据其包通过 @ComponentScan 添加的。

\n\n

正如您所看到的,这两个函数都使用notificationService. 当我发送时POSTcreate已正确/notifications注入notificationService。在同一个控制器中,当我PUT在 上请求时/{id}/readnotificationServicenull

\n\n

我认为这与 spring 将东西放入其容器中有关,并且由于某种原因无法执行该功能。我在控制器中还有一些功能,并且所有功能notificationService都已正确注入。我没有看到createNotificationmarkNotificationAsRead函数之间有任何真正的区别,而且我在 google/stack 上找不到任何远程相关的东西。在所有情况下,由于配置错误,服务根本不会注入。

\n\n

编辑\n我尝试更改函数中的内容,直到它开始工作。我的最终代码如下所示:

\n\n
@PreAuthorize("isFullyAuthenticated() and hasRole(\'update_notification\')")\n    @RequestMapping(value = "{id}/read", method = RequestMethod.PUT)\n    public ResponseEntity<?> read(@PathVariable("id") Long id, @AuthenticatedContractor ContractorDto contractor) {\n        this.notificationService.markAsRead(id, contractor.getNip());\n\n        final HttpHeaders headers = new HttpHeaders();\n        return new ResponseEntity<>(headers, HttpStatus.OK);\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

它有效。老实说,我看不出与原始代码有任何区别,并且我已经盯着它看了一个小时左右。进口的也是一样的。

\n\n

我还注意到(在无法工作的代码上),虽然调试堆栈上控制器的所有函数都被标记为

\n\n
NotificationController.functionName(arguments) line: x\n
Run Code Online (Sandbox Code Playgroud)\n\n

非工作功能是:

\n\n
NotificationController$$EnhancerBySpringCGLIB$$64d88bfe(NotificationController).\xe2\x80\x8c\xe2\x80\x8bmarkNotificationAsRead(ContractorDto) line: 86\n
Run Code Online (Sandbox Code Playgroud)\n\n

我不知道为什么 spring CGLIB 增强了这个单一功能。我尝试过查找,但现在我两手空空。即使代码开始工作,我仍将问题悬而未决,以便找到根本原因。

\n

mvm*_*vmn 7

您的方法markNotificationAsRead是私有的,这可能会导致问题。我刚刚对最终方法遇到了同样的问题 - 此消息出现在日志中:

2016-11-28 17:19:14.186  INFO 97079 --- [           main] o.s.aop.framework.CglibAopProxy          : Unable to proxy method [public final java.util.Map com.package.controller.MyController.someMethod(javax.servlet.http.HttpServletResponse)] because it is final: All calls to this method via a proxy will NOT be routed to the target instance.
Run Code Online (Sandbox Code Playgroud)

看起来在一种情况下我们看到了 CGLib 代理,而在另一种情况下我们看到了实际的类。其中只有一个已注入所有字段,看起来代理的所有字段均为空。但这并不重要 - 重点是您的方法应该是公共的,而不是最终的,以便通过 @PreAuthorize 方法正确代理。

  • 从那时起我们做了一些不同的事情来解决这个问题,但我检查了旧的提交并且它有效。天哪,这么简单,却很难发现。 (2认同)
  • 是的。此日志消息的“INFO”级别是一个奇怪的选择。 (2认同)