Reputation: 2920
I have a project with a Spring container. Let's say this project is called my-common-library
and uses the namespace my.common
. It scans all components in this namespace, as specified in common-context.xml
which looks like following
<beans ...>
<context:component-scan base-package="my.common"/>
</beans>
Among other things this scan detects classes annotated with @MyComponent
.
Now I would like to reuse this project as fully as possible. Let's say I start a new project my-client
which uses in the namespace my.client
. The my-client
mostly consists of components annotated with @MyComponent
.
In the ideal world I would just add the dependency my-common-library
and all @MyComponent
s will be scanned and registered. The only problem is the new namespace is unknown to the original my-common-library
.
One solution that I'm aware of is to add an updated common-context.xml
to my-client
which would look like
<beans ...>
<context:component-scan base-package="my.common,my.client"/>
</beans>
That would certainly work, but seems quite fragile. Is there a more elegant solution maybe?
Upvotes: 7
Views: 15757
Reputation: 1529
I think Ricardo Veguilla suggested good option. But another (sometimes better) way is to use spring starter for this purpose. You can declare your beans within spring.factories file within your dependency and pre-configure required beans outside your main code.
Upvotes: 1
Reputation: 3155
Attempting to implement component registration from libraries via component-scan is always fragile, in my opinion.
If you are just reusing code, I recommend explicitly importing the my-common-library
dependency. For example, using Java-based Spring configuration:
@Configuration
@ComponentScan("my.common")
public class MyCommonLibraryConfig {
}
On 'my-client`:
@Configuration
@Import(MyCommonLibraryConfig.class)
@ComponentScan("my.client")
public class MyClientConfig {
}
Since my-client
always depends on my-library
, it is best to define the dependency explicitly.
On the other hand, if what you actually want is to implement something like a plugin system, then you will need to use some package-based convention to discover dependencies since the component using the dependencies does not know what its dependencies until run-time.
In that case, I recommend defining a registration package name such as my.plugin
, then the Spring configuration for the component that depends on the plugins just need to define component scan on my.plugin
, and each plugin just need to define its @Components
or its @Configurations
beans in the same my.plugin
package.
If you want more control, you can add a filter to the component-scan so that you only register the bean with a certain annotation. For example, assuming you define a @MyPlugin
annotation:
@ComponentScan(
basePackages = {"my.plugin"},
includeFilters = @ComponentScan.Filter(
value= MyPlugin.class,
type = FilterType.ANNOTATION
)
)
Upvotes: 17