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有四個(gè)枚舉,分別是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方法會(huì)判斷webEnvironment,然后決定ACTIVATE_SERVLET_LISTENER是設(shè)置為true還是false,在為MOCK的時(shí)候該值為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會(huì)判斷ACTIVATE_SERVLET_LISTENER是不是設(shè)置為true,或者testClass有標(biāo)注@WebAppConfiguration; setUpRequestContextIfNecessary方法會(huì)調(diào)用isActivated來決定是否初始化MockHttpServletRequest等設(shè)置
小結(jié)
SpringBootTest的webEnvironment默認(rèn)為SpringBootTest.WebEnvironment.MOCK,它會(huì)設(shè)置ACTIVATE_SERVLET_LISTENER是設(shè)置為true,即在ServletTestExecutionListener的isActivated為true,在setUpRequestContextIfNecessary方法會(huì)初始化MockHttpServletRequest、MockHttpServletResponse等。
以上就是SpringBootTest的webEnvironment源碼解讀的詳細(xì)內(nèi)容,更多關(guān)于SpringBootTest webEnvironment的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java實(shí)現(xiàn)鏈表數(shù)據(jù)結(jié)構(gòu)的方法
這篇文章主要介紹了Java實(shí)現(xiàn)鏈表數(shù)據(jù)結(jié)構(gòu)的相關(guān)資料,每一個(gè)鏈表都包含多個(gè)節(jié)點(diǎn),節(jié)點(diǎn)又包含兩個(gè)部分,一個(gè)是數(shù)據(jù)域(儲(chǔ)存節(jié)點(diǎn)含有的信息),一個(gè)是引用域(儲(chǔ)存下一個(gè)節(jié)點(diǎn)或者上一個(gè)節(jié)點(diǎn)的地址),需要的朋友可以參考下2022-01-01
在Web項(xiàng)目中手機(jī)短信驗(yàn)證碼實(shí)現(xiàn)的全過程記錄
這篇文章主要給大家介紹了關(guān)于在Web項(xiàng)目中實(shí)現(xiàn)短信驗(yàn)證碼的全過程記錄,文中通過示例代碼介紹的非常詳細(xì),在文末跟大家提供了源碼下載,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12
Java中的notyfy()和notifyAll()的本質(zhì)區(qū)別
很多朋友對(duì)java中的notyfy()和notifyAll()的本質(zhì)區(qū)別不了解,今天小編抽空給大家整理一篇教程關(guān)于Java中的notyfy()和notifyAll()的本質(zhì)區(qū)別,需要的朋友參考下吧2017-02-02
mybatis-plus分頁查詢total=0問題及解決方案
這篇文章主要介紹了mybatis-plus分頁查詢total=0問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2026-03-03

