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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41430051/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 05:52:14  来源:igfitidea点击:

Scan components of different maven modules/JARs in a Spring Boot application

javaspringspring-boot

提问by Rox

I have two Maven modules. The first one, called "application", contains the spring bootApplication class that just contains these lines:

我有两个 Maven 模块。第一个称为“应用程序”,包含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);
    }
}

In the same Maven module and package, org.example.application, I have a RestControllerthat uses a Componentthat in turn uses the components of the other Maven module described below.

在同一个 Maven 模块和包中org.example.application,我有一个RestController使用 的Component,而该 又使用下面描述的其他 Maven 模块的组件。

The other Maven module, called "model", contains the spring bootcomponents (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.repositoriesetc.

另一个 Maven 模块,称为“模型”,包含spring boot组件(crud 存储库、实体等)。所有这些类是相同的封装结构与第一Maven的模块(下org.example),但在那的子包,等org.example.model.entitiesorg.example.model.repositories等。

So, the flow is like this:

所以,流程是这样的:

Maven module applicationin package org.example:
SpringBootApplication -> RestController -> MyComponent

org.exampleapplication包中的Maven 模块:
SpringBootApplication -> RestController -> MyComponent

And the components that should be autowired in MyComponentare the ones in the modelMaven module under the package org.example.model.

而应该自动装配MyComponentmodel组件是 package 下 Maven 模块中的组件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.MyRepositorydoes exist in Maven module "model" but cannot be found by the SpringBootApplication class!

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

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.

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

So what have I done wrong?

那么我做错了什么?

回答by davidxxx

The first thing that you should wonder is : why do you declare @ComponentScanwhile one of the goal of @SpringBootApplicationis (among other things) to enable the component scan ?
From Spring Boot documentation:

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

The @SpringBootApplicationannotation is equivalent to using @Configuration, @EnableAutoConfigurationand @ComponentScanwith their default attributes

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

Note that when on the class of your Spring Boot Application, you declare @ComponentScanto specify a value as basePackages, it overrides the basePackagesused by default by @SpringBootApplicationthat 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.

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

Besides basePackagesis 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.

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

Try that :

试试看:

@SpringBootApplication(scanBasePackages={"org.example"})

Or alternatively :

或者:

@SpringBootApplication
@ComponentScan("org.example")


When specify @EnableJpaRepositories/@ComponentScan/scanBasePackages in a Spring Boot Application ?

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

As you design your Spring Boot application layout, your have two cases :

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

1) case (to favor) where you use a package layout that provides the auto configuration of Spring Boot with zero configuration.

1) 案例(赞成)您使用包布局提供零配置的 Spring Boot 自动配置。

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 @SpringBootApplicationis all you need.

总结一下:如果用 Spring Bean 构造型注释的类 : @Component, @Repositories, @Repositories,... 位于 Spring Boot Application 类的同一个包或子包中,则只需声明即可 @SpringBootApplication

2) case (to avoid) where you don't use a package layout that provides the auto configuration of Spring Boot with zero configuration.

2) 情况(避免)您不使用提供零配置的 Spring Boot 自动配置的包布局。

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 scanBasePackagesattribute or add @ComponentScanto 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")

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

Here is the documentationabout 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).

80.3 使用 Spring 数据存储库

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)。



Examples

例子

1) case (to favor) where you use a package layout that provides the auto configuration of Spring Boot with zero configuration.

1) 案例(赞成)您使用包布局提供零配置的 Spring Boot 自动配置。

With a Spring Boot application declared in the org.examplepackage, 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 :

如果在org.example包中声明了一个 Spring Boot 应用程序,并且所有 bean 类(包括 Repositories)都声明在同一个包或 的子包中org.example,那么对于 Spring Boot 应用程序,以下声明就足够了:

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.repositorypackage such as :

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

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.controllerpackage :

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

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.

2) 情况(避免)您不使用提供零配置的 Spring Boot 自动配置的包布局。

With a Spring Boot application declared in the org.example.applicationpackage, 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 :

如果在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);
    }
}

And the bean classes could be as below.

bean 类可能如下所示。

The repositories that may come from an external a JAR could be located in the org.thirdparty.repositorypackage such as :

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

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.controllerpackage :

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

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.

结论:确实鼓励在命名空间的基本包中定义 Spring Boot 应用程序,以使 Spring Boot 配置尽可能简单。