集成测试中@PreAuthorize注解导致注入Bean为空的问题排查
问题根源
当给控制器方法添加@PreAuthorize、@Secured或@RolesAllowed这类方法级安全注解时,Spring Security会通过AOP为控制器生成代理对象。如果控制器未实现接口,默认会使用CGLIB代理,但如果配置或环境触发了JDK动态代理(基于接口的代理方式),代理对象不会继承原控制器类的字段,就会出现注入的Bean为空的情况。另外,代理初始化时机不当也可能导致依赖注入未完成。
具体解决办法
1. 强制使用CGLIB代理
在测试配置类或starter的自动配置类中,开启CGLIB代理模式:
@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true) public class TestSecurityConfig { // 自定义安全配置逻辑 }
proxyTargetClass = true会强制Spring使用CGLIB生成代理,代理对象会继承原控制器的所有字段,注入的Bean就能正常访问。
2. 改用构造函数注入
避免在控制器字段上直接使用@Autowired,改用Spring官方推荐的构造函数注入方式,确保代理创建前完成依赖注入:
@RestController public class TestController { private final ApplicationContext applicationContext; // Spring 4.3+无需添加@Autowired,自动识别构造函数注入 public TestController(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } @PreAuthorize("hasRole('ADMIN')") @GetMapping("/test") public String test() { // 正常使用applicationContext return "success"; } }
3. 检查测试类配置
确保测试类正确加载Spring上下文,配置必要的测试注解:
@SpringBootTest(classes = TestApplication.class) @AutoConfigureMockMvc public class SecurityIT { @Autowired private MockMvc mockMvc; @Test public void testAuthorizedRequest() throws Exception { mockMvc.perform(get("/test") .with(user("admin").roles("ADMIN"))) .andExpect(status().isOk()); } }
@SpringBootTest需指定正确的启动类,@AutoConfigureMockMvc会自动配置MockMvc,保证测试上下文完整初始化所有Bean和代理对象。
4. 调整自动配置加载顺序
如果starter的自动配置类有依赖顺序要求,让它在Spring Security自动配置之后加载,避免代理逻辑提前初始化导致依赖注入未完成:
@AutoConfigureAfter(SecurityAutoConfiguration.class) @Configuration public class MySecurityAutoConfiguration { // starter的自动配置逻辑 }
内容的提问来源于stack exchange,提问作者pirox22
相关产品推荐
相关产品推荐

