Reputation: 63
I'm writing a library for two applications A and B. Application A defines beans with XML (without component scanning) and B uses annotations and component scanning. I want to let the library define some beans that both A and B can include. However, A and B should only include those beans when they are started in a specific Spring profile (let's say my_profile
).
The TLDR question is: is there a way to do the above without referencing my_profile
in the library and without having to explicitly exclude the library from B's component scan?
Currently, the beans in the library are defined as @Bean methods in a @Configuration class, like this:
@Configuration
open class LibraryConfig {
@Bean
open fun libraryBean() = ...
}
Now in application A, in XML, I can do this:
<beans profile="my_profile">
<bean class="com.package.LibraryConfig" />
</beans>
And that works. In application B, that uses annotations, I would like to do something like this:
@Configuration
@Profile("my_profile")
@Import(LibraryConfig::class)
open class MyProfileConfig
But since LibraryConfig is also annotated with @Configuration, it will always be found by the component scanning. So this approach to make it conditional doesn't work.
Approaches I have considered:
my_profile
. I want to be able to include the library there anyway without having to explicitly exclude a part of it.So I'm looking for a way to create a 'configuration' class that can only be explicitly included. Or any other elegant way to do the above. Can it be done?
Upvotes: 1
Views: 1405
Reputation: 3450
There might be some ways to exclude the library package from project A or B's component scan without explicitly stating that the package is to be excluded.
Use a different package root for your library
The most straightforward option is to use a different package root for the library than the project uses. Since the @SpringBootApplication
annotation is meta-annotated with @ComponentScan
, if @ComponentScan
's attributes basePackageClasses
or basePackages
have not been specified, the package name of the annotated class is used as root package to use for component scanning (source):
Configures component scanning directives for use with @Configuration classes. Provides support parallel with Spring XML's context:component-scan element. Either basePackageClasses() or basePackages() (or its alias value()) may be specified to define specific packages to scan. If specific packages are not defined, scanning will occur from the package of the class that declares this annotation.
For instance, if a @SpringBootApplication
annotated root class is located in package com.example.somepackage
:
package com.example.somepackage;
@SpringBootApplication
public class DemoApplication {
...
}
The base package root com.example.somepackage
will be used as the root for component scanning. Using com.example.library
instead of com.example.somepackage.library
should exclude the library from being included in the component scanning.
Make use of ConditionalOn
annotations in the Library
If the method above doesn't work and the configuration is still automatically included during component scanning, a slightly less invasive way when compared to using profiles is adding @ConditionalOnX
annotations to your configuration class, such as:
@Configuration
@ConditionalOnProperty(prefix = "yourlibrary", name = "enabled", havingValue="true")
The projects relying on the library will now need to include the property yourlibrary.enabled=true
.
More info on the several @ConditionalOn
annotations can be found here.
Upvotes: 1