I have two Maven modules. The first one, called "application", contains the spring boot
Application class that just contains these lines:
package org.example.application; @SpringBootApplication @ComponentScan({"org.example.model", "org.example"}) public class Application { public static void main(String[] args) { ApplicationContext ctx = SpringApplication.run(Application.class, args); } }
In the same Maven module and package, org.example.application
, I have a RestController
that uses a Component
that in turn uses the components of the other Maven module described below.
The other Maven module, called "model", contains the spring boot
components (crud-repositories, entities etc). All those classes are under the same package structure as the first Maven module (org.example
) but in subpackages of that, like org.example.model.entities
, org.example.model.repositories
etc.
So, the flow is like this:
Maven module application
in package org.example:SpringBootApplication -> RestController -> MyComponent
And the components that should be autowired in MyComponent
are the ones in the model
Maven module under the package org.example.model
.
But when I start the application I just get the error:
*************************** APPLICATION FAILED TO START *************************** Description: Field myRepository in org.example.MyComponent required a bean of type 'org.example.model.repositories.MyRepository' that could not be found. Action: Consider defining a bean of type 'org.example.model.repositories.MyRepository' in your configuration.
org.example.model.repositories.MyRepository
does exist in Maven module "model" but cannot be found by the SpringBootApplication class!
As you can see, I have tried to explicitly define the scan components to: @ComponentScan({"org.example.model", "org.example"})
but that does not seem to help.
So what have I done wrong?
Using @ComponentScan in a Spring Application. With Spring, we use the @ComponentScan annotation along with the @Configuration annotation to specify the packages that we want to be scanned. @ComponentScan without arguments tells Spring to scan the current package and all of its sub-packages.
@Component and @ComponentScan are for different purposes. @Component indicates that a class might be a candidate for creating a bean. It's like putting a hand up. @ComponentScan is searching packages for Components.
The @ComponentScan annotation is used with the @Configuration annotation to tell Spring the packages to scan for annotated components. @ComponentScan also used to specify base packages and base package classes using thebasePackageClasses or basePackages attributes of @ComponentScan.
The first thing that you should wonder is : why do you declare @ComponentScan
while one of the goal of @SpringBootApplication
is (among other things) to enable the component scan ?
From Spring Boot documentation :
The
@SpringBootApplication
annotation is equivalent to using@Configuration
,@EnableAutoConfiguration
and@ComponentScan
with their default attributes
Note that when on the class of your Spring Boot Application, you declare @ComponentScan
to specify a value as basePackages
, it overrides the basePackages
used by default by @SpringBootApplication
that is the current package where the class resides. So to have as base package both the package of the Spring Boot Application class and the additional packages that were missing, you have to explicitly set them.
Besides basePackages
is recursive. So to enable the scan both for classes locating in the "org.example"
and "org.example.model"
packages, specifying "org.example"
is enough as "org.example.model"
is a sub-package of it.
Try that :
@SpringBootApplication(scanBasePackages={"org.example"})
Or alternatively :
@SpringBootApplication @ComponentScan("org.example")
As you design your Spring Boot application layout, your have two cases :
1) case (to favor) where you use a package layout that provides the auto configuration of Spring Boot with zero configuration.
To summarize : if your classes annotated with Spring Bean stereotypes : @Component
, @Repositories
, @Repositories
,... are located in the same package or a sub-package of the Spring Boot Application class, declaring only @SpringBootApplication
is all you need.
2) case (to avoid) where you don't use a package layout that provides the auto configuration of Spring Boot with zero configuration.
It generally means that you have candidate classes to scan that are not in the package (or sub-package) of your class annotated with @SpringBootApplication
.
In this case, you add the scanBasePackages
attribute or add @ComponentScan
to specify packages to scan.
But additionally, if your repositories are not located in a package or sub-package of your class annotated with @SpringBootApplication
, something else has to be declared such as : @EnableJpaRepositories(="packageWhereMyRepoAreLocated")
Here is the documentation about this part (emphasis is mine) :
80.3 Use Spring Data Repositories
Spring Data can create implementations of @Repository interfaces of various flavors. Spring Boot handles all of that for you, as long as those @Repositories are included in the same package (or a sub-package) of your @EnableAutoConfiguration class.
For many applications, all you need is to put the right Spring Data dependencies on your classpath (there is a spring-boot-starter-data-jpa for JPA and a spring-boot-starter-data-mongodb for Mongodb) and create some repository interfaces to handle your @Entity objects. Examples are in the JPA sample and the Mongodb sample.
Spring Boot tries to guess the location of your @Repository definitions, based on the @EnableAutoConfiguration it finds. To get more control, use the @EnableJpaRepositories annotation (from Spring Data JPA).
1) case (to favor) where you use a package layout that provides the auto configuration of Spring Boot with zero configuration.
With a Spring Boot application declared in the org.example
package, and all bean classes (Repositories included) declared in the same package or a sub-package of org.example
, the following declaration is enough for the Spring Boot application :
package org.example; @SpringBootApplication public class Application { public static void main(String[] args) { ApplicationContext ctx = SpringApplication.run(Application.class, args); } }
The repositories could be located in the org.example.repository
package such as :
package org.example.repository; @Repository public interface FooRepository extends JpaRepository<Foo, Long>, { }
and
package org.example.repository; @Repository public interface BarRepository extends JpaRepository<Bar, Long>, { }
The controllers could be located in the org.example.controller
package :
package org.example.controller; @RestController @RequestMapping("/api/foos") public class FooController {...}
and so for...
2) case (to avoid) where you don't use a package layout that provides the auto configuration of Spring Boot with zero configuration.
With a Spring Boot application declared in the org.example.application
package, and not all bean classes (Repositories included) declared in the same package or a sub-package of org.example.application
, the following declaration will be required for the Spring Boot application :
package org.example.application; @SpringBootApplication(scanBasePackages= { "org.example", "org.thirdparty.repository"}) @EnableJpaRepositories("org.thirdparty.repository") public class Application { public static void main(String[] args) { ApplicationContext ctx = SpringApplication.run(Application.class, args); } }
And the bean classes could be as below.
The repositories that may come from an external a JAR could be located in the org.thirdparty.repository
package such as :
package org.thirdparty.repository; @Repository public interface FooRepository extends JpaRepository<Foo, Long>, { }
and
package org.thirdparty.repository; @Repository public interface BarRepository extends JpaRepository<Bar, Long>, { }
The controllers could be located in the org.example.controller
package :
package org.example.controller @RestController @RequestMapping("/api/foos") public class FooController {...}
and so for...
Conclusion : defining the Spring Boot application in the base package of your namespace is really encouraged to make the Spring Boot configuration as simple as possible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With