注入弹簧控制器的服务在其中一个功能中不可用

时间:2015-04-22 15:50:27

标签: java spring rest dependency-injection controller

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

bean在config中添加(我们使用java配置):

@Bean
public NotificationService notificationService() {
    return new NotificationService();
}

服务本身几乎没有注入依赖项和几个函数:

public class NotificationService {

    @Inject
    NotificationRepository notificationRepository;

    @Inject
    ProjectRepository projectRepository;

    @Inject
    ModelMapper modelMapper;

    public NotificationDto create(NotificationDto notificationDto) {
        //convert to domain object, save, return dto with updated ID
        return notificationDto;
    }

    public void markAsRead(Long id, String recipientNip) {
        //find notification, update status
    }
}

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

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

@RestController
@RequestMapping("/notifications")
public class NotificationController extends ExceptionHandlerController {

    @Autowired
    private NotificationService notificationService;

    @PreAuthorize("isFullyAuthenticated() and hasRole('create_notification')")
    @RequestMapping(method = RequestMethod.POST, consumes = MediaTypeExtension.APPLICATION_JSON_UTF8_VALUE)
    public ResponseEntity<?> createNotification(@Valid @RequestBody(required = true) final NotificationDto notification) {
        this.notificationService.create(notification);
        final HttpHeaders headers = new HttpHeaders();
        return new ResponseEntity<>(headers, HttpStatus.CREATED);
    }

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

所有控制器都是通过@ComponentScan添加的,基于它们的包。

正如您所看到的,两个函数都使用notificationService。当我POST create /notifications notificationService时,PUT已正确注入/{id}/read。在同一个控制器中,当我notificationService nullnotificationService createNotification markNotificationAsRead @PreAuthorize("isFullyAuthenticated() and hasRole('update_notification')") @RequestMapping(value = "{id}/read", method = RequestMethod.PUT) public ResponseEntity<?> read(@PathVariable("id") Long id, @AuthenticatedContractor ContractorDto contractor) { this.notificationService.markAsRead(id, contractor.getNip()); final HttpHeaders headers = new HttpHeaders(); return new ResponseEntity<>(headers, HttpStatus.OK); }

我认为它与将弹簧放入其容器中有关,并且由于某种原因无法为该功能执行此操作。我在控制器中有更多功能,并且所有功能NotificationController.functionName(arguments) line: x 都已正确注入。我发现NotificationController$$EnhancerBySpringCGLIB$$64d88bfe(NotificationController).‌​markNotificationAsRead(ContractorDto) line: 86 和{{1}}功能之间没有任何真正的区别,我无法在Google /堆栈上找到任何与远程相关的内容。在所有情况下,由于配置错误,服务根本不会注入。

修改 我已经尝试在函数中改变它,直到它开始工作。我的最终代码如下所示:

{{1}}

它有效。老实说,我看不出我原来的代码有什么不同,我一直在盯着它看了一个小时左右。进口也是一样。

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

{{1}}

非工作职能是:

{{1}}

为什么弹簧CGLIB增强了这个单一的功能我不知道。我试过看了,但是现在我空手而归。即使代码开始起作用,我仍然会打开问题以找到根本原因。

2 个答案:

答案 0 :(得分:3)

您的方法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.

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

答案 1 :(得分:2)

我也面临着同样的问题。这都是由于使用了专用访问修饰符和@PreAuthorize。如果您不将控制器方法设为私有,则将其设为私有不会产生问题。但是,为了确保安全,请将其公开。