在Spring Boot应用程序中扫描不同maven模块/ JAR的组件

时间:2017-01-02 16:12:53

标签: java spring spring-boot

我有两个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.repositoriesapplication等。

所以,流程是这样的:

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 : */ 但这似乎没有帮助。

那我做错了什么?

1 个答案:

答案 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应用程序中指定@ EnableJpaRepositories / @ ComponentScan / scanBasePackages?

在设计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配置尽可能简单。