英文:
@WithMockUser in a parallel context
问题
以下是您要翻译的内容:
以下代码只是我想实现的简化版本。
我在测试中使用@WithMockUser(username = "jane@no-domain.com", authorities = {"ROLE_ADMIN"})
来模拟用户。
@RunWith(SpringRunner.class)
@SpringBootTest
@EnableAsync
@WithMockUser(username = "jane@no-domain.com", authorities = {"ROLE_ADMIN"})
public class NonTest {
@Test
public void test() {
IntStream.range(1, 10)
.parallel() // 注释掉这一行,它就会正常工作
.forEach(value -> {
getUser(value);
});
}
public void getUser(int value) {
System.out.println(value + ": " + ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername());
}
}
当我将上述代码执行时,如果将.parallel()
注释掉,它将按预期输出以下内容:
1: jane@no-domain.com
2: jane@no-domain.com
3: jane@no-domain.com
4: jane@no-domain.com
5: jane@no-domain.com
6: jane@no-domain.com
7: jane@no-domain.com
8: jane@no-domain.com
9: jane@no-domain.com
... 但是当我添加.parallel()
时,它会抛出NullPointerException
,因为某种方式下模拟的用户不存在。
当我使用ExecutorService
或任何线程时,它的行为是相同的。
那么,我该如何并行执行这个方法呢?
英文:
The following code is just a simplified version of what I want to achieve.
I am using @WithMockUser(username = "jane@no-domain.com", authorities = {"ROLE_ADMIN"})
to mock a user in my tests.
@RunWith(SpringRunner.class)
@SpringBootTest
@EnableAsync
@WithMockUser(username = "jane@no-domain.com", authorities = {"ROLE_ADMIN"})
public class NonTest {
@Test
public void test() {
IntStream.range(1, 10)
.parallel() // Comment this and it will work
.forEach(value -> {
getUser(value);
});
}
public void getUser(int value) {
System.out.println(value + ": " + ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername());
}
}
When I execute the above code with .parallel()
commented out, it works and prints out the following as intended:
1: jane@no-domain.com
2: jane@no-domain.com
3: jane@no-domain.com
4: jane@no-domain.com
5: jane@no-domain.com
6: jane@no-domain.com
7: jane@no-domain.com
8: jane@no-domain.com
9: jane@no-domain.com
... but when I add the .parallel()
it throws a NullPointerException
since somehow the mocked user is not present.
It behaves the same way when I use an ExecutorService
or any threading of some sort.
So, how do I execute the method in parallel?
答案1
得分: 3
使用.parallel()
将会启动多个线程并行运行流。根据教程中的描述:
> 当流以并行方式执行时,Java运行时会将流分成多个子流。聚合操作会并行迭代和处理这些子流,然后合并结果。
因此,您需要使子线程从本地线程继承SecurityContextHolder
,为此,您可以使用@PostConstruct
,如下所示(更多信息请参见这里):
@SpringBootTest
@EnableAsync
@WithMockUser(username = "jane@no-domain.com", authorities = {"ROLE_ADMIN"})
public class NonTest {
@Test
public void test() {
IntStream.range(1, 10)
.parallel()
.forEach(this::getUser);
}
@PostConstruct
void setGlobalSecurityContext() {
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
}
public void getUser(int value) {
System.out.println(value + ": " + ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername());
}
}
输出
6: jane@no-domain.com
7: jane@no-domain.com
1: jane@no-domain.com
2: jane@no-domain.com
3: jane@no-domain.com
9: jane@no-domain.com
4: jane@no-domain.com
8: jane@no-domain.com
5: jane@no-domain.com
英文:
The use of .parallel()
will spawn multiple threads to run over the stream in parallel. From the tutorial on streams:
> When a stream executes in parallel, the Java runtime partitions the
> stream into multiple substreams. Aggregate operations iterate over and
> process these substreams in parallel and then combine the results.
So you need to make the children threads inherit the SecurityContextHolder
from the local thread, for this you could use @PostConstruct
as follows, (see more info here):
@SpringBootTest
@EnableAsync
@WithMockUser(username = "jane@no-domain.com", authorities = {"ROLE_ADMIN"})
public class NonTest {
@Test
public void test() {
IntStream.range(1, 10)
.parallel()
.forEach(this::getUser);
}
@PostConstruct
void setGlobalSecurityContext() {
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
}
public void getUser(int value) {
System.out.println(value + ": " + ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername());
}
}
Output
6: jane@no-domain.com
7: jane@no-domain.com
1: jane@no-domain.com
2: jane@no-domain.com
3: jane@no-domain.com
9: jane@no-domain.com
4: jane@no-domain.com
8: jane@no-domain.com
5: jane@no-domain.com
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论