java - @ComponentScan 和 @Bean 在上下文配置中有什么区别?
问题描述
至少有两种方法可以将 Spring bean 放入上下文配置中:
@Bean
在配置类中声明一个方法。- 放上
@ComponentScan
配置类。
我期望这两种方法在生成的 Spring bean 方面没有区别。
但是,我找到了一个示例来说明差异:
// UserInfoService.java
public interface UserInfoService
{
@PreAuthorize("isAuthenticated()")
String getUserInfo ();
}
// UserInfoServiceTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextHierarchy({
@ContextConfiguration(classes = TestSecurityContext.class),
@ContextConfiguration(classes = UserInfoServiceTest.Config.class)
})
public class UserInfoServiceTest
{
@Configuration
public static class Config
{
@Bean
public UserInfoService userInfoService ()
{
return new UserInfoServiceImpl();
}
}
@Autowired
private UserInfoService userInfoService;
@Test
public void testGetUserInfoWithoutUser ()
{
assertThatThrownBy(() -> userInfoService.getUserInfo())
.isInstanceOf(AuthenticationCredentialsNotFoundException.class);
}
@Test
@WithMockUser
public void testGetUserInfoWithUser ()
{
String userInfo = userInfoService.getUserInfo();
assertThat(userInfo).isEqualTo("info about user");
}
上面的代码是为了测试服务中的安全注解UserInfoService
。但是,它会在testGetUserInfoWithoutUser()
. 原因是 beanuserInfoService
没有被 Spring Security 代理。因此,调用userInfoService.getUserInfo()
没有被注释阻止@PreAuthorize("isAuthenticated()")
。
但是,如果我用 替换@Bean
注释@ComponentScan
,一切都会开始工作。也就是说,beanuserInfoService
将被代理并且调用userInfoService.getUserInfo()
将被@PreAuthorize
注解阻塞。
@Bean
为什么和之间的方法@ComponentScan
不同?我错过了什么?
解决方案
这是因为@ContextHierarchy
将创建具有父子层次结构的多个弹簧上下文。在您的情况下,TestSecurityContext
为父上下文定义 bean 配置,同时UserInfoServiceTest.Config
为子上下文定义。
如果 没有@ComponentScan
,UserInfoServiceTest.Config
则安全相关的 bean 定义在父上下文中,对子上下文中的UserInfoService
bean 是不可见的,因此它不会被 Spring Security 代理。
另一方面,如果您@ComponentScan
在 上定义UserInfoServiceTest.Config
,它还将扫描@Configuration
包含UserInfoService
(及其所有子包)的包中的所有 bean。因为TestSecurityContext
也在这个包内,因此它被扫描并且与安全相关的bean也被配置为子上下文。UserInfoService
然后在子上下文中将由 Spring Security 代理。(注意:在这种情况下,父上下文和子上下文都有自己的一组安全相关 bean)
顺便说一句,如果您只需要一个上下文,您可以简单地使用@ContextConfiguration
:
@ContextConfiguration(classes= {TestSecurityContext.class,UserInfoServiceTest.Config.class})
public class UserInfoServiceTest {
public static class Config {
@Bean
public UserInfoService userInfoService() {
return new UserInfoServiceImpl();
}
}
}
推荐阅读
- generics - Rust 特征边界与类型
- database - 查找在 id 列中出现一次并具有标志 1 的所有 id
- java - 如何交换二维字符串数组中的字符串位置
- spring - oauth 2.0、JWT、Spring 安全、微服务
- angular - 我需要将打字稿类链接到角度组件
- python - 在 pexpect 中切换交互和非交互模式
- sql - 更新 SQL 命令未使用 JSP 更新 SQL 记录
- swift - 在 CK 查询中无法获得多个结果的问题,其中可能多次返回相同的记录
- vue.js - SPA 有没有办法检查是否有代理并正确处理它?
- c - C中的混合快速排序+插入排序