Skip to content

Commit 4686691

Browse files
Fix some dependency issues with NonRootBeanPostProcessor (#2556)
Fix some dependency issues with NonRootBeanPostProcessor
1 parent 231c724 commit 4686691

File tree

5 files changed

+84
-29
lines changed

5 files changed

+84
-29
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package io.temporal.spring.boot.autoconfigure;
2+
3+
import io.temporal.spring.boot.autoconfigure.properties.NonRootNamespaceProperties;
4+
import java.util.List;
5+
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
6+
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
7+
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
8+
import org.springframework.boot.context.properties.bind.BindResult;
9+
import org.springframework.boot.context.properties.bind.Bindable;
10+
import org.springframework.boot.context.properties.bind.Binder;
11+
import org.springframework.context.annotation.ConditionContext;
12+
import org.springframework.core.type.AnnotatedTypeMetadata;
13+
14+
/**
15+
* Condition that checks if the "spring.temporal.namespaces" property is present in the application
16+
* context.
17+
*/
18+
class NamespacesPresentCondition extends SpringBootCondition {
19+
private static final Bindable<List<NonRootNamespaceProperties>> NAMESPACES_LIST =
20+
Bindable.listOf(NonRootNamespaceProperties.class);
21+
private static final String NAMESPACES_KEY = "spring.temporal.namespaces";
22+
23+
@Override
24+
public ConditionOutcome getMatchOutcome(
25+
ConditionContext context, AnnotatedTypeMetadata metadata) {
26+
BindResult<?> namespacesProperty =
27+
Binder.get(context.getEnvironment()).bind(NAMESPACES_KEY, NAMESPACES_LIST);
28+
ConditionMessage.Builder messageBuilder = ConditionMessage.forCondition("Present namespaces");
29+
if (namespacesProperty.isBound()) {
30+
return ConditionOutcome.match(messageBuilder.found("property").items(NAMESPACES_KEY));
31+
}
32+
return ConditionOutcome.noMatch(messageBuilder.didNotFind("property").items(NAMESPACES_KEY));
33+
}
34+
}

temporal-spring-boot-autoconfigure/src/main/java/io/temporal/spring/boot/autoconfigure/NonRootBeanPostProcessor.java

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.springframework.beans.BeansException;
3434
import org.springframework.beans.factory.BeanFactory;
3535
import org.springframework.beans.factory.BeanFactoryAware;
36+
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
3637
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
3738
import org.springframework.beans.factory.config.BeanPostProcessor;
3839
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@@ -45,26 +46,32 @@ public class NonRootBeanPostProcessor implements BeanPostProcessor, BeanFactoryA
4546

4647
private final @Nonnull TemporalProperties temporalProperties;
4748
private final @Nullable List<NonRootNamespaceProperties> namespaceProperties;
48-
private final @Nullable Tracer tracer;
49-
private final @Nullable TestWorkflowEnvironmentAdapter testWorkflowEnvironment;
50-
private final @Nullable Scope metricsScope;
51-
52-
public NonRootBeanPostProcessor(
53-
@Nonnull TemporalProperties temporalProperties,
54-
@Nullable Tracer tracer,
55-
@Nullable TestWorkflowEnvironmentAdapter testWorkflowEnvironment,
56-
@Nullable Scope metricsScope) {
49+
private @Nullable Tracer tracer;
50+
private @Nullable TestWorkflowEnvironmentAdapter testWorkflowEnvironment;
51+
private @Nullable Scope metricsScope;
52+
53+
public NonRootBeanPostProcessor(@Nonnull TemporalProperties temporalProperties) {
5754
this.temporalProperties = temporalProperties;
5855
this.namespaceProperties = temporalProperties.getNamespaces();
59-
this.tracer = tracer;
60-
this.testWorkflowEnvironment = testWorkflowEnvironment;
61-
this.metricsScope = metricsScope;
6256
}
6357

6458
@Override
65-
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
59+
public Object postProcessAfterInitialization(@Nonnull Object bean, @Nonnull String beanName)
60+
throws BeansException {
6661
if (bean instanceof NamespaceTemplate && beanName.equals("temporalRootNamespaceTemplate")) {
6762
if (namespaceProperties != null) {
63+
// If there are non-root namespaces, we need to inject beans for each of them. Look
64+
// up the bean manually instead of using @Autowired to avoid circular dependencies or
65+
// causing the dependency to
66+
// get initialized to early and skip post-processing.
67+
//
68+
// Note: We don't use @Lazy here because these dependencies are optional and @Lazy doesn't
69+
// interact well with
70+
// optional dependencies.
71+
metricsScope = findBean("temporalMetricsScope", Scope.class);
72+
tracer = findBean(Tracer.class);
73+
testWorkflowEnvironment =
74+
findBean("temporalTestWorkflowEnvironment", TestWorkflowEnvironmentAdapter.class);
6875
namespaceProperties.forEach(this::injectBeanByNonRootNamespace);
6976
}
7077
}
@@ -163,6 +170,24 @@ private <T> T findBeanByNamespace(String beanPrefix, Class<T> clazz) {
163170
return null;
164171
}
165172

173+
private <T> @Nullable T findBean(Class<T> clazz) {
174+
try {
175+
return beanFactory.getBean(clazz);
176+
} catch (NoSuchBeanDefinitionException | BeanNotOfRequiredTypeException ignore) {
177+
// Ignore if the bean is not found or not of the required type
178+
}
179+
return null;
180+
}
181+
182+
private <T> @Nullable T findBean(String beanName, Class<T> clazz) {
183+
try {
184+
return beanFactory.getBean(beanName, clazz);
185+
} catch (NoSuchBeanDefinitionException | BeanNotOfRequiredTypeException ignore) {
186+
// Ignore if the bean is not found or not of the required type
187+
}
188+
return null;
189+
}
190+
166191
private <T> TemporalOptionsCustomizer<T> findBeanByNameSpaceForTemporalCustomizer(
167192
String beanPrefix, Class<T> genericOptionsBuilderClass) {
168193
String beanName =

temporal-spring-boot-autoconfigure/src/main/java/io/temporal/spring/boot/autoconfigure/NonRootNamespaceAutoConfiguration.java

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
package io.temporal.spring.boot.autoconfigure;
22

33
import com.google.common.base.MoreObjects;
4-
import com.uber.m3.tally.Scope;
5-
import io.opentracing.Tracer;
64
import io.temporal.spring.boot.autoconfigure.properties.NamespaceProperties;
75
import io.temporal.spring.boot.autoconfigure.properties.NonRootNamespaceProperties;
86
import io.temporal.spring.boot.autoconfigure.properties.TemporalProperties;
9-
import io.temporal.spring.boot.autoconfigure.template.TestWorkflowEnvironmentAdapter;
107
import io.temporal.spring.boot.autoconfigure.template.WorkersTemplate;
118
import java.util.List;
129
import java.util.Optional;
@@ -15,8 +12,6 @@
1512
import org.slf4j.Logger;
1613
import org.slf4j.LoggerFactory;
1714
import org.springframework.beans.BeansException;
18-
import org.springframework.beans.factory.annotation.Autowired;
19-
import org.springframework.beans.factory.annotation.Qualifier;
2015
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2116
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
2217
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
@@ -25,6 +20,7 @@
2520
import org.springframework.context.ApplicationContextAware;
2621
import org.springframework.context.ApplicationListener;
2722
import org.springframework.context.annotation.Bean;
23+
import org.springframework.context.annotation.Conditional;
2824
import org.springframework.context.annotation.Configuration;
2925
import org.springframework.context.annotation.Lazy;
3026
import org.springframework.context.event.ApplicationContextEvent;
@@ -35,6 +31,7 @@
3531
@EnableConfigurationProperties(TemporalProperties.class)
3632
@AutoConfigureAfter({RootNamespaceAutoConfiguration.class, ServiceStubsAutoConfiguration.class})
3733
@ConditionalOnBean(ServiceStubsAutoConfiguration.class)
34+
@Conditional(NamespacesPresentCondition.class)
3835
@ConditionalOnExpression(
3936
"${spring.temporal.test-server.enabled:false} || '${spring.temporal.connection.target:}'.length() > 0")
4037
public class NonRootNamespaceAutoConfiguration {
@@ -43,20 +40,14 @@ public class NonRootNamespaceAutoConfiguration {
4340
LoggerFactory.getLogger(NonRootNamespaceAutoConfiguration.class);
4441

4542
@Bean
46-
public NonRootBeanPostProcessor nonRootBeanPostProcessor(
47-
TemporalProperties properties,
48-
@Autowired(required = false) @Nullable Tracer otTracer,
49-
@Qualifier("temporalTestWorkflowEnvironmentAdapter") @Autowired(required = false) @Nullable
50-
TestWorkflowEnvironmentAdapter testWorkflowEnvironment,
51-
@Qualifier("temporalMetricsScope") @Autowired(required = false) @Nullable
52-
Scope metricsScope) {
53-
return new NonRootBeanPostProcessor(
54-
properties, otTracer, testWorkflowEnvironment, metricsScope);
43+
public static NonRootBeanPostProcessor nonRootBeanPostProcessor(
44+
@Lazy TemporalProperties properties) {
45+
return new NonRootBeanPostProcessor(properties);
5546
}
5647

5748
@Bean
58-
public NonRootNamespaceEventListener nonRootNamespaceEventListener(
59-
TemporalProperties temporalProperties,
49+
public static NonRootNamespaceEventListener nonRootNamespaceEventListener(
50+
@Lazy TemporalProperties temporalProperties,
6051
@Nullable @Lazy List<WorkersTemplate> workersTemplates) {
6152
return new NonRootNamespaceEventListener(temporalProperties, workersTemplates);
6253
}

temporal-spring-boot-autoconfigure/src/test/java/io/temporal/spring/boot/autoconfigure/MultiNamespaceTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ void setUp() {
3636
@Test
3737
@Timeout(value = 10)
3838
public void shouldContainsNonRootRelatedBean() {
39+
Assertions.assertTrue(applicationContext.containsBean("nonRootBeanPostProcessor"));
3940
Assertions.assertTrue(applicationContext.containsBean("ns1NamespaceTemplate"));
4041
Assertions.assertTrue(applicationContext.containsBean("namespace2NamespaceTemplate"));
4142
Assertions.assertTrue(applicationContext.containsBean("ns1ClientTemplate"));

temporal-spring-boot-autoconfigure/src/test/java/io/temporal/spring/boot/autoconfigure/StartWorkersTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
import io.temporal.spring.boot.autoconfigure.properties.TemporalProperties;
66
import io.temporal.testing.TestWorkflowEnvironment;
77
import io.temporal.worker.Worker;
8+
import org.junit.jupiter.api.Assertions;
89
import org.junit.jupiter.api.Test;
910
import org.junit.jupiter.api.TestInstance;
1011
import org.junit.jupiter.api.Timeout;
1112
import org.springframework.beans.factory.annotation.Autowired;
1213
import org.springframework.boot.test.context.SpringBootTest;
14+
import org.springframework.context.ConfigurableApplicationContext;
1315
import org.springframework.context.annotation.ComponentScan;
1416
import org.springframework.context.annotation.FilterType;
1517
import org.springframework.test.context.ActiveProfiles;
@@ -18,6 +20,7 @@
1820
@ActiveProfiles(profiles = "disable-start-workers")
1921
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
2022
public class StartWorkersTest {
23+
@Autowired ConfigurableApplicationContext applicationContext;
2124

2225
@Autowired TemporalProperties temporalProperties;
2326

@@ -33,6 +36,7 @@ public void testStartWorkersConfigDisabled() {
3336
@Timeout(value = 10)
3437
public void testWorkersStarted() {
3538
Worker worker = testWorkflowEnvironment.getWorkerFactory().getWorker("UnitTest");
39+
Assertions.assertFalse(applicationContext.containsBean("nonRootBeanPostProcessor"));
3640
assertNotNull(worker);
3741
assertTrue(worker.isSuspended());
3842
}

0 commit comments

Comments
 (0)