Переглянути джерело

Optimize Spring samples (#9249)

* Optimize spring-webflux

- Upgrade to Spring Boot 3.3.3
- Optimize handler implementations
- Optimize the router implementation
- Use WebFlux.fn configuration for HttpHandler

* Optimize spring

- Upgrade to Spring Boot 3.3.3
- Use WebMVC.fn instead of `@Controller`
- Refine configuration
Sébastien Deleuze 1 рік тому
батько
коміт
f834743318

+ 1 - 1
frameworks/Java/spring-webflux/pom.xml

@@ -13,7 +13,7 @@
     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
-        <version>3.3.1</version>
+        <version>3.3.3</version>
     </parent>
 
     <properties>

+ 17 - 0
frameworks/Java/spring-webflux/src/main/java/benchmark/App.java

@@ -1,13 +1,30 @@
 package benchmark;
 
+import benchmark.web.ServerFilter;
+
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.http.server.reactive.HttpHandler;
 import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.web.reactive.function.server.HandlerStrategies;
+import org.springframework.web.reactive.function.server.RouterFunction;
+import org.springframework.web.reactive.function.server.RouterFunctions;
+import org.springframework.web.reactive.function.server.ServerResponse;
+import org.springframework.web.reactive.result.view.ViewResolver;
+import org.springframework.web.server.WebHandler;
+import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
 
 @SpringBootApplication
 @EnableScheduling
 public class App  {
 
+    @Bean
+    public HttpHandler httpHandler(RouterFunction<ServerResponse> route, ServerFilter serverFilter, ViewResolver viewResolver) {
+        WebHandler webHandler = RouterFunctions.toWebHandler(route, HandlerStrategies.builder().viewResolver(viewResolver).build());
+        return WebHttpHandlerBuilder.webHandler(webHandler).filter(serverFilter).build();
+    }
+
     public static void main(String[] args) {
         SpringApplication.run(App.class, args);
     }

+ 7 - 25
frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxHandler.java → frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java

@@ -2,11 +2,9 @@ package benchmark.web;
 
 import java.util.Collections;
 import java.util.List;
-import java.util.Optional;
 import java.util.concurrent.ThreadLocalRandom;
 
 import benchmark.model.Fortune;
-import benchmark.model.Message;
 import benchmark.model.World;
 import benchmark.repository.DbRepository;
 import reactor.core.publisher.Flux;
@@ -21,26 +19,14 @@ import org.springframework.web.reactive.function.server.ServerResponse;
 import static java.util.Comparator.comparing;
 
 @Component
-public class WebfluxHandler {
+public class DbHandler {
 
     private final DbRepository dbRepository;
 
-    public WebfluxHandler(DbRepository dbRepository) {
+    public DbHandler(DbRepository dbRepository) {
         this.dbRepository = dbRepository;
     }
 
-    public Mono<ServerResponse> plaintext(ServerRequest request) {
-        return ServerResponse.ok()
-                .contentType(MediaType.TEXT_PLAIN)
-                .bodyValue("Hello, World!");
-    }
-
-    public Mono<ServerResponse> json(ServerRequest request) {
-        return ServerResponse.ok()
-                .contentType(MediaType.APPLICATION_JSON)
-                .bodyValue(new Message("Hello, World!"));
-    }
-
     public Mono<ServerResponse> db(ServerRequest request) {
         int id = randomWorldNumber();
         Mono<World> world = dbRepository.getWorld(id)
@@ -52,7 +38,7 @@ public class WebfluxHandler {
     }
 
     public Mono<ServerResponse> queries(ServerRequest request) {
-        int queries = getQueries(request);
+        int queries = parseQueryCount(request.queryParams().getFirst("queries"));
 
         Mono<List<World>> worlds = Flux.range(0, queries)
                 .flatMap(i -> dbRepository.getWorld(randomWorldNumber()))
@@ -64,13 +50,13 @@ public class WebfluxHandler {
                 });
     }
 
-    private static int parseQueryCount(Optional<String> maybeTextValue) {
-        if (!maybeTextValue.isPresent()) {
+    private static int parseQueryCount(String maybeTextValue) {
+        if (maybeTextValue == null) {
             return 1;
         }
         int parsedValue;
         try {
-            parsedValue = Integer.parseInt(maybeTextValue.get());
+            parsedValue = Integer.parseInt(maybeTextValue);
         } catch (NumberFormatException e) {
             return 1;
         }
@@ -78,7 +64,7 @@ public class WebfluxHandler {
     }
 
     public Mono<ServerResponse> updates(ServerRequest request) {
-        int queries = getQueries(request);
+        int queries = parseQueryCount(request.queryParams().getFirst("queries"));
 
         Mono<List<World>> worlds = Flux.range(0, queries)
                 .flatMap(i -> dbRepository.findAndUpdateWorld(randomWorldNumber(), randomWorldNumber()))
@@ -101,10 +87,6 @@ public class WebfluxHandler {
                 .render("fortunes", Collections.singletonMap("fortunes", result));
     }
 
-    private static int getQueries(ServerRequest request) {
-        return parseQueryCount(request.queryParam("queries"));
-    }
-
     private static int randomWorldNumber() {
         return 1 + ThreadLocalRandom.current().nextInt(10000);
     }

+ 54 - 0
frameworks/Java/spring-webflux/src/main/java/benchmark/web/JsonHandler.java

@@ -0,0 +1,54 @@
+package benchmark.web;
+
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+import reactor.core.publisher.Mono;
+
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.core.io.buffer.DataBufferFactory;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+import org.springframework.web.reactive.function.server.HandlerFunction;
+import org.springframework.web.reactive.function.server.ServerRequest;
+import org.springframework.web.reactive.function.server.ServerResponse;
+
+@Component
+public class JsonHandler implements HandlerFunction<ServerResponse> {
+
+	private final ObjectWriter writer;
+
+	public JsonHandler(ObjectMapper objectMapper) {
+		this.writer = objectMapper.writerFor(Map.class);
+	}
+
+	@Override
+	public Mono<ServerResponse> handle(ServerRequest request) {
+		return ServerResponse.ok()
+				.body((message, context) -> {
+					DataBuffer buffer = serialize(request, Map.of("message", "Hello, world!"));
+					HttpHeaders headers = message.getHeaders();
+					headers.setContentLength(buffer.readableByteCount());
+					headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
+					return message.writeWith(Mono.just(buffer));
+				});
+	}
+
+	private DataBuffer serialize(ServerRequest request, Object object) {
+		try {
+			byte[] bytes = this.writer.writeValueAsBytes(object);
+			return bufferFactory(request).wrap(bytes);
+		}
+		catch (JsonProcessingException ex) {
+			throw new RuntimeException(ex);
+		}
+	}
+
+	private static DataBufferFactory bufferFactory(ServerRequest request) {
+		return request.exchange().getResponse().bufferFactory();
+	}
+
+}

+ 2 - 3
frameworks/Java/spring-webflux/src/main/java/benchmark/ServerFilter.java → frameworks/Java/spring-webflux/src/main/java/benchmark/web/ServerFilter.java

@@ -1,6 +1,5 @@
 package benchmark.web;
 
-import io.netty.handler.codec.http.HttpHeaderNames;
 import org.springframework.http.HttpHeaders;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
@@ -28,8 +27,8 @@ public class ServerFilter implements WebFilter {
     @Override
     public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
         HttpHeaders headers = exchange.getResponse().getHeaders();
-        headers.add(HttpHeaderNames.SERVER.toString(), SERVER_NAME);
-        headers.add(HttpHeaderNames.DATE.toString(), this.date);
+        headers.add(HttpHeaders.SERVER, SERVER_NAME);
+        headers.add(HttpHeaders.DATE, this.date);
         return chain.filter(exchange);
     }
 }

+ 37 - 0
frameworks/Java/spring-webflux/src/main/java/benchmark/web/TextHandler.java

@@ -0,0 +1,37 @@
+package benchmark.web;
+
+import java.nio.charset.StandardCharsets;
+
+import reactor.core.publisher.Mono;
+
+import org.springframework.core.io.buffer.DataBufferFactory;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+import org.springframework.web.reactive.function.server.HandlerFunction;
+import org.springframework.web.reactive.function.server.ServerRequest;
+import org.springframework.web.reactive.function.server.ServerResponse;
+
+@Component
+public class TextHandler implements HandlerFunction<ServerResponse> {
+
+	private static final byte[] TEXT_BODY = "Hello, World!".getBytes(StandardCharsets.UTF_8);
+
+	private static final String TEXT_BODY_LENGTH = String.valueOf(TEXT_BODY.length);
+
+	@Override
+	public Mono<ServerResponse> handle(ServerRequest request) {
+		return ServerResponse.ok()
+				.body((message, context) -> {
+					HttpHeaders headers = message.getHeaders();
+					headers.add(HttpHeaders.CONTENT_LENGTH, TEXT_BODY_LENGTH);
+					headers.add(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE);
+					return message.writeWith(Mono.just(bufferFactory(request).wrap(TEXT_BODY)));
+				});
+	}
+
+	private static DataBufferFactory bufferFactory(ServerRequest request) {
+		return request.exchange().getResponse().bufferFactory();
+	}
+
+}

+ 19 - 10
frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java

@@ -1,23 +1,32 @@
 package benchmark.web;
 
+import reactor.core.publisher.Mono;
+
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.web.reactive.function.server.HandlerFunction;
 import org.springframework.web.reactive.function.server.RouterFunction;
-import org.springframework.web.reactive.function.server.RouterFunctions;
 import org.springframework.web.reactive.function.server.ServerResponse;
 
 @Configuration
 public class WebfluxRouter {
 
     @Bean
-    public RouterFunction<ServerResponse> route(WebfluxHandler handler) {
-        return RouterFunctions.route()
-                .GET("/plaintext", handler::plaintext)
-                .GET("/json", handler::json)
-                .GET("/db", handler::db)
-                .GET("/queries", handler::queries)
-                .GET("/updates", handler::updates)
-                .GET("/fortunes", handler::fortunes)
-                .build();
+    public RouterFunction<ServerResponse> route(
+            TextHandler textHandler, JsonHandler jsonHandler, DbHandler dbHandler) {
+
+        return request -> {
+            HandlerFunction<ServerResponse> fn = switch (request.uri().getRawPath()) {
+                case "/plaintext" -> textHandler;
+                case "/json" -> jsonHandler;
+                case "/db" -> dbHandler::db;
+                case "/queries" -> dbHandler::queries;
+                case "/updates" -> dbHandler::updates;
+                case "/fortunes" -> dbHandler::fortunes;
+                default -> r -> ServerResponse.notFound().build();
+            };
+            return Mono.just(fn);
+        };
     }
+
 }

+ 1 - 1
frameworks/Java/spring/pom.xml

@@ -11,7 +11,7 @@
 	<parent>
 		<groupId>org.springframework.boot</groupId>
 		<artifactId>spring-boot-starter-parent</artifactId>
-		<version>3.3.1</version>
+		<version>3.3.3</version>
 	</parent>
 
 	<properties>

+ 1 - 1
frameworks/Java/spring/spring.dockerfile

@@ -12,4 +12,4 @@ RUN java -Djarmode=tools -jar app.jar extract
 
 EXPOSE 8080
 
-CMD ["java", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app/app.jar", "--spring.profiles.active=jpa"]
+CMD ["java", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app/app.jar", "--spring.profiles.active=jdbc"]

+ 1 - 2
frameworks/Java/spring/src/main/java/hello/App.java

@@ -4,8 +4,6 @@ import javax.sql.DataSource;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration;
-import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
 import org.springframework.boot.context.event.ApplicationReadyEvent;
 import org.springframework.context.annotation.Bean;
@@ -35,4 +33,5 @@ public class App {
 
 		return dataSource;
 	}
+
 }

+ 3 - 2
frameworks/Java/spring/src/main/java/hello/UpdateWorldServiceImpl.java

@@ -3,7 +3,8 @@ package hello;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import hello.controller.HelloController;
+import hello.web.DbHandler;
+import hello.web.WebmvcRouter;
 import hello.model.World;
 import hello.repository.DbRepository;
 
@@ -33,7 +34,7 @@ public class UpdateWorldServiceImpl implements UpdateWorldService {
 
 		int newRandomNumber;
 		do {
-			newRandomNumber = HelloController.randomWorldNumber();
+			newRandomNumber = DbHandler.randomWorldNumber();
 		} while (newRandomNumber == world.randomnumber);
 
 		return dbRepository.updateWorld(world, newRandomNumber);

+ 36 - 47
frameworks/Java/spring/src/main/java/hello/controller/HelloController.java → frameworks/Java/spring/src/main/java/hello/web/DbHandler.java

@@ -1,79 +1,68 @@
-package hello.controller;
+package hello.web;
 
-import static java.util.Comparator.comparing;
-
-import java.util.List;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.stream.IntStream;
 
-import hello.model.Message;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.ModelAttribute;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
 import hello.UpdateWorldService;
 import hello.model.Fortune;
 import hello.model.World;
 import hello.repository.DbRepository;
 
-@RestController
-public final class HelloController {
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.function.RenderingResponse;
+import org.springframework.web.servlet.function.ServerRequest;
+import org.springframework.web.servlet.function.ServerResponse;
+
+import static java.util.Comparator.comparing;
+
+@Component
+public class DbHandler {
 
 	private DbRepository dbRepository;
 	private UpdateWorldService updateWorldService;
 
-	public HelloController(
-			DbRepository dbRepository,
-			UpdateWorldService updateWorldService) {
+	public DbHandler(DbRepository dbRepository, UpdateWorldService updateWorldService) {
 		this.dbRepository = dbRepository;
 		this.updateWorldService = updateWorldService;
 	}
 
-	@GetMapping("/plaintext")
-	String plaintext(HttpServletResponse response) {
-		response.setContentType(MediaType.TEXT_PLAIN_VALUE);
-		return "Hello, World!";
-	}
-
-	@GetMapping("/json")
-	Message json(HttpServletResponse response) {
-		response.setContentType(MediaType.APPLICATION_JSON_VALUE);
-		return new Message("Hello, World!");
+	ServerResponse db(ServerRequest request) {
+		return ServerResponse.ok()
+				.contentType(MediaType.APPLICATION_JSON)
+				.body(dbRepository.getWorld(randomWorldNumber()));
 	}
 
-	@GetMapping("/db")
-	World db(HttpServletResponse response) {
-		response.setContentType(MediaType.APPLICATION_JSON_VALUE);
-		return dbRepository.getWorld(randomWorldNumber());
-	}
-
-	@GetMapping("/queries")
-	World[] queries(HttpServletResponse response, @RequestParam(required = false) String queries) {
-		response.setContentType(MediaType.APPLICATION_JSON_VALUE);
-		return randomWorldNumbers().mapToObj(dbRepository::getWorld).limit(parseQueryCount(queries))
+	ServerResponse queries(ServerRequest request) {
+		String queries = request.params().getFirst("queries");
+		World[] worlds = randomWorldNumbers()
+				.mapToObj(dbRepository::getWorld).limit(parseQueryCount(queries))
 				.toArray(World[]::new);
+		return ServerResponse.ok()
+				.contentType(MediaType.APPLICATION_JSON)
+				.body(worlds);
 	}
 
-	@GetMapping("/updates")
-	World[] updates(HttpServletResponse response, @RequestParam(required = false) String queries) {
-		response.setContentType(MediaType.APPLICATION_JSON_VALUE);
-		return randomWorldNumbers()
+	ServerResponse updates(ServerRequest request) {
+		String queries = request.params().getFirst("queries");
+		World[] worlds = randomWorldNumbers()
 				.mapToObj(id -> updateWorldService.updateWorld(id))
 				.limit(parseQueryCount(queries)).toArray(World[]::new);
+		return ServerResponse.ok()
+				.contentType(MediaType.APPLICATION_JSON)
+				.body(worlds);
 	}
 
-	@GetMapping("/fortunes")
-	@ModelAttribute("fortunes")
-	List<Fortune> fortunes(HttpServletResponse response) {
-		response.setContentType(MediaType.TEXT_HTML_VALUE);
+	ServerResponse fortunes(ServerRequest request) {
 		var fortunes = dbRepository.fortunes();
-
 		fortunes.add(new Fortune(0, "Additional fortune added at request time."));
 		fortunes.sort(comparing(fortune -> fortune.message));
-		return fortunes;
+		return RenderingResponse
+				.create("fortunes")
+				.modelAttribute("fortunes", fortunes)
+				.header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_HTML_VALUE)
+				.build();
 	}
 
 	private static final int MIN_WORLD_NUMBER = 1;

+ 39 - 0
frameworks/Java/spring/src/main/java/hello/web/JsonHandler.java

@@ -0,0 +1,39 @@
+package hello.web;
+
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.function.HandlerFunction;
+import org.springframework.web.servlet.function.ServerRequest;
+import org.springframework.web.servlet.function.ServerResponse;
+
+@Component
+public class JsonHandler implements HandlerFunction<ServerResponse> {
+
+	private final ObjectWriter writer;
+
+	public JsonHandler(ObjectMapper objectMapper) {
+		this.writer = objectMapper.writerFor(Map.class);
+	}
+
+	@Override
+	public ServerResponse handle(ServerRequest request) {
+		try {
+			byte[] body = this.writer.writeValueAsBytes(Map.of("message", "Hello, world!"));
+			return ServerResponse.ok()
+					.contentLength(body.length)
+					.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
+					.body(body);
+		}
+		catch (JsonProcessingException ex) {
+			throw new RuntimeException(ex);
+		}
+	}
+
+}

+ 27 - 0
frameworks/Java/spring/src/main/java/hello/web/TextHandler.java

@@ -0,0 +1,27 @@
+package hello.web;
+
+import java.nio.charset.StandardCharsets;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.function.HandlerFunction;
+import org.springframework.web.servlet.function.ServerRequest;
+import org.springframework.web.servlet.function.ServerResponse;
+
+@Component
+public class TextHandler implements HandlerFunction<ServerResponse> {
+
+	private static final byte[] TEXT_BODY = "Hello, World!".getBytes(StandardCharsets.UTF_8);
+
+	private static final String TEXT_BODY_LENGTH = String.valueOf(TEXT_BODY.length);
+
+	@Override
+	public ServerResponse handle(ServerRequest request) {
+		return ServerResponse.ok()
+				.header(HttpHeaders.CONTENT_LENGTH, TEXT_BODY_LENGTH)
+				.header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE)
+				.body(TEXT_BODY);
+	}
+
+}

+ 32 - 0
frameworks/Java/spring/src/main/java/hello/web/WebmvcRouter.java

@@ -0,0 +1,32 @@
+package hello.web;
+
+import java.util.Optional;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.function.HandlerFunction;
+import org.springframework.web.servlet.function.RouterFunction;
+import org.springframework.web.servlet.function.ServerResponse;
+
+@Configuration
+public class WebmvcRouter {
+
+	@Bean
+	public RouterFunction<ServerResponse> route(
+			TextHandler textHandler,
+			JsonHandler jsonHandler,
+			DbHandler dbHandler) {
+
+		return request -> Optional.of((HandlerFunction<ServerResponse>) r ->
+				switch (r.uri().getRawPath()) {
+					case "/plaintext" -> textHandler.handle(r);
+					case "/json" -> jsonHandler.handle(r);
+					case "/db" -> dbHandler.db(r);
+					case "/queries" -> dbHandler.queries(r);
+					case "/updates" -> dbHandler.updates(r);
+					case "/fortunes" -> dbHandler.fortunes(r);
+					default -> ServerResponse.notFound().build();
+				});
+	}
+}
+

+ 4 - 5
frameworks/Java/spring/src/main/resources/application.yml

@@ -1,12 +1,10 @@
 ---
 spring:
-  jpa:
-    open-in-view: false
   config:
     activate:
       on-profile: jdbc
   autoconfigure:
-    exclude: org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration
+    exclude: org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration
 
 ---
 spring:
@@ -31,7 +29,7 @@ spring:
     activate:
       on-profile: jpa
   autoconfigure:
-    exclude: org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration
+    exclude: org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration
   jpa:
     database-platform: org.hibernate.dialect.PostgreSQLDialect
 
@@ -41,7 +39,7 @@ spring:
     activate:
       on-profile: mongo
   autoconfigure:
-    exclude: org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
+    exclude: org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration
 
 spring.data.mongodb:
   host: tfb-database
@@ -55,3 +53,4 @@ spring:
 
 server.server-header: Spring
 server.servlet.encoding.force: true
+spring.jpa.open-in-view: false