diff --git a/multi-ctx-app-builder/pom.xml b/multi-ctx-app-builder/pom.xml
index ed5bd5d..043f5b5 100644
--- a/multi-ctx-app-builder/pom.xml
+++ b/multi-ctx-app-builder/pom.xml
@@ -6,7 +6,7 @@
com.alex.demo.ctx
multi-ctx-app
- 1.3.1
+ 1.3.2
multi-ctx-app-builder
diff --git a/multi-ctx-app-embed/README.md b/multi-ctx-app-embed/README.md
index aaef1f0..d815b01 100644
--- a/multi-ctx-app-embed/README.md
+++ b/multi-ctx-app-embed/README.md
@@ -18,8 +18,8 @@ public AnnotationConfigServletWebServerApplicationContext createChildContext(App
```
It's exposed on port 8082 while actuator is exposed on port 8081.
-Most of the logic used for child context creation is taken from: `org.springframework.boot.actuate.autoconfigure.web.servlet.WebMvcEndpointChildContextConfiguration`.
-So, child and actuator contexts are very similar.
+Most of the logic used for child context creation is taken from: `org.springframework.boot.actuate.autoconfigure.web.server.ChildManagementContextInitializer` and `org.springframework.boot.actuate.autoconfigure.web.ManagementContextFactory`.
+So, child and actuator contexts are very similar in case child context is child of parent context.
This demo application provides two options:
* child context is standalone (not child of parent web context). This is default.
diff --git a/multi-ctx-app-embed/pom.xml b/multi-ctx-app-embed/pom.xml
index 7efdd4a..987cae8 100644
--- a/multi-ctx-app-embed/pom.xml
+++ b/multi-ctx-app-embed/pom.xml
@@ -6,7 +6,7 @@
com.alex.demo.ctx
multi-ctx-app
- 1.3.1
+ 1.3.2
multi-ctx-app-embed
diff --git a/multi-ctx-app-embed/src/main/java/com/alex/demo/ctx/child/ChildCtxConfig.java b/multi-ctx-app-embed/src/main/java/com/alex/demo/ctx/child/ChildCtxConfig.java
index 57d3fbf..3ae7eae 100644
--- a/multi-ctx-app-embed/src/main/java/com/alex/demo/ctx/child/ChildCtxConfig.java
+++ b/multi-ctx-app-embed/src/main/java/com/alex/demo/ctx/child/ChildCtxConfig.java
@@ -2,13 +2,11 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
import java.util.Optional;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-
+import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
+import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -47,6 +45,9 @@
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
/**
* @see org.springframework.boot.actuate.autoconfigure.web.servlet.WebMvcEndpointChildContextConfiguration
*/
@@ -211,12 +212,9 @@ public ModelAndView handle(HttpServletRequest request, HttpServletResponse respo
return null;
}
- /**
- * @deprecated
- */
- @SuppressWarnings("deprecation")
@Override
- @Deprecated
+ @Deprecated(since = "2.4.9", forRemoval = false)
+ @SuppressWarnings("deprecation")
public long getLastModified(HttpServletRequest request, Object handler) {
Optional adapter = getAdapter(handler);
return adapter.map((handlerAdapter) -> handlerAdapter.getLastModified(request, handler)).orElse(0L);
@@ -245,28 +243,43 @@ class CompositeHandlerExceptionResolver implements HandlerExceptionResolver {
@Autowired
private ListableBeanFactory beanFactory;
- private List resolvers;
+ private volatile List resolvers;
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
- if (this.resolvers == null) {
- this.resolvers = extractResolvers();
+ for (HandlerExceptionResolver resolver : getResolvers()) {
+ ModelAndView resolved = resolver.resolveException(request, response, handler, ex);
+ if (resolved != null) {
+ return resolved;
+ }
}
- return this.resolvers.stream().map((resolver) -> resolver.resolveException(request, response, handler, ex))
- .filter(Objects::nonNull).findFirst().orElse(null);
+ return null;
}
- private List extractResolvers() {
- List list = new ArrayList<>(
- this.beanFactory.getBeansOfType(HandlerExceptionResolver.class).values());
- list.remove(this);
- AnnotationAwareOrderComparator.sort(list);
- if (list.isEmpty()) {
- list.add(new DefaultErrorAttributes());
- list.add(new DefaultHandlerExceptionResolver());
+ private List getResolvers() {
+ List resolvers = this.resolvers;
+ if (resolvers == null) {
+ resolvers = new ArrayList<>();
+ collectResolverBeans(resolvers, this.beanFactory);
+ resolvers.remove(this);
+ AnnotationAwareOrderComparator.sort(resolvers);
+ if (resolvers.isEmpty()) {
+ resolvers.add(new DefaultErrorAttributes());
+ resolvers.add(new DefaultHandlerExceptionResolver());
+ }
+ this.resolvers = resolvers;
+ }
+ return resolvers;
+ }
+
+ private void collectResolverBeans(List resolvers, BeanFactory beanFactory) {
+ if (beanFactory instanceof ListableBeanFactory listableBeanFactory) {
+ resolvers.addAll(listableBeanFactory.getBeansOfType(HandlerExceptionResolver.class).values());
+ }
+ if (beanFactory instanceof HierarchicalBeanFactory hierarchicalBeanFactory) {
+ collectResolverBeans(resolvers, hierarchicalBeanFactory.getParentBeanFactory());
}
- return list;
}
}
}
diff --git a/multi-ctx-app-servlets/pom.xml b/multi-ctx-app-servlets/pom.xml
index 6938c76..b71c71c 100644
--- a/multi-ctx-app-servlets/pom.xml
+++ b/multi-ctx-app-servlets/pom.xml
@@ -6,7 +6,7 @@
com.alex.demo.ctx
multi-ctx-app
- 1.3.1
+ 1.3.2
multi-ctx-app-servlets
diff --git a/pom.xml b/pom.xml
index b27816f..4e78243 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,13 +6,13 @@
org.springframework.boot
spring-boot-starter-parent
- 3.1.5
+ 3.2.0
com.alex.demo.ctx
multi-ctx-app
- 1.3.1
+ 1.3.2
pom
Multi Context App