From bee5e0b1635dff4f0331b1e90a37c1e8c477d87a Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Thu, 25 Apr 2024 16:14:35 +0200 Subject: [PATCH] GH-1138 Fix serverless web container initialization Resolves #1138 --- .../pom.xml | 25 ++++++++++------- .../web/ServerlessAutoConfiguration.java | 27 +++++++++---------- .../serverless/web/ServerlessMVC.java | 7 +++-- .../serverless/web/RequestResponseTests.java | 8 ++++++ .../test/app/PetStoreSpringAppConfig.java | 2 +- .../src/test/resources/templates/index.ftlh | 5 ++++ 6 files changed, 46 insertions(+), 28 deletions(-) create mode 100644 spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/resources/templates/index.ftlh diff --git a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/pom.xml b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/pom.xml index 82b4bf1f9..b4c7f35c1 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/pom.xml +++ b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/pom.xml @@ -21,7 +21,7 @@ org.springframework spring-webmvc - + org.springframework.boot @@ -34,26 +34,31 @@ test - + - jakarta.servlet - jakarta.servlet-api - provided + jakarta.servlet + jakarta.servlet-api + provided org.springframework.boot spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-freemarker + test + org.springframework.boot spring-boot-starter-web - - org.springframework.boot - spring-boot-starter-tomcat - - + + org.springframework.boot + spring-boot-starter-tomcat + + test diff --git a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ServerlessAutoConfiguration.java b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ServerlessAutoConfiguration.java index 65e78a756..88e83d6bb 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ServerlessAutoConfiguration.java +++ b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ServerlessAutoConfiguration.java @@ -22,7 +22,6 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; 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.server.WebServer; import org.springframework.boot.web.server.WebServerException; @@ -67,16 +66,6 @@ public class ServerlessAutoConfiguration { @Override 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 @@ -97,10 +86,18 @@ public class ServerlessAutoConfiguration { logger.info("Configuring Serverless Web Container"); ServerlessServletContext servletContext = new ServerlessServletContext(); servletApplicationContet.setServletContext(servletContext); - for (ServletContextInitializer beans : new ServletContextInitializerBeans(this.applicationContext)) { - if (!(beans instanceof DispatcherServletRegistrationBean)) { - beans.onStartup(servletContext); - } + DispatcherServlet dispatcher = applicationContext.getBean(DispatcherServlet.class); + try { + 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); } } } diff --git a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ServerlessMVC.java b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ServerlessMVC.java index 853617a63..486794734 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ServerlessMVC.java +++ b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/main/java/org/springframework/cloud/function/serverless/web/ServerlessMVC.java @@ -29,6 +29,7 @@ import java.util.stream.Stream; import jakarta.servlet.AsyncContext; +import jakarta.servlet.DispatcherType; import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; import jakarta.servlet.FilterConfig; @@ -156,8 +157,6 @@ public final class ServerlessMVC { * @see org.springframework.test.web.servlet.result.MockMvcResultMatchers */ 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. " + "If you need to increase it, please set " + INIT_TIMEOUT + " environment variable"); this.service(request, response, (CountDownLatch) null); @@ -269,6 +268,10 @@ public final class ServerlessMVC { this.request = request; this.response = response; + + if (!response.isCommitted() && request.getDispatcherType() != DispatcherType.ASYNC) { + response.flushBuffer(); + } } /** diff --git a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/java/org/springframework/cloud/function/serverless/web/RequestResponseTests.java b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/java/org/springframework/cloud/function/serverless/web/RequestResponseTests.java index c0351cac1..1cbf27cc7 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/java/org/springframework/cloud/function/serverless/web/RequestResponseTests.java +++ b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/java/org/springframework/cloud/function/serverless/web/RequestResponseTests.java @@ -57,6 +57,14 @@ public class RequestResponseTests { 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("

hello from freemarker

"); + } + @Test public void validateAccessDeniedWithCustomHandler() throws Exception { HttpServletRequest request = new ServerlessHttpServletRequest(null, "GET", "/foo/deny"); diff --git a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/java/org/springframework/cloud/function/test/app/PetStoreSpringAppConfig.java b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/java/org/springframework/cloud/function/test/app/PetStoreSpringAppConfig.java index 8a5bdfbdf..2cd6d734b 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/java/org/springframework/cloud/function/test/app/PetStoreSpringAppConfig.java +++ b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/java/org/springframework/cloud/function/test/app/PetStoreSpringAppConfig.java @@ -53,7 +53,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl @Configuration -@Import({ PetsController.class }) +@Import({ PetsController.class, FreemarkerController.class }) @EnableWebSecurity @EnableAutoConfiguration public class PetStoreSpringAppConfig { diff --git a/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/resources/templates/index.ftlh b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/resources/templates/index.ftlh new file mode 100644 index 000000000..3631fde40 --- /dev/null +++ b/spring-cloud-function-adapters/spring-cloud-function-serverless-web/src/test/resources/templates/index.ftlh @@ -0,0 +1,5 @@ +

hello from freemarker

+ +<#list 1..10 as x> + ${x} + \ No newline at end of file