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

Rox*_*Rox 14 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在相同的Maven模块和包中org.example.application,我有一个RestController使用Component它反过来使用下面描述的另一个Maven模块的组件.

另一个称为"模型"的Maven模块包含spring boot组件(crud-repositories,实体等).所有这些类都与第一个Maven模块(org.example)在相同的包结构下,但在其中的子包中,如org.example.model.entities,org.example.model.repositories等等.

所以,流程是这样的:

applicationorg.example中的 Maven模块:
SpringBootApplication -> RestController -> MyComponent

应该自动装配MyComponentmodel组件是包装下的Maven模块中的组件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.
Run Code Online (Sandbox Code Playgroud)

org.example.model.repositories.MyRepository 确实存在于Maven模块"model"中,但SpringBootApplication类无法找到它!

正如您所看到的,我已尝试将扫描组件明确定义为: @ComponentScan({"org.example.model", "org.example"})但这似乎没有帮助.

那我做错了什么?

dav*_*xxx 21

你应该想知道的第一件事是:你为什么要声明@ComponentScan其中一个目标@SpringBootApplication是(除其他事项外)启用组件扫描?
Spring Boot文档:

@SpringBootApplication注解相当于使用 @Configuration,@EnableAutoConfiguration@ComponentScan与他们的默认属性

请注意,当您在Spring Boot Application的类上声明@ComponentScan指定一个值时basePackages,它会覆盖basePackages默认使用的值,@SpringBootApplication即该类所在的当前包.因此,要将Spring Boot Application类的包和缺少的其他包作为基础包,您必须明确设置它们.

除此之外basePackages是递归的.因此,要为位于"org.example""org.example.model"包中的类启用扫描,指定"org.example"就足够了,就像"org.example.model"它的子包一样.

试试看:

@SpringBootApplication(scanBasePackages={"org.example"})
Run Code Online (Sandbox Code Playgroud)

或者:

@SpringBootApplication
@ComponentScan("org.example")
Run Code Online (Sandbox Code Playgroud)

在Spring Boot应用程序中指定@ EnableJpaRepositories/@ ComponentScan/scanBasePackages?

在设计Spring Boot应用程序布局时,您有两种情况:

1)case(赞成)你使用一个包布局,它提供Spring Boot的零配置自动配置.

总结:如果你用的Spring bean注解的类定型:@Component,@Repositories,@Repositories,...都位于同一个包或者Spring引导应用程序类的子包,仅声明 @SpringBootApplication是你所需要的.

2)大小写(避免)你不使用的软件包布局提供Spring引导的零配置自动配置.

它通常意味着您有要扫描的候选类,这些类不在您注释的类的包(或子包)中@SpringBootApplication.
在这种情况下,您可以添加scanBasePackages属性或添加@ComponentScan以指定要扫描的包.
但另外,如果您的存储库不在您的类的包或子包中@SpringBootApplication,则必须声明其他内容,例如:@EnableJpaRepositories(="packageWhereMyRepoAreLocated")

这是关于这部分的文档(重点是我的):

80.3使用Spring Data Repositories

Spring Data可以创建各种风格的@Repository接口的实现.Spring Boot会为您处理所有这些,只要这些@Repositories包含在@EnableAutoConfiguration类的同一个包(或子包)中.

对于许多应用程序,您只需要在类路径上放置正确的Spring Data依赖项(对于JPA有一个spring-boot-starter-data-jpa,对于Mongodb有一个spring-boot-starter-data-mongodb)并创建一些存储库接口来处理您的@Entity对象.例子在JPA样本和Mongodb样本中.

Spring Boot会根据找到的@EnableAutoConfiguration尝试猜测@Repository定义的位置.要获得更多控制,请使用@EnableJpaRepositories注释(来自Spring Data JPA).


例子

1)case(赞成)你使用一个包布局,它提供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);
    }
}
Run Code Online (Sandbox Code Playgroud)

存储库可以位于org.example.repository包中,例如:

package org.example.repository;

@Repository
public interface FooRepository extends  JpaRepository<Foo, Long>,  { }
Run Code Online (Sandbox Code Playgroud)

package org.example.repository;

@Repository
public interface BarRepository extends  JpaRepository<Bar, Long>,  { }
Run Code Online (Sandbox Code Playgroud)

控制器可以位于org.example.controller包装中:

package org.example.controller;

@RestController
@RequestMapping("/api/foos")
public class FooController  {...}
Run Code Online (Sandbox Code Playgroud)

等......

2)大小写(避免)你不使用的软件包布局提供Spring引导的零配置自动配置.

使用在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);
    }
}
Run Code Online (Sandbox Code Playgroud)

bean类可以如下所示.

可能来自外部JAR的存储库可以位于org.thirdparty.repository包中,例如:

package org.thirdparty.repository;

@Repository
public interface FooRepository extends  JpaRepository<Foo, Long>,  { }
Run Code Online (Sandbox Code Playgroud)

package org.thirdparty.repository;

@Repository
public interface BarRepository extends  JpaRepository<Bar, Long>,  { }
Run Code Online (Sandbox Code Playgroud)

控制器可以位于org.example.controller包装中:

package org.example.controller

@RestController
@RequestMapping("/api/foos")
public class FooController  {...}
Run Code Online (Sandbox Code Playgroud)

等......

结束语:我们鼓励在命名空间的基础包中定义Spring Boot应用程序,以使Spring Boot配置尽可能简单.

  • 啊,我现在找到了解决方案。在上面的文章中,我对代码进行了一些混淆,而SpringBootApplication类实际上位于org.example.application包中。如果我将SpringBootApplication移到org.example包中,那么它将起作用。但是我仍然不明白为什么当我明确进行组件扫描以扫描org.example下的所有内容时,为什么它不能在org.example.application下,例如@ComponentScan({“ org.example.model”, “ org.example”})`。 (3认同)