Add packages to component-scan
Asked Answered
P

2

6

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 @MyComponents 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?

Precedence answered 18/8, 2014 at 16:2 Comment(0)
G
17

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
   )
)
Gilmour answered 20/8, 2014 at 1:22 Comment(1)
is there a way to replace/wrap @Import(MyCommonLibraryConfig.class) with a custom annotation provided by MyCommonLibrary? (es. @MyCommonLibraryEnabled)Adrenal
A
1

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.

Across answered 21/12, 2020 at 19:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.