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

2024-01-09

我有两个 Maven 模块。 第一个称为“应用程序”,包含spring boot仅包含这些行的应用程序类:

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它又使用下面描述的其他 Maven 模块的组件。

另一个 Maven 模块称为“model”,包含spring boot组件(crud 存储库、实体等)。所有这些类都与第一个 Maven 模块位于相同的包结构下(org.example)但是在它的子包中,比如org.example.model.entities, org.example.model.repositories etc.

所以,流程是这样的:

Maven模块application包装内组织示例:
SpringBootApplication -> RestController -> MyComponent

以及应该自动装配的组件MyComponent是那些在model包下的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.

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

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

那么我到底做错了什么?


您应该想知道的第一件事是:为什么您要声明@ComponentScan而目标之一@SpringBootApplication是(除其他外)启用组件扫描?
From Spring Boot 文档 http://docs.spring.io/autorepo/docs/spring-boot/current/reference/html/using-boot-using-springbootapplication-annotation.html :

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

请注意,在 Spring Boot 应用程序的类上,您声明@ComponentScan将值指定为basePackages,它会覆盖basePackages默认情况下使用@SpringBootApplication这是该类所在的当前包。因此,要将 Spring Boot 应用程序类的包和缺少的附加包都作为基础包,您必须显式设置它们。

Besides basePackages是递归的。因此,要启用扫描位于"org.example" and "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 Boot Application 类的同一个包或子包中,仅声明@SpringBootApplication是你所需要的全部。

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

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

这是文档 https://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.html#howto-use-spring-data-repositories关于这部分(重点是我的):

80.3 使用 Spring 数据存储库

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

对于许多应用程序,您所需要做的就是放置正确的 Spring Data 依赖于你的类路径(有一个 spring-boot-starter-data-jpa 用于 JPA 和 spring-boot-starter-data-mongodb for Mongodb)并创建一些 用于处理 @Entity 对象的存储库接口。例子在 JPA 示例和 Mongodb 示例。

Spring Boot 尝试猜测您的 @Repository 的位置 定义,基于它找到的@EnableAutoConfiguration。要得到 更多控制,使用 @EnableJpaRepositories 注释(来自 Spring 数据 JPA)。


Examples

1) 使用包布局(以零配置提供 Spring Boot 自动配置)的情况(有利)。

在 Spring Boot 应用程序中声明org.example包,以及在同一包或子包中声明的所有 bean 类(包括存储库)org.example,对于 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>,  { }

and

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 零配置自动配置的包布局的情况(避免)。

在 Spring Boot 应用程序中声明org.example.application包,而不是在同一个包或子包中声明的所有 bean 类(包括存储库)org.example.application,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>,  { }

and

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

扫描 Spring Boot 应用程序中不同 Maven 模块/JAR 的组件 的相关文章

随机推荐