Hi,
I wrote custom DeferredImportSelectors
and corresponding annotations that run before/after auto configurations for my library.
- Import[Before|After]AutoConfigurationDeferredImportSelector
:
DeferedImportSelector
implementation that runs before/after auto configuration
- @Import[Before|After]AutoConfiguration
:
Use the above deferred selector to specify which configurations to run before/after auto configuration
The background is we have shared library on top of spring-boot and provides shared configurations. Applications will pick some of the shared configurations to enable features.
Since those shared configurations are not autoconfigurations, because of our preference to explicitly enable each feature, I had some problems with configuration orders especially with @ConditionalOn[Missing]Bean
.
By using these DeferredImportSelectors
, I have better control for my library's configurations to run after user's configurations, and then before/after auto configurations.
Sample usage are:
In library:
// Make this configuration runs after user config but before autoconfig
@Configuration(proxyBeanMethods = false)
class MyFeatureConfig {
// @Bean to enable some feature
}
// annotation to enable my feature(config)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ImportBeforeAutoConfiguration(MyFeatureConfig.class) // <=== meta annotate
@interface EnableMyFeature {
}
In application:
@EnableMyFeature
@SpringBootApplication
class Application {
}
I am going to apply these import selectors to our library. At the same time, I think this is also beneficial if exists in spring-boot itself, hence the PR here.
Thanks,
Relates to: #18228, #19343
Comment From: philwebb
We've been discussing this issue along with #18228 and #19343 and ultimately feel like this is adding too much complexity into Spring Boot for a quite specialized use-case.
It sounds like a lot of the problems that have been raised against Spring Boot are coming from the desire to have something behave as both an @Enable...
annotation, but also a form of auto-configuration. I think it's likely that such an approach is always going to be moving against the grain of the features we provide and I it's probably worth reconsidering to see if there's another design that might work better.
My personal opinion is that if you are using @Enable
annotations then you shouldn't also try to combine them with @Condition
annotations. I'd think it would be better to keep to a purely configuration based approach and model your code in a similar way to Spring MVC where configuration and bean overrides need to happen in a very specific way (e.g. the WebMvcConfigurer
interface or WebMvcConfigurationSupport
class).
If you don't want to do that, then I'd go all in on auto-configuration and design classes that work in the same way as other auto-configurations. If you really want them to be opt-in, you could write your own @Condition
that checks against something. For example, you could have an annotation that uses an ImportBeanDefinitionRegistrar
to records it was processed then use a condition that checks for a recorded result (AutoConfigurationPackage
works a bit like that but it's not got a condition attached to it). If you go this route, it would be better to not use @Enable...
as the annotation prefix since that tends to mean something that isn't auto-configuration. Perhaps you could use something like @AllowCommonMetrics
instead?
I appreciate that this probably isn't the outcome you wanted for this pull-request. Unfortunately we really need to balance changes such as this against the future maintenance costs they might incur and the signal that they send. In this case, we just feel like there's going to be a lot of additional complexity and questions raised which won't be able to answer or support.
Comment From: ttddyy
@philwebb Thanks for the feedback.
First approach is a bit cumbersome for us to create such configuration extension points for each feature, and requires to consider rather many permutation of possibilities.
So, I'll probably go with the second suggestion since we need @Conditional
and opt-in capability.
Putting our configurations in auto-configuration semantics is better to take advantage of auto-configuration infrastructure.
Probably I'll create custom annotation @Allow...
or @Use...
to enable feature which probably put some entry in in-memory map or a bean, and create a custom @Condition
on our configurations to check the map to whether to activate the @Configuration
. Basically, auto-configurations disabled by default and enabled by annotation.
I think writing library on top of spring-boot is one way of consuming spring-boot in order for micro-service applications in an organization to streamline the feature and adapting laid out infrastructure. While evolving spring-boot, keeping in such aspect would be appreciated.
Thanks,