我在Spring Boot中使用@PostConstruct
方法提供服务。在某些集成测试中,不得执行此方法(在这些集成测试中根本不使用该服务)。所以我想我可以让new
在此测试(@ContextConfiguration
)中加载的配置类中创建bean。
但是,这不符合我的想法。 @PostConstruct
仍然被调用,甚至两次,如下所示(是,这是整个代码):
应用
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
服务
@Service
public class MyService {
@PostConstruct
public void startup() {
System.out.println("@PostConstruct - " + this);
}
}
测试
@RunWith(SpringRunner.class)
@SpringBootTest(
webEnvironment = WebEnvironment.RANDOM_PORT,
classes = {DemoApplication.class})
@ContextConfiguration(classes = TestConfiguration.class)
public class DemoApplicationTests {
@Test
public void test() {
System.out.println("Test");
}
@Configuration
static class TestConfiguration {
@Bean
public MyService xxx() {
MyService myService = new MyService();
System.out.println("@Bean - " + myService);
return myService;
}
}
}
如果执行测试,将输出以下输出:
:: Spring Boot :: (v2.1.1.RELEASE)
...
2018-11-30 20:34:28.422 INFO 16916 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2018-11-30 20:34:28.422 INFO 16916 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1573 ms
@PostConstruct - com.example.demo.MyService@41c89d2f
@Bean - com.example.demo.MyService@2516fc68
@PostConstruct - com.example.demo.MyService@2516fc68
2018-11-30 20:34:28.838 INFO 16916 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2018-11-30 20:34:29.086 INFO 16916 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 62040 (http) with context path ''
2018-11-30 20:34:29.090 INFO 16916 --- [ main] com.example.demo.DemoApplicationTests : Started DemoApplicationTests in 2.536 seconds (JVM running for 4.187)
Test
2018-11-30 20:34:29.235 INFO 16916 --- [ Thread-3] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
有人可以向我解释吗?
@PostConstruct
被称为@PostConstruct
调用由new
构造的bean。为什么这个豆在春天被管理? 编辑:
我试图返回使用Mockito.mock(...)
创建的bean,而不是使用new
创建的bean。从某种意义上说,这有助于避免执行第二个@PostConstruct
。所以问题仍然存在:为什么第一个?以及如何摆脱它呢?
答案 0 :(得分:2)
我将解释所有情况下的行为,以便您了解发生了什么。
调用第一个PostConstruct是因为您正在使用SpringRunner
和@SpringBootTest
运行测试,这是扫描类路径并将MyService
注册为Bean,因为它带有{{1 }}。
之所以调用第二个PostConstruct,是因为即使您正在更新MyService,您仍在用@Service
注释的方法中进行了此操作,该方法在Spring上下文中注册了bean,因此它仅参与了生命周期。其他任何bean所采用的方式(包括调用其@Bean
和@PostConstruct
方法)。
如果您不希望在SpringBootTests中使用@PreDestroy
的真实实例,则可以使用MyService
。在您的SpringBootTests中,您可能需要MockBean胜过Mock,因为它将在您的Spring上下文中模拟bean。