我有两个Maven模块。
第一个名为" application",包含仅包含这些行的spring boot
Application类:
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);
}
}
在同一个Maven模块和软件包org.example.application
中,我有RestController
使用Component
,而spring boot
又使用下面描述的其他Maven模块的组件。
另一个名为" model"的Maven模块包含org.example
组件(crud-repositories,实体等)。所有这些类都与第一个Maven模块(org.example.model.entities
)在相同的包结构下,但在其子包中,如org.example.model.repositories
,application
等。
所以,流程是这样的:
包 org.example 中的 Maven模块SpringBootApplication -> RestController -> MyComponent
:
MyComponent
model
中应自动装配的组件是包org.example.model
下的***************************
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.
Maven模块中的组件。
但是当我启动应用程序时,我得到错误:
org.example.model.repositories.MyRepository
@ComponentScan({"org.example.model", "org.example"})
确实存在于Maven模块"模型"但SpringBootApplication类无法找到它!
如您所见,我尝试将扫描组件明确定义为:
DECLARE @Duration int
SET @Duration= 12540 /* for example big hour amount in minutes -> 209h */
SELECT CAST( CAST((@Duration) AS int) / 60 AS varchar) + ':' + right('0' + CAST(CAST((@Duration) AS int) % 60 AS varchar(2)),2)
/* you will get hours and minutes divided by : */
但这似乎没有帮助。
那我做错了什么?
答案 0 :(得分:15)
您应该想知道的第一件事是:为什么在@ComponentScan
的目标之一(以及其他内容)启用组件扫描时声明@SpringBootApplication
?
来自Spring Boot documentation:
@SpringBootApplication
注释等同于使用@Configuration
,@EnableAutoConfiguration
和@ComponentScan
与他们合作 默认属性
请注意,在Spring Boot应用程序的类中,您声明@ComponentScan
将值指定为basePackages
,它会覆盖basePackages
默认使用的@SpringBootApplication
这是该类所在的当前包。因此,要将Spring Boot Application类的包和缺少的其他包作为基础包,您必须明确设置它们。
除了basePackages
是递归的。因此,要为位于"org.example"
和"org.example.model"
包中的类启用扫描,指定"org.example"
就足够了,因为"org.example.model"
是它的子包。
试试:
@SpringBootApplication(scanBasePackages={"org.example"})
或者:
@SpringBootApplication
@ComponentScan("org.example")
在设计Spring Boot应用程序布局时,您有两种情况:
1)使用包布局的情况(赞成),该布局提供Spring Boot的自动配置,零配置。
总结一下:如果您的类使用Spring Bean构造型注释:@Component
,@Repositories
,@Repositories
,...位于Spring的同一个包或子包中引导应用程序类,仅声明
你只需要@SpringBootApplication
。
2)大小写(避免)你没有使用提供Spring Boot自动配置零包配置的软件包布局。
这通常意味着您要扫描的候选类不在使用@SpringBootApplication
注释的类的包(或子包)中。
在这种情况下,您可以添加scanBasePackages
属性或添加@ComponentScan
以指定要扫描的包
但另外,如果您的存储库不在使用@SpringBootApplication
注释的类的包或子包中,则必须声明其他内容,例如:@EnableJpaRepositories(="packageWhereMyRepoAreLocated")
Here is the documentation关于这一部分(重点是我的):
80.3使用Spring数据存储库
Spring Data可以创建@Repository接口的实现 各种口味。 Spring Boot为您处理所有这些,只要 那些@Repositories包含在同一个包中(或者 你的@EnableAutoConfiguration类的子包。
对于许多应用程序,您只需要输入正确的Spring Data 你的类路径依赖(有一个 spring-boot-starter-data-jpa for JPA and a 用于Mongodb的spring-boot-starter-data-mongodb)并创建一些 存储库接口来处理您的@Entity对象。例子是 JPA样本和Mongodb样本。
Spring Boot试图猜测你的@Repository的位置 定义,基于它找到的@EnableAutoConfiguration。要得到 更多控件,使用@EnableJpaRepositories注释(来自Spring 数据JPA)。
1)使用包布局的情况(赞成),该布局提供Spring Boot的自动配置,零配置。
在org.example
包中声明了Spring Boot应用程序,并且在同一个包或org.example
的子包中声明了所有bean类(包含的存储库),以下声明对于Spring Boot应用程序:
package org.example;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
存储库可以位于org.example.repository
包中,例如:
package org.example.repository;
@Repository
public interface FooRepository extends JpaRepository<Foo, Long>, { }
和
package org.example.repository;
@Repository
public interface BarRepository extends JpaRepository<Bar, Long>, { }
控制器可以位于org.example.controller
包中:
package org.example.controller;
@RestController
@RequestMapping("/api/foos")
public class FooController {...}
等等......
2)大小写(避免)你没有使用提供Spring Boot自动配置零包配置的软件包布局。
在org.example.application
包中声明的Spring Boot应用程序,而不是在org.example.application
的同一个包或子包中声明的所有bean类(包含存储库),将需要以下声明对于Spring Boot应用程序:
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);
}
}
bean类可以如下所示。
可能来自外部JAR的存储库可以位于org.thirdparty.repository
包中,例如:
package org.thirdparty.repository;
@Repository
public interface FooRepository extends JpaRepository<Foo, Long>, { }
和
package org.thirdparty.repository;
@Repository
public interface BarRepository extends JpaRepository<Bar, Long>, { }
控制器可以位于org.example.controller
包中:
package org.example.controller
@RestController
@RequestMapping("/api/foos")
public class FooController {...}
等等......
结论:确实鼓励在命名空间的基础包中定义Spring Boot应用程序,以使Spring Boot配置尽可能简单。