添加@PreAuthorize注解后Service注入为null的原因排查
问题原因及解决方案
核心原因
你的控制器方法使用了private修饰符,而Spring Security的@PreAuthorize注解依赖Spring AOP实现权限拦截,AOP机制无法对private方法进行代理增强:
- JDK动态代理只能代理接口的public方法;
- CGLIB代理虽然可以继承目标类,但也无法拦截父类的private方法(子类无法访问父类私有方法)。
添加@PreAuthorize后,Spring尝试为UserController生成代理类以实现权限校验,但由于目标方法是private,代理逻辑无法生效,最终导致请求调用的对象并非Spring容器中已完成依赖注入的Bean实例,因此userService为null。
移除@PreAuthorize后,Spring MVC通过反射直接调用控制器的private方法(虽然不规范,但反射可访问私有方法),此时调用的是Spring容器中已注入依赖的Bean,所以能正常工作。
解决方案
将控制器中的方法修饰符改为public:
@RestController @RequestMapping("/users") public class UserController { private final UserServiceImpl userService; @Autowired public UserController(UserServiceImpl userService) { this.userService = userService; } @PutMapping @PreAuthorize("hasAnyAuthority('ADMIN')") // 修改为public public ResponseEntity<ResultDto<UserDto>> updateUser(@RequestBody UserUpdateDto userUpdateDto) { return ResponseEntity.ok(new ResultDto<>(userService.updateUser(userUpdateDto))); } @GetMapping("/{id}") // 修改为public public ResponseEntity<ResultDto<UserDto>> getUserById(@PathVariable Long id) { return ResponseEntity.ok(new ResultDto<>(userService.findById(id))); } ... }
额外说明
Spring MVC的控制器方法规范上必须是public的,即使反射能调用private方法,也会破坏Spring的代理机制(包括AOP、事务、权限等),引发各类异常问题,务必遵循规范使用public修饰控制器方法。
内容的提问来源于stack exchange,提问作者Soymun
相关产品推荐
相关产品推荐

