110

I'm using Spring 3.1 and bootstrapping an application using the @Configuration and @ComponentScan attributes.

The actual start is done with

new AnnotationConfigApplicationContext(MyRootConfigurationClass.class);

This Configuration class is annotated with

@Configuration
@ComponentScan("com.my.package")
public class MyRootConfigurationClass

and this works fine. However I'd like to be more specific about the packages I scan so I tried.

@Configuration
@ComponentScan("com.my.package.first,com.my.package.second")
public class MyRootConfigurationClass

However this fails with errors telling me it can't find components specified using the @Component annotation.

What is the correct way to do what I'm after?

Thanks

mprabhat
  • 20,107
  • 7
  • 46
  • 63
Programming Guy
  • 7,259
  • 11
  • 50
  • 59
  • Two correct answers given at about the same time as far as I can tell. I'll give the accept to hage just because he has less points, but thank you both. – Programming Guy May 31 '12 at 01:26
  • If you are wondering the same thing for **kotlin** version check this one https://stackoverflow.com/a/62818187/7747942 – Sylhare Jul 09 '20 at 15:21

9 Answers9

183

@ComponentScan uses string array, like this:

@ComponentScan({"com.my.package.first","com.my.package.second"})

When you provide multiple package names in only one string, Spring interprets this as one package name, and thus can't find it.

hage
  • 5,966
  • 3
  • 32
  • 42
51

There is another type-safe alternative to specifying a base-package location as a String. See the API here, but I've also illustrated below:

@ComponentScan(basePackageClasses = {ExampleController.class, ExampleModel.class, ExmapleView.class})

Using the basePackageClasses specifier with your class references will tell Spring to scan those packages (just like the mentioned alternatives), but this method is both type-safe and adds IDE support for future refactoring -- a huge plus in my book.

Reading from the API, Spring suggests creating a no-op marker class or interface in each package you wish to scan that serves no other purpose than to be used as a reference for/by this attribute.

IMO, I don't like the marker-classes (but then again, they are pretty much just like the package-info classes) but the type safety, IDE support, and drastically reducing the number of base packages needed to include for this scan is, with out a doubt, a far better option.

Prancer
  • 3,336
  • 2
  • 32
  • 38
  • 1
    Could someone explain why @ComponentScan({"com.app", "com.controllers"}) doesn't work for me but @ComponentScan(basePackageClasses ={"com.controllers"}) does work nice ? I find it boring writing every class name – xaverras Oct 08 '15 at 14:19
  • 3
    You only have to specify one class in the package, for the package you want to scan. This is known as a marker class. If you need to scan a package higher in the hierarchy that has no classes, spring suggests a technique using a "spring marker" interface or final class defined in that package solely for the purpose of package scanning. – Prancer Oct 12 '15 at 11:54
  • Thank you. I am so sick of tracking down #wheresWaldo with string-magic/magic-strings. – granadaCoder Mar 29 '21 at 21:30
21

Provide your package name separately, it requires a String[] for package names.

Instead of this:

@ComponentScan("com.my.package.first,com.my.package.second")

Use this:

@ComponentScan({"com.my.package.first","com.my.package.second"})
mprabhat
  • 20,107
  • 7
  • 46
  • 63
  • Java's "when is a comma-separated", "when is it a string-array", "when is it a string varargs" jigsaw puzzle drives me nuts sometimes. – granadaCoder Mar 30 '21 at 18:22
14

Another way of doing this is using the basePackages field; which is a field inside ComponentScan annotation.

@ComponentScan(basePackages={"com.firstpackage","com.secondpackage"})

If you look into the ComponentScan annotation .class from the jar file you will see a basePackages field that takes in an array of Strings

public @interface ComponentScan {
String[] basePackages() default {};
}

Or you can mention the classes explicitly. Which takes in array of classes

Class<?>[]  basePackageClasses
shashwatZing
  • 1,550
  • 1
  • 17
  • 24
5

You use ComponentScan to scan multiple packages using

@ComponentScan({"com.my.package.first","com.my.package.second"})

ksw
  • 53
  • 1
  • 3
3

You can also use @ComponentScans annotation:

@ComponentScans(value = { @ComponentScan("com.my.package.first"),
                          @ComponentScan("com.my.package.second") })
Farouk.ch
  • 71
  • 7
2

I use:

@ComponentScan(basePackages = {"com.package1","com.package2","com.package3", "com.packagen"})
Dharman
  • 30,962
  • 25
  • 85
  • 135
Yann
  • 21
  • 1
1

make sure you have added this dependency in your pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
1

Use

 @ComponentScan(basePackages = {"package1", "package2"})

define it at top before class.

Edit: the brackets must be around all the base packages, not a pair of brackets per package

geanakuch
  • 778
  • 7
  • 13
  • 24
vaibhav
  • 37
  • 5
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 19 '22 at 10:28