GH-1138 Fix serverless web container initialization

Resolves #1138
This commit is contained in:
Oleg Zhurakousky
2024-04-25 16:14:35 +02:00
parent d38ab942bd
commit bee5e0b163
6 changed files with 46 additions and 28 deletions

View File

@@ -21,7 +21,7 @@
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId> <artifactId>spring-webmvc</artifactId>
</dependency> </dependency>
<!-- --> <!-- -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@@ -34,26 +34,31 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- --> <!-- -->
<dependency> <dependency>
<groupId>jakarta.servlet</groupId> <groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId> <artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId> <artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion> </exclusion>
</exclusions> </exclusions>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -22,7 +22,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.web.context.ConfigurableWebServerApplicationContext; import org.springframework.boot.web.context.ConfigurableWebServerApplicationContext;
import org.springframework.boot.web.server.WebServer; import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.WebServerException; import org.springframework.boot.web.server.WebServerException;
@@ -67,16 +66,6 @@ public class ServerlessAutoConfiguration {
@Override @Override
public void start() throws WebServerException { public void start() throws WebServerException {
if (applicationContext instanceof ServletWebServerApplicationContext servletApplicationContet) {
DispatcherServlet dispatcher = applicationContext.getBean(DispatcherServlet.class);
try {
dispatcher.init(new ProxyServletConfig(servletApplicationContet.getServletContext()));
logger.info("Initalized DispatcherServlet");
}
catch (Exception e) {
throw new IllegalStateException("Faild to create Spring MVC DispatcherServlet proxy", e);
}
}
} }
@Override @Override
@@ -97,10 +86,18 @@ public class ServerlessAutoConfiguration {
logger.info("Configuring Serverless Web Container"); logger.info("Configuring Serverless Web Container");
ServerlessServletContext servletContext = new ServerlessServletContext(); ServerlessServletContext servletContext = new ServerlessServletContext();
servletApplicationContet.setServletContext(servletContext); servletApplicationContet.setServletContext(servletContext);
for (ServletContextInitializer beans : new ServletContextInitializerBeans(this.applicationContext)) { DispatcherServlet dispatcher = applicationContext.getBean(DispatcherServlet.class);
if (!(beans instanceof DispatcherServletRegistrationBean)) { try {
beans.onStartup(servletContext); logger.info("Initializing DispatcherServlet");
} dispatcher.init(new ProxyServletConfig(servletApplicationContet.getServletContext()));
logger.info("Initalized DispatcherServlet");
}
catch (Exception e) {
throw new IllegalStateException("Faild to create Spring MVC DispatcherServlet proxy", e);
}
for (ServletContextInitializer initializer : new ServletContextInitializerBeans(this.applicationContext)) {
System.out.println("==> INITIALIZING " + initializer);
initializer.onStartup(servletContext);
} }
} }
} }

View File

@@ -29,6 +29,7 @@ import java.util.stream.Stream;
import jakarta.servlet.AsyncContext; import jakarta.servlet.AsyncContext;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.Filter; import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain; import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig; import jakarta.servlet.FilterConfig;
@@ -156,8 +157,6 @@ public final class ServerlessMVC {
* @see org.springframework.test.web.servlet.result.MockMvcResultMatchers * @see org.springframework.test.web.servlet.result.MockMvcResultMatchers
*/ */
public void service(HttpServletRequest request, HttpServletResponse response) throws Exception { public void service(HttpServletRequest request, HttpServletResponse response) throws Exception {
//this.waitForContext();
//contextStartupLatch.await(this.initializatioinTimeout, TimeUnit.MILLISECONDS);
Assert.state(this.waitForContext(), "Failed to initialize Application within the specified time of " + this.initializatioinTimeout + " milliseconds. " Assert.state(this.waitForContext(), "Failed to initialize Application within the specified time of " + this.initializatioinTimeout + " milliseconds. "
+ "If you need to increase it, please set " + INIT_TIMEOUT + " environment variable"); + "If you need to increase it, please set " + INIT_TIMEOUT + " environment variable");
this.service(request, response, (CountDownLatch) null); this.service(request, response, (CountDownLatch) null);
@@ -269,6 +268,10 @@ public final class ServerlessMVC {
this.request = request; this.request = request;
this.response = response; this.response = response;
if (!response.isCommitted() && request.getDispatcherType() != DispatcherType.ASYNC) {
response.flushBuffer();
}
} }
/** /**

View File

@@ -57,6 +57,14 @@ public class RequestResponseTests {
this.mvc.stop(); this.mvc.stop();
} }
@Test
public void validateFreemarker() throws Exception {
HttpServletRequest request = new ServerlessHttpServletRequest(null, "GET", "/index");
ServerlessHttpServletResponse response = new ServerlessHttpServletResponse();
mvc.service(request, response);
assertThat(response.getContentAsString()).contains("<h1> hello from freemarker </h1>");
}
@Test @Test
public void validateAccessDeniedWithCustomHandler() throws Exception { public void validateAccessDeniedWithCustomHandler() throws Exception {
HttpServletRequest request = new ServerlessHttpServletRequest(null, "GET", "/foo/deny"); HttpServletRequest request = new ServerlessHttpServletRequest(null, "GET", "/foo/deny");

View File

@@ -53,7 +53,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
@Configuration @Configuration
@Import({ PetsController.class }) @Import({ PetsController.class, FreemarkerController.class })
@EnableWebSecurity @EnableWebSecurity
@EnableAutoConfiguration @EnableAutoConfiguration
public class PetStoreSpringAppConfig { public class PetStoreSpringAppConfig {

View File

@@ -0,0 +1,5 @@
<h1> hello from freemarker </h1>
<#list 1..10 as x>
${x}
</#list>