Skip to content

Commit edf88a5

Browse files
authored
refactor(springboot): builder bean conditional to no other builder bean already created (#770)
1 parent 8c9e174 commit edf88a5

File tree

2 files changed

+38
-53
lines changed

2 files changed

+38
-53
lines changed

platform-plugins/flamingock-springboot-integration/src/main/java/io/flamingock/springboot/FlamingockAutoConfiguration.java

Lines changed: 30 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@
2424
import org.springframework.boot.ApplicationRunner;
2525
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2626
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
27+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2728
import org.springframework.boot.context.properties.EnableConfigurationProperties;
2829
import org.springframework.context.ApplicationContext;
2930
import org.springframework.context.ApplicationEventPublisher;
3031
import org.springframework.context.annotation.Bean;
3132
import org.springframework.context.annotation.Configuration;
33+
import org.springframework.context.annotation.Profile;
3234

3335
import java.util.List;
3436

@@ -37,11 +39,14 @@
3739
*
3840
* <p>The configuration behavior is controlled by the {@code flamingock.management-mode} property:</p>
3941
* <ul>
40-
* <li>{@code APPLICATION_RUNNER} (default) - Spring creates, builds, and executes the runner as an ApplicationRunner</li>
41-
* <li>{@code INITIALIZING_BEAN} - Spring creates, builds, and executes the runner as an InitializingBean</li>
42+
* <li>{@code APPLICATION_RUNNER} (default) - Spring creates the builder and executes it as an ApplicationRunner</li>
43+
* <li>{@code INITIALIZING_BEAN} - Spring creates the builder and executes it as an InitializingBean</li>
4244
* <li>{@code DEFERRED} - Spring creates the builder; the application controls execution</li>
4345
* <li>{@code UNMANAGED} - No beans are created; the application manages everything</li>
4446
* </ul>
47+
*
48+
* <p>The builder bean is always created (unless UNMANAGED) and can be overridden by providing
49+
* your own {@link AbstractChangeRunnerBuilder} bean.</p>
4550
*/
4651
@Configuration
4752
@ConditionalOnClass(name = "org.springframework.boot.SpringApplication")
@@ -50,56 +55,16 @@
5055
public class FlamingockAutoConfiguration {
5156

5257
/**
53-
* Creates an ApplicationRunner that builds and executes Flamingock at application startup.
54-
* Only created when management-mode is APPLICATION_RUNNER (the default).
55-
*/
56-
@Bean("flamingock-runner")
57-
@ConditionalOnExpression("'${flamingock.management-mode:APPLICATION_RUNNER}'.toUpperCase().equals('APPLICATION_RUNNER')")
58-
public ApplicationRunner applicationRunner(SpringbootProperties configurationProperties,
59-
ApplicationContext springContext,
60-
ApplicationEventPublisher applicationEventPublisher,
61-
@Autowired(required = false) CommunityAuditStore auditStore,
62-
List<TargetSystem> targetSystems) {
63-
AbstractChangeRunnerBuilder<?, ?> builder = createBuilder(
64-
configurationProperties, springContext, applicationEventPublisher, auditStore, targetSystems);
65-
return SpringbootUtil.toApplicationRunner(builder);
66-
}
67-
68-
/**
69-
* Creates an InitializingBean that builds and executes Flamingock during bean initialization.
70-
* Only created when management-mode is INITIALIZING_BEAN.
71-
*/
72-
@Bean("flamingock-runner")
73-
@ConditionalOnExpression("'${flamingock.management-mode:APPLICATION_RUNNER}'.toUpperCase().equals('INITIALIZING_BEAN')")
74-
public InitializingBean initializingBeanRunner(SpringbootProperties configurationProperties,
75-
ApplicationContext springContext,
76-
ApplicationEventPublisher applicationEventPublisher,
77-
@Autowired(required = false) CommunityAuditStore auditStore,
78-
List<TargetSystem> targetSystems) {
79-
AbstractChangeRunnerBuilder<?, ?> builder = createBuilder(
80-
configurationProperties, springContext, applicationEventPublisher, auditStore, targetSystems);
81-
return SpringbootUtil.toInitializingBean(builder);
82-
}
83-
84-
/**
85-
* Exposes the Flamingock builder for manual control over execution.
86-
* Only created when management-mode is DEFERRED.
58+
* Creates the Flamingock builder bean.
59+
* Always created unless management-mode is UNMANAGED or user provides their own builder.
8760
*/
8861
@Bean("flamingock-builder")
89-
@ConditionalOnExpression("'${flamingock.management-mode:APPLICATION_RUNNER}'.toUpperCase().equals('DEFERRED')")
62+
@ConditionalOnMissingBean(AbstractChangeRunnerBuilder.class)
9063
public AbstractChangeRunnerBuilder<?, ?> flamingockBuilder(SpringbootProperties configurationProperties,
9164
ApplicationContext springContext,
9265
ApplicationEventPublisher applicationEventPublisher,
9366
@Autowired(required = false) CommunityAuditStore auditStore,
9467
List<TargetSystem> targetSystems) {
95-
return createBuilder(configurationProperties, springContext, applicationEventPublisher, auditStore, targetSystems);
96-
}
97-
98-
private AbstractChangeRunnerBuilder<?, ?> createBuilder(SpringbootProperties configurationProperties,
99-
ApplicationContext springContext,
100-
ApplicationEventPublisher applicationEventPublisher,
101-
CommunityAuditStore auditStore,
102-
List<TargetSystem> targetSystems) {
10368
AbstractChangeRunnerBuilder<?, ?> builder = FlamingockFactory.getEditionAwareBuilder(
10469
configurationProperties.getCoreConfiguration(),
10570
configurationProperties.getCloudProperties(),
@@ -116,4 +81,24 @@ public InitializingBean initializingBeanRunner(SpringbootProperties configuratio
11681

11782
return builder;
11883
}
84+
85+
/**
86+
* Creates an ApplicationRunner that builds and executes Flamingock at application startup.
87+
* Only created when management-mode is APPLICATION_RUNNER (the default).
88+
*/
89+
@Bean("flamingock-runner")
90+
@ConditionalOnExpression("'${flamingock.management-mode:APPLICATION_RUNNER}'.toUpperCase().equals('APPLICATION_RUNNER')")
91+
public ApplicationRunner applicationRunner(AbstractChangeRunnerBuilder<?, ?> builder) {
92+
return SpringbootUtil.toApplicationRunner(builder);
93+
}
94+
95+
/**
96+
* Creates an InitializingBean that builds and executes Flamingock during bean initialization.
97+
* Only created when management-mode is INITIALIZING_BEAN.
98+
*/
99+
@Bean("flamingock-runner")
100+
@ConditionalOnExpression("'${flamingock.management-mode:APPLICATION_RUNNER}'.toUpperCase().equals('INITIALIZING_BEAN')")
101+
public InitializingBean initializingBeanRunner(AbstractChangeRunnerBuilder<?, ?> builder) {
102+
return SpringbootUtil.toInitializingBean(builder);
103+
}
119104
}

platform-plugins/flamingock-springboot-integration/src/test/java/io/flamingock/springboot/FlamingockAutoConfigurationTests.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,29 +42,29 @@ private ApplicationContextRunner contextRunner() {
4242
}
4343

4444
@Test
45-
void whenModeIsDefault_thenRunnerBeanExistsAndBuilderBeanDoesNot() {
46-
// Default is APPLICATION_RUNNER - runner bean exists, builder bean does not
45+
void whenModeIsDefault_thenBothBuilderAndRunnerBeansExist() {
46+
// Default is APPLICATION_RUNNER - both builder and runner beans exist
4747
contextRunner().run(ctx -> {
48+
assertThat(ctx).hasBean("flamingock-builder");
4849
assertThat(ctx).hasBean("flamingock-runner");
49-
assertThat(ctx).doesNotHaveBean("flamingock-builder");
5050
});
5151
}
5252

5353
@Test
54-
void whenModeIsApplicationRunner_thenRunnerBeanExistsAndBuilderBeanDoesNot() {
54+
void whenModeIsApplicationRunner_thenBothBuilderAndRunnerBeansExist() {
5555
contextRunner()
5656
.withPropertyValues("flamingock.management-mode=APPLICATION_RUNNER")
5757
.run(ctx -> {
58+
assertThat(ctx).hasBean("flamingock-builder");
5859
assertThat(ctx).hasBean("flamingock-runner");
59-
assertThat(ctx).doesNotHaveBean("flamingock-builder");
6060
});
6161
}
6262

6363
@Test
64-
void whenModeIsInitializingBean_thenRunnerBeanIsCreated() {
64+
void whenModeIsInitializingBean_thenBothBeansCreatedAndExecutionAttempted() {
6565
// InitializingBean executes immediately during bean creation.
66-
// We verify the bean creation was attempted by checking the context fails
67-
// with a Flamingock-related error (proving the InitializingBean bean was created and executed).
66+
// Both builder and runner beans are created, but execution fails because
67+
// the test context doesn't have all required Flamingock dependencies.
6868
contextRunner()
6969
.withPropertyValues("flamingock.management-mode=INITIALIZING_BEAN")
7070
.run(ctx -> {

0 commit comments

Comments
 (0)