我正在编写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
null
时notificationService
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增强了这个单一的功能我不知道。我试过看了,但是现在我空手而归。即使代码开始起作用,我仍然会打开问题以找到根本原因。
答案 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。如果您不将控制器方法设为私有,则将其设为私有不会产生问题。但是,为了确保安全,请将其公开。