SpringBoot?Test的webEnvironment源碼解讀
序
本文主要研究一下SpringBootTest的webEnvironment
SpringBootTest
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @BootstrapWith(SpringBootTestContextBootstrapper.class) @ExtendWith({SpringExtension.class}) public @interface SpringBootTest { @AliasFor("properties") String[] value() default {}; @AliasFor("value") String[] properties() default {}; String[] args() default {}; Class<?>[] classes() default {}; WebEnvironment webEnvironment() default SpringBootTest.WebEnvironment.MOCK; }
SpringBootTest的webEnvironment默認(rèn)為SpringBootTest.WebEnvironment.MOCK
WebEnvironment
/** * An enumeration web environment modes. */ enum WebEnvironment { /** * Creates a {@link WebApplicationContext} with a mock servlet environment if * servlet APIs are on the classpath, a {@link ReactiveWebApplicationContext} if * Spring WebFlux is on the classpath or a regular {@link ApplicationContext} * otherwise. */ MOCK(false), /** * Creates a web application context (reactive or servlet based) and sets a * {@code server.port=0} {@link Environment} property (which usually triggers * listening on a random port). Often used in conjunction with a * {@link LocalServerPort @LocalServerPort} injected field on the test. */ RANDOM_PORT(true), /** * Creates a (reactive) web application context without defining any * {@code server.port=0} {@link Environment} property. */ DEFINED_PORT(true), /** * Creates an {@link ApplicationContext} and sets * {@link SpringApplication#setWebApplicationType(WebApplicationType)} to * {@link WebApplicationType#NONE}. */ NONE(false); private final boolean embedded; WebEnvironment(boolean embedded) { this.embedded = embedded; } /** * Return if the environment uses an {@link ServletWebServerApplicationContext}. * @return if an {@link ServletWebServerApplicationContext} is used. */ public boolean isEmbedded() { return this.embedded; } }
WebEnvironment有四個枚舉,分別是MOCK、RANDOM_PORT、DEFINED_PORT、NONE
SpringBootTestContextBootstrapper
spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java
public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstrapper { private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" }; private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework." + "web.reactive.DispatcherHandler"; private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework.web.servlet.DispatcherServlet"; private static final String JERSEY_WEB_ENVIRONMENT_CLASS = "org.glassfish.jersey.server.ResourceConfig"; private static final String ACTIVATE_SERVLET_LISTENER = "org.springframework.test." + "context.web.ServletTestExecutionListener.activateListener"; private static final Log logger = LogFactory.getLog(SpringBootTestContextBootstrapper.class); @Override public TestContext buildTestContext() { TestContext context = super.buildTestContext(); verifyConfiguration(context.getTestClass()); WebEnvironment webEnvironment = getWebEnvironment(context.getTestClass()); if (webEnvironment == WebEnvironment.MOCK && deduceWebApplicationType() == WebApplicationType.SERVLET) { context.setAttribute(ACTIVATE_SERVLET_LISTENER, true); } else if (webEnvironment != null && webEnvironment.isEmbedded()) { context.setAttribute(ACTIVATE_SERVLET_LISTENER, false); } return context; } //...... }
SpringBootTestContextBootstrapper繼承了DefaultTestContextBootstrapper,其buildTestContext方法會判斷webEnvironment,然后決定ACTIVATE_SERVLET_LISTENER是設(shè)置為true還是false,在為MOCK的時候該值為true
ServletTestExecutionListener
spring-test/src/main/java/org/springframework/test/context/web/ServletTestExecutionListener.java
private boolean isActivated(TestContext testContext) { return Boolean.TRUE.equals(testContext.getAttribute(ACTIVATE_LISTENER)) || AnnotatedElementUtils.hasAnnotation(testContext.getTestClass(), WebAppConfiguration.class); } private void setUpRequestContextIfNecessary(TestContext testContext) { if (!isActivated(testContext) || alreadyPopulatedRequestContextHolder(testContext)) { return; } ApplicationContext context = testContext.getApplicationContext(); if (context instanceof WebApplicationContext) { WebApplicationContext wac = (WebApplicationContext) context; ServletContext servletContext = wac.getServletContext(); Assert.state(servletContext instanceof MockServletContext, () -> String.format( "The WebApplicationContext for test context %s must be configured with a MockServletContext.", testContext)); if (logger.isDebugEnabled()) { logger.debug(String.format( "Setting up MockHttpServletRequest, MockHttpServletResponse, ServletWebRequest, and RequestContextHolder for test context %s.", testContext)); } MockServletContext mockServletContext = (MockServletContext) servletContext; MockHttpServletRequest request = new MockHttpServletRequest(mockServletContext); request.setAttribute(CREATED_BY_THE_TESTCONTEXT_FRAMEWORK, Boolean.TRUE); MockHttpServletResponse response = new MockHttpServletResponse(); ServletWebRequest servletWebRequest = new ServletWebRequest(request, response); RequestContextHolder.setRequestAttributes(servletWebRequest); testContext.setAttribute(POPULATED_REQUEST_CONTEXT_HOLDER_ATTRIBUTE, Boolean.TRUE); testContext.setAttribute(RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE, Boolean.TRUE); if (wac instanceof ConfigurableApplicationContext) { @SuppressWarnings("resource") ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) wac; ConfigurableListableBeanFactory bf = configurableApplicationContext.getBeanFactory(); bf.registerResolvableDependency(MockHttpServletResponse.class, response); bf.registerResolvableDependency(ServletWebRequest.class, servletWebRequest); } } }
ServletTestExecutionListener的isActivated會判斷ACTIVATE_SERVLET_LISTENER是不是設(shè)置為true,或者testClass有標(biāo)注@WebAppConfiguration; setUpRequestContextIfNecessary方法會調(diào)用isActivated來決定是否初始化MockHttpServletRequest等設(shè)置
小結(jié)
SpringBootTest的webEnvironment默認(rèn)為SpringBootTest.WebEnvironment.MOCK,它會設(shè)置ACTIVATE_SERVLET_LISTENER是設(shè)置為true,即在ServletTestExecutionListener的isActivated為true,在setUpRequestContextIfNecessary方法會初始化MockHttpServletRequest、MockHttpServletResponse等。
以上就是SpringBootTest的webEnvironment源碼解讀的詳細內(nèi)容,更多關(guān)于SpringBootTest webEnvironment的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java批量下載將多個文件(minio中存儲)壓縮成一個zip包代碼示例
在Java應(yīng)用程序中有時我們需要從多個URL地址下載文件,并將這些文件打包成一個Zip文件進行批量處理或傳輸,這篇文章主要給大家介紹了關(guān)于java批量下載將多個文件(minio中存儲)壓縮成一個zip包的相關(guān)資料,需要的朋友可以參考下2023-11-11解析SpringBoot中@Autowire注解的實現(xiàn)原理
在開發(fā)Java項目時,依賴注入是一種常見的實現(xiàn)方式,SpringBoot框架通過@Autowired注解來實現(xiàn)依賴注入的功能,本文將介紹SpringBoot中 Autowired注解實現(xiàn)的原理2023-06-06SpringBoot?+?Vue?+?ElementUI?實現(xiàn)?el-table?分頁功能(詳細步驟)
本文詳細介紹了使用SpringBoot和Vue.js結(jié)合ElementUI實現(xiàn)分頁功能的數(shù)據(jù)表格,從后端分頁邏輯到前端展示和狀態(tài)管理,全面解析如何高效處理大量數(shù)據(jù),提升用戶體驗與系統(tǒng)性能,感興趣的朋友跟隨小編一起看看吧2024-09-09在java中使用SPI創(chuàng)建可擴展的應(yīng)用程序操作
這篇文章主要介紹了在java中使用SPI創(chuàng)建可擴展的應(yīng)用程序操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09SecurityUtils.getSubject().getPrincipal()為null的問題
這篇文章主要介紹了SecurityUtils.getSubject().getPrincipal()為null的問題及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07SpringBoot集成redis與session實現(xiàn)分布式單點登錄
這篇文章主要介紹了SpringBoot集成redis與session實現(xiàn)分布式單點登錄,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-09-09