My application contains the following classes among others:
SpringMainApplication:
@SpringBootApplication
@ComponentScan(basePackages = {"com.foo"})
class com.foo.appl.SpringMainApplication {
... some code...
}
An interface that should be used to autowire a field:
interface com.foo.bar.ClassToAutowire {
}
And another class that uses said interface for a field:
@Component
class com.foo.appl.pack.ImplementationClass {
@Autowired
ClassToAutowire autoClass;
@Scheduled(fixedRate = 60000)
public void startStuff() {
// do something...
}
}
But the field won't autowire:
Field autoClass in com.foo.appl.pack.ImplementationClass required a bean of type 'com.foo.bar.ClassToAutowire' that could not be found.
Action:
Consider defining a bean of type 'com.foo.bar.ClassToAutowire' in your configuration.
I guess Spring doesn't like my package-structure?
com.foo.bar.ClassToAutowire
com.foo.appl.SpringMainApplication
com.foo.appl.pack.ImplementationClass
Does the @SpringBootApplication
have to be in the root package and all components must be in subpackages? If so, how do I solve my "problem", because the ClassToAutowire
comes from an imported JAR.
When changing the basePackge
to com.foo.bar
the application starts, but then the scheduled method won't run.
Thanks
When using Spring Boot it by default does component scanning. This component-scanning is done starting in the same package as the @SpringBootApplication
annotated class is in. In your case that is com.foo.appl
however this does not cover com.foo.bar
.
The best practice is to put your @SpringBootApplication
annotated class in the most top-level package you can find, in your case that would be com.foo
. This will scan all packages beneath it and will include the proper components.
You could also add @ComponentScan("com.foo")
to your @SpringBootApplication
annotated class to let it start scanning at a different package or (@SpringBootApplication(basePackage="com.foo")
.
If there aren't anymore components in the dependency jar you could also add a @Bean
method to create an instance of the desired class.
@Bean
public ClassToAutowire classToAutowire() {
return new ClassToAutowire();
}
The drawback of the second approach is that when using things like Spring Data or JPA you will also manually have to configure those (adding things like @EnableJpaRepositories
and @EntityScan
). This will grow when using/adding different frameworks, this isn't the case when you put the class in a top-level package as all packages are considered.