为何Spring Security配置类需同时标注@Configuration与@EnableWebSecurity
我正在阅读《Spring实战(第5版)》,在第4部分Spring安全模块中,作者为了覆盖Spring Boot自动配置的默认安全规则,创建了名为SecurityConfig的配置类,代码如下:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { }
官方@EnableWebSecurity的Javadoc文档中,示例代码也采用了相同的写法,文档说明如下:
请将该注解添加到标注了@Configuration的类上,即可通过任意WebSecurityConfigurer定义Spring Security配置,更常见的做法是继承WebSecurityConfigurerAdapter基类并重写对应方法,实现自定义安全配置。
但查看@EnableWebSecurity的源码可以发现,该注解本身已经被元标注了@Configuration,源码片段如下:
@Retention(RUNTIME) @Target(TYPE) @Documented @Import({WebSecurityConfiguration.class, org.springframework.security.config.annotation.web.configuration.SpringWebMvcImportSelector.class, org.springframework.security.config.annotation.web.configuration.OAuth2ImportSelector.class, org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.class}) @EnableGlobalAuthentication @Configuration public @interface EnableWebSecurity
对应的疑问是:为什么自定义安全配置类需要同时标注@Configuration和@EnableWebSecurity两个注解,而不是仅标注@EnableWebSecurity即可?
很多人一开始都会有这个疑问,本质是对Spring注解的传递规则存在认知误区:注解类自身标注的元注解,不会自动传递生效到被该注解标注的业务类上。
@EnableWebSecurity源码上的@Configuration,作用是让Spring框架识别到@EnableWebSecurity本身是配置类级别的注解,触发它自带的@Import逻辑,把Spring Security运行需要的WebSecurityConfiguration、HttpSecurityConfiguration等核心配置类加载到容器中,这个元注解的作用范围只针对@EnableWebSecurity注解本身,不会传递到你自己写的SecurityConfig类上。- 如果自定义安全配置类只加
@EnableWebSecurity、不显式加@Configuration,Spring在做组件扫描的时候,不会把这个类判定为需要解析的配置类,你在类里重写的权限拦截规则、登录逻辑等配置方法,还有类中声明的安全相关@Bean都不会被解析加载,最终写的自定义安全规则完全不生效。 - 官方文档和示例统一显式标注两个注解,也是为了做通用兼容:不管是单独拆分的独立配置类,还是不同版本的Spring/Spring Boot环境,都不会因为配置类识别逻辑的差异出现配置失效的问题,是最稳妥的写法。
补充一个特殊场景:如果把@EnableWebSecurity直接标注在Spring Boot启动类上——启动类自带的@SpringBootApplication注解已经包含了@Configuration元注解,这种场景下不用额外重复加@Configuration也能正常运行,但单独编写独立的安全配置类时,必须显式标注@Configuration。
内容的提问来源于stack exchange,提问作者mouad36

