GH-331 - Avoid processing infrastructure beans in observability infrastructure.
We now skip infrastructure role beans during the processing of beans that could be subject to inter-module interaction observability. Previously, we could accidentally trigger a dependency cycle if the ModuleTracingBeanPostProcessor triggered the initial creation of AutoConfigurationPackages as that would then trigger the PostProcessor in turn which would try to lookup the ACP bean again to determine whether it should post process that to apply observability.
This commit is contained in:
@@ -27,8 +27,9 @@ import org.springframework.aop.support.ComposablePointcut;
|
|||||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||||
import org.springframework.aop.support.StaticMethodMatcher;
|
import org.springframework.aop.support.StaticMethodMatcher;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
import org.springframework.modulith.core.ApplicationModules;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.modulith.runtime.ApplicationModulesRuntime;
|
import org.springframework.modulith.runtime.ApplicationModulesRuntime;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
@@ -45,6 +46,7 @@ public class ModuleTracingBeanPostProcessor extends ModuleTracingSupport impleme
|
|||||||
private final ApplicationModulesRuntime runtime;
|
private final ApplicationModulesRuntime runtime;
|
||||||
private final Supplier<Tracer> tracer;
|
private final Supplier<Tracer> tracer;
|
||||||
private final Map<String, Advisor> advisors;
|
private final Map<String, Advisor> advisors;
|
||||||
|
private final ConfigurableListableBeanFactory factory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link ModuleTracingBeanPostProcessor} for the given {@link ApplicationModulesRuntime} and
|
* Creates a new {@link ModuleTracingBeanPostProcessor} for the given {@link ApplicationModulesRuntime} and
|
||||||
@@ -53,7 +55,8 @@ public class ModuleTracingBeanPostProcessor extends ModuleTracingSupport impleme
|
|||||||
* @param runtime must not be {@literal null}.
|
* @param runtime must not be {@literal null}.
|
||||||
* @param tracer must not be {@literal null}.
|
* @param tracer must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public ModuleTracingBeanPostProcessor(ApplicationModulesRuntime runtime, Supplier<Tracer> tracer) {
|
public ModuleTracingBeanPostProcessor(ApplicationModulesRuntime runtime, Supplier<Tracer> tracer,
|
||||||
|
ConfigurableListableBeanFactory factory) {
|
||||||
|
|
||||||
Assert.notNull(runtime, "ApplicationModulesRuntime must not be null!");
|
Assert.notNull(runtime, "ApplicationModulesRuntime must not be null!");
|
||||||
Assert.notNull(tracer, "Tracer must not be null!");
|
Assert.notNull(tracer, "Tracer must not be null!");
|
||||||
@@ -61,6 +64,7 @@ public class ModuleTracingBeanPostProcessor extends ModuleTracingSupport impleme
|
|||||||
this.runtime = runtime;
|
this.runtime = runtime;
|
||||||
this.tracer = tracer;
|
this.tracer = tracer;
|
||||||
this.advisors = new HashMap<>();
|
this.advisors = new HashMap<>();
|
||||||
|
this.factory = factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -70,13 +74,13 @@ public class ModuleTracingBeanPostProcessor extends ModuleTracingSupport impleme
|
|||||||
@Override
|
@Override
|
||||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||||
|
|
||||||
Class<?> type = runtime.getUserClass(bean, beanName);
|
var type = runtime.getUserClass(bean, beanName);
|
||||||
|
|
||||||
if (!runtime.isApplicationClass(type) || !type.isInstance(bean)) {
|
if (!type.isInstance(bean) || isInfrastructureBean(beanName) || !runtime.isApplicationClass(type)) {
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplicationModules modules = runtime.get();
|
var modules = runtime.get();
|
||||||
|
|
||||||
return modules.getModuleByType(type.getName())
|
return modules.getModuleByType(type.getName())
|
||||||
.map(DefaultObservedModule::new)
|
.map(DefaultObservedModule::new)
|
||||||
@@ -91,6 +95,12 @@ public class ModuleTracingBeanPostProcessor extends ModuleTracingSupport impleme
|
|||||||
}).orElse(bean);
|
}).orElse(bean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isInfrastructureBean(String beanName) {
|
||||||
|
|
||||||
|
return factory.containsBean(beanName) &&
|
||||||
|
factory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE;
|
||||||
|
}
|
||||||
|
|
||||||
private Advisor getOrBuildAdvisor(ObservedModule module, ObservedModuleType type) {
|
private Advisor getOrBuildAdvisor(ObservedModule module, ObservedModuleType type) {
|
||||||
|
|
||||||
return advisors.computeIfAbsent(module.getName(), __ -> {
|
return advisors.computeIfAbsent(module.getName(), __ -> {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import brave.propagation.TraceContext;
|
|||||||
import io.micrometer.tracing.Tracer;
|
import io.micrometer.tracing.Tracer;
|
||||||
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@@ -42,8 +43,8 @@ class ModuleObservabilityAutoConfiguration {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
static ModuleTracingBeanPostProcessor moduleTracingBeanPostProcessor(ApplicationModulesRuntime runtime,
|
static ModuleTracingBeanPostProcessor moduleTracingBeanPostProcessor(ApplicationModulesRuntime runtime,
|
||||||
ObjectProvider<Tracer> tracer) {
|
ObjectProvider<Tracer> tracer, ConfigurableListableBeanFactory factory) {
|
||||||
return new ModuleTracingBeanPostProcessor(runtime, () -> tracer.getObject());
|
return new ModuleTracingBeanPostProcessor(runtime, () -> tracer.getObject(), factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package org.springframework.modulith.runtime.autoconfigure;
|
package org.springframework.modulith.runtime.autoconfigure;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@@ -38,6 +39,7 @@ class SpringBootApplicationRuntime implements ApplicationRuntime {
|
|||||||
|
|
||||||
private final ApplicationContext context;
|
private final ApplicationContext context;
|
||||||
private Class<?> mainApplicationClass;
|
private Class<?> mainApplicationClass;
|
||||||
|
private List<String> resolvedAutoConfigurationPackages;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link SpringBootApplicationRuntime} for the given {@link ApplicationContext}.
|
* Creates a new {@link SpringBootApplicationRuntime} for the given {@link ApplicationContext}.
|
||||||
@@ -113,6 +115,15 @@ class SpringBootApplicationRuntime implements ApplicationRuntime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return fqn.startsWith(applicationClass.getPackage().getName())
|
return fqn.startsWith(applicationClass.getPackage().getName())
|
||||||
|| AutoConfigurationPackages.get(context).stream().anyMatch(pkg -> fqn.startsWith(pkg));
|
|| getAutoConfigurationPackages().stream().anyMatch(pkg -> fqn.startsWith(pkg));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getAutoConfigurationPackages() {
|
||||||
|
|
||||||
|
if (resolvedAutoConfigurationPackages == null) {
|
||||||
|
this.resolvedAutoConfigurationPackages = AutoConfigurationPackages.get(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvedAutoConfigurationPackages;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user