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

我有两个Maven模块.
一个名为“application”,包含仅包含以下行的Spring引导应用程序类:

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中,我有一个使用Component的RestController,而Component又使用下面描述的另一个Maven模块的组件.

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

所以,流程是这样的:

包org.example中的Maven模块应用程序:
SpringBootApplication – > RestController – >为MyComponent

应该在MyComponent中自动装配的组件是包org.example.model下的模型Maven模块中的组件.

但是当我启动应用程序时,我只是得到错误

***************************
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.MyRepository确实存在于Maven模块“model”中,但是SpringBootApplication类找不到它!

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

那我做错了什么?

最佳答案
你应该想知道的第一件事是:为什么你声明@ComponentScan而@SpringBootApplication的目标之一是(除其他事项外)启用组件扫描?
Spring Boot documentation开始:

The @SpringBootApplication annotation is equivalent to using
@Configuration,@EnableAutoConfiguration and @ComponentScan with their
default attributes

请注意,在Spring Boot Application的类上,声明@ComponentScan将值指定为basePackages,它会覆盖认情况下由@SpringBootApplication使用的basePackages,它是类所在的当前包.因此,要将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)case(赞成)你使用一个包布局,它提供Spring Boot的零配置自动配置.

总结一下:如果您的类使用Spring Bean构造型注释:@ Component,@ Storage,@ Repositories,…位于Spring Boot Application类的相同包或子包中,仅声明
@SpringBootApplication就是您所需要的.

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

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

关于这部分的Here is the documentation(重点是我的):

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

例子

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);
    }
}

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

package org.example.repository;

@Repository
public interface FooRepository extends  JpaRepository

package org.example.repository;

@Repository
public interface BarRepository extends  JpaRepository

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

package org.example.controller;

@RestController
@RequestMapping("/api/foos")
public class FooController  {...}

等……

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

使用org.example.application包中声明的Spring Boot应用程序,而不是在同一个包或org.example.application的子包中声明的所有bean类(包含的存储库),Spring将需要以下声明:启动应用:

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

package org.thirdparty.repository;

@Repository
public interface BarRepository extends  JpaRepository

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

package org.example.controller

@RestController
@RequestMapping("/api/foos")
public class FooController  {...}

等……

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

相关文章

这篇文章主要介绍了spring的事务传播属性REQUIRED_NESTED的原...
今天小编给大家分享的是一文解析spring中事务的传播机制,相...
这篇文章主要介绍了SpringCloudAlibaba和SpringCloud有什么区...
本篇文章和大家了解一下SpringCloud整合XXL-Job的几个步骤。...
本篇文章和大家了解一下Spring延迟初始化会遇到什么问题。有...
这篇文章主要介绍了怎么使用Spring提供的不同缓存注解实现缓...