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

问题描述 投票:1回答:2

我正在写一个注入bean的spring控制器。

bean在config中添加(我们使用java config来处理所有内容):

@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请求时,notificationServicenull

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

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

@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

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

java spring rest dependency-injection controller
2个回答
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方法正确代理。


2
投票

我也面临同样的问题。这完全归功于使用的私有访问修饰符和@PreAuthorize。如果不使其安全,则将控制器方法设为私有不会产生问题。但是,要确保安全,请将其公之于众。

© www.soinside.com 2019 - 2024. All rights reserved.