Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability of specifying base package for configuration beans #63

Merged
merged 7 commits into from
May 22, 2022

Conversation

Stmated
Copy link
Contributor

@Stmated Stmated commented May 6, 2022

Ability of specifying base package for configuration beans, so components that are registered inside @Configuration can be found. This is because some projects simply do not use the @Component annotation, instead manually wire the beans.

In a way I think this overcomplicates things, and it would almost be easier to give ANT path pattern for which classes to search, and the code would just search all the methods of all the classes that match that pattern, with no regard to any class-level annotations at all.

Probable issues with this PR:

  • It removes @Configuration from being matched in the regular base package scanning. So if a user has a @KafkaListener inside a @Configuration class, it would not be found.

… so components that are registered inside @configuration can be found.
@Stmated
Copy link
Contributor Author

Stmated commented May 6, 2022

It would probably also be better to change the docket to take a ComponentScanner instance instead of specifying the basePackage, so it is decoupled and you can give a custom ComponentScanner that works completely different depending on need. Like not wanting any scanning at all, and just giving your classes manually.

@stavshamir
Copy link
Member

Hi @Stmated , thanks for the PR! This does sound like a relevant use case that should be supported.
I will look into it soon, in the meanwhile please merge from master as I just fixed a failing test.

@@ -18,9 +18,13 @@ public class AsyncApiDocket {
/**
* The base package to scan for listeners.
*/
@NonNull
private String basePackage;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should make the comments more clear, as basePackage and configurationBasePackage are very similar and may be confusing.

I think this should change to:

/**
 * The base package to scan for listeners which are declared inside a class annotated with @Component or @Service.
*/

/**
* The base package to scan for configurations that contain beans that contain listeners.
*/
private String configurationBasePackage;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like they comment above, I think this comment should be more specific:

/**
* The base package to scan for @Configuration classes that contain beans that contain listeners. 
* Set this property if your listeners are declared in a class that is not annotated with @Component or @Service,
* and are declared in a class which is instantiated in a @Bean method in a @Configuration class.
*/

Copy link
Member

@stavshamir stavshamir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Stmated, that's a great contribution, well thought out and useful. I also appreciate providing new unit tests :) I have a few comments that I would like you to check and after the required changes I would gladly merge this!

@@ -9,13 +9,16 @@ public interface ComponentsScanner {
* @param basePackage The root package to scan.
* @return A set of found classes.
*/
Set<Class<?>> scanForComponents(Package basePackage);
default Set<Class<?>> scanForComponents(String basePackage) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove the argument completely form scanForComponents and leave it without arguments. Then we can also remove the AsyncAciDocket wirings from AbstractChannelScanner etc. and have DefaultComponentScanner ue the docket directly.

@@ -17,28 +24,79 @@
public class DefaultComponentsScanner implements ComponentsScanner {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wire the AsyncApiDocket here instead of in AbstrctChannelScanner, AbstractMethodLevelListener and ClassLevelKafkaListenerScanner.


Set<Class<?>> components;
if (StringUtils.isNotBlank(basePackage) && StringUtils.isNotBlank(configurationBasePackage)) {
log.debug("Scanning for component classes in configuration package {}, filtered by beans in {}", configurationBasePackage, basePackage);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the filtering part is going to be too confusing - if the user want to scan based on beans in a configuration class, let it scan all the beans. Let's remove the filtering logic.

ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AnnotationTypeFilter(Component.class));
provider.addExcludeFilter(new AnnotationTypeFilter(Configuration.class));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should we exclude @Configuration?

final Bean bean = AnnotationUtils.getAnnotation(method, Bean.class);
if (bean != null) {
final Class<?> returnType = method.getReturnType();
final String beanPackage = returnType.getPackage().getName();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned above, I think this would be too confusing, let's remove the package filtering logic here.

@stavshamir
Copy link
Member

@Stmated, that's a great contribution, well thought out and useful. I also appreciate providing new unit tests :) I have a few comments that I would like you to check and after the required changes I would gladly merge this!

…omponent scanners, Spring-aware Component Scanner
@pontus-eliason
Copy link

I did the changes noted in this PR, but also did a few extra things (which you might disagree with, who knows):

  • Changed so AsyncApiDocket takes a ComponentsScanner directly, but backwards compatible to previous basePackage way.
  • Added a ApplicationContextComponentsScanner which searches the bean registry. What's good about it: Can find beans given by external libraries and by a FactoryBean.
  • Separated the different ComponentsScanners into what they do, and created a default DefaultClassPathComponentsScanner that searches for @Component and @Configuration + @Bean annotations.

I did not make any changes to documentation, since it all works like it did previously, just with an option to swap the scanner if want to.

@Stmated
Copy link
Contributor Author

Stmated commented May 13, 2022

And that ^ was me. Having multiple accounts is a hassle.

@stavshamir
Copy link
Member

Sorry for the long time it took me to review!
Wow, that's a very impressive contribution. Thanks a lot. I will merge this now (the build is failing on some java doc stuff, I suspect it's related to lombok - I won't bother you with fixing that, I can do it myself).

Since this is a big amount of content added to the library, that would be great if we could also document it, so if you are looking for further contributions, I'm opening an issue in the project documentation site for this additions.

You are also welcome to the discord server that's starting to attract some action, and please add me on linkedin (https://www.linkedin.com/in/stavshamir/).

Cheers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants