当前位置: 首页 > 知识库问答 >
问题:

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

盖夕
2023-03-14

我有两个Maven模块。第一个,叫做“应用程序”,包含了只包含以下行的弹性引导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,然后使用下面描述的其他Maven模块的组件。

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

所以,流程是这样的:

Maven模块应用程序包org.example:
SpringBootApplication-

应该在MyComponent中自动连接的组件是包org下的modelMaven模块中的组件。实例型号

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

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

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

那么我做错了什么?


共有1个答案

白念
2023-03-14

您应该想知道的第一件事是:为什么要声明@ComponentScan,而@SpringBootApplication的目标之一是启用组件扫描?
来自Spring Boot留档:

@SpringBootApplication注释相当于使用@Configance@EnableAutoConfigance@ComponentScan及其默认属性

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

此外,basePackages递归的。因此,为了能够扫描位于“org.example”“org.example.model”包中的类,指定“org.example”就足够了,因为“org.example.model”是它的一个子包。

试试看:

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

或作为替代:

@SpringBootApplication
@ComponentScan("org.example")

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

1)使用包布局的情况,该布局提供了零配置的Spring Boot的自动配置。

总结一下:如果你的类用SpringBean原型注释:@Component@Repositories@Repositories,。。。位于Spring Boot应用程序类的同一个包或子包中,只需声明@SpringBootApplication即可。

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

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

以下是关于这一部分的文件(重点是我的):

80.3使用Spring数据存储库

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

对于许多应用程序,只需在类路径上放置正确的Spring数据依赖项(jpa有Spring boot starter Data jpa,mongodb有Spring boot starter Data mongodb),并创建一些存储库接口来处理@Entity对象。例如JPA示例和Mongodb示例。

Spring Boot试图根据它找到的@EnableAutoConfigance来猜测@Repository定义的位置。要获得更多的控制,请使用@EnableJpaRepository注释(来自Spring Data JPA)。

1)使用包布局的情况,该布局提供了零配置的Spring Boot的自动配置。

使用org中声明的Spring启动应用程序。示例package,以及在同一个包或org的子包中声明的所有bean类(包括存储库)。示例,以下声明对于Spring Boot应用程序已经足够了:

package org.example;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(Application.class, args);
    }
}

存储库可以位于组织中。实例存储库包,例如:

package org.example.repository;

@Repository
public interface FooRepository extends  JpaRepository<Foo, Long>,  { }

package org.example.repository;

@Repository
public interface BarRepository extends  JpaRepository<Bar, Long>,  { }

控制器可以位于组织中。实例控制器软件包:

package org.example.controller;

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

所以对于。。。

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

对于在org.example.application包中声明的Spring Boot应用程序,并且并非所有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中。第三方。存储库包,例如:

package org.thirdparty.repository;

@Repository
public interface FooRepository extends  JpaRepository<Foo, Long>,  { }

package org.thirdparty.repository;

@Repository
public interface BarRepository extends  JpaRepository<Bar, Long>,  { }

控制器可以位于组织中。实例控制器软件包:

package org.example.controller

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

所以对于。。。

结论:建议在名称空间的基本包中定义Spring Boot应用程序,使Spring Boot配置尽可能简单。

 类似资料:
  • 我不明白的是包装是如何工作的。我现在脑子里全是意大利面。当Spring转到@componentscan行并看到“实体”和“服务”时,它看到的获取这些类的结构是什么? 我的包裹结构很简单。在服务模块中,我只有src/main/java/entities和src/main/java/services 这里的幕后发生了一些我不明白的事情。Spring怎么会聪明到知道这一点?我甚至不必列出完整的包,即my

  • 我有1个应用程序和2个模块 框架结构 但我不能在MyApp中使用MyModule的文件。IDE显示我“无法访问”错误,我想扩展一个MyModule类的类。而且它不是从MyModule创建类的,有人对此有想法吗?怎么了?

  • 我有一个遗留的Spring应用程序,不管上下文是否完全用XML配置。我想使用@controller注释向应用程序添加一个新的控制器,所以我开始迁移到使用注释。 作为测试,我在应用程序中添加了以下控制器 我还添加了上下文:组件扫描标记到我的Spring上下文 尽管classpath scanner(ClassPathScanningCandidateComponentProvider)选择了hell

  • 我有一个Maven Java应用程序,我正在尝试进行对接。到目前为止,我有以下dockerfile,是我从这个答案中复制的。 如果我的应用程序是一个单模块项目,这将是很好的,但是因为它是多模块的,所以我假设我不能仅仅使用。 但是,这会在阶段出错: 注意,来自我的本地m2文件夹。

  • Player类如下所示: 前面的main方法(它使用多个扫描器,包括try-with-recours,没有任何错误或异常)如下所示:

  • Checkmarx扫描抱怨某些“元素的值在没有经过适当清理或验证的情况下流过代码,并最终在OnItemDataBound方法中显示给用户 或者 如何清理这些值?HTML编码和解码是否容易避免此类漏洞结果? 请注意,这是针对dot net应用程序的。