具有多个配置的@ComponentScan class :基于注释的配置

@ComponentScan with multiple configuration class : Annotation Based Configuration

根据 Spring 文档-

Configures component scanning directives for use with @Configuration classes. Provides support parallel with Spring XML's <context:component-scan> element.

在我的 spring 网络应用程序中有多个标记为 @Configuration 的文件,以便在 spring 容器中注册 @component bean-

问题1-我们可以在@Configurationclass的任何中使用@ComponentScan或全部 @Configuration classes?

问题2-

我也在springdoc

看到了
@Configuration
@ComponentScan(basePackageClasses = { MyConfiguration.class })
public class MyConfiguration extends WebMvcConfigurerAdapter {
...
}

为什么要在这里扫描配置 class 本身。

编辑:基本上我对@ComponentScan的理解是扫描和注册立体类型bean(例如@componant@Controller@Services等),为什么我们正在注册 @Configuration Bean。

来自文档:

Q1:

@Configuration is meta-annotated with @Component, therefore @Configuration classes are candidates for component scanning (typically using Spring XML's element) and therefore may also take advantage of @Autowired/@Inject like any regular @Component.

@Configuration classes may not only be bootstrapped using component scanning, but may also themselves configure component scanning using the @ComponentScan annotation:

@Configuration
@ComponentScan("com.acme.app.services")
public class AppConfig {
 // various @Bean definitions ...
}

Q2:

basePackageClasses

public abstract Class<?>[] basePackageClasses

Type-safe basePackages() 的替代方法,用于指定包以扫描带注释的组件。 将扫描每个 class 指定的包


回答您编辑过的问题

在某些时候,您需要告诉 Spring 您的应用程序需要的 bean 在哪里。您可以使用例如:

public static void main(String[] args) {  
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.scan("com.acme");  
    ctx.refresh();
    MyService myService = ctx.getBean(MyService.class);
}

或使用旧的 xml 样式:

<context:component-scan base-package="com.acme" />

在@Configuration 级别使用@ComponentScan 确保该配置class 的所有依赖项都可用。将 @CompenentScan 与 basePackageClasses 一起使用,您将在 class 指定的同一包下注册所有可用组件。

如果你已经让spring知道它需要扫描哪些包,在不同的地方或方式,你不需要使用它。 Q2 中的这段代码只是 spring 能够做的一个例子。

对于你的问题 1 -

是的,您可以使用 @ComponentScan 任何 配置 bean 中注册一个 bean,它在 spring 容器中注册.你可以通过以下任何一种方式将bean注册到容器中-

  1. 使用@Configurationrootcontext中注册bean或者 dispatchersevletcontext.
  2. 在任何 @Configuration bean(已在容器中注册)中导入 class。

假设-您有MvcConfig class,您正在其中扫描组件-

@ComponentScan(basePackages = {"xxxx","yyyy","zzzz"})
@Configuration
public class MvcConfig  {
....
}

要在容器中注册 MvcConfig,您必须执行 -

两者都

new AnnotationConfigWebApplicationContext().register(MvcConfig.class);

new AnnotationConfigWebApplicationContext().register(AnotherConfig.class);

@Configuration
@Import({MvcConfig.class})
public class AnotherConfig  {
....
}

对于你的问题 2 -

此处 spring 不仅注册 MyConfiguration.class,而且还注册 MyConfiguration 定义的包中的所有组件 classes。

问题一的解答:
是的,您可以在 class 的配置中使用 @Componentscan。这完全取决于你。它只是将一些特定包的各种注释 classes 注册为 beans。因此,如果您有 all 带注释的 classes 组件扫描,只需使用一个 @Componentscan 就足够了 ,因为您需要的所有必需 bean 都已在 DispatcherServlet 容器中激活和注册。

问题 2 的解答:

@Configuration
@ComponentScan(basePackageClasses = { MyConfiguration.class })
public class MyConfiguration extends WebMvcConfigurerAdapter {
...
}

您的问题:为什么要扫描配置 class 本身?
@ComponentScan(basePackageClasses = { MyConfiguration.class }) 以 MyConfiguration.class 为例。问题是这是什么意思?

通过 basepackage 属性或 basepackageclasses 有两种方法可以组件扫描包。这两个是相同的,但使用 basepackageclasses 有两个好处:
它既是 type-safe 又添加了 IDE 对未来重构的支持
这只是意味着,在未来,您可以重命名(通过重构)一些基础后台,并且由于您已经重命名了基础包,如果您使用过,则无需在配置中更改 @ComponentScan classes basepackageclasses属性。

现在回到你的第二个问题。为什么MyConfiguration.class被指定为@Componentscanbasepackageclasses属性的值?

首先,让我们知道:
basepackageclasses 属性采用表示某个标记 class 的字符串值。标记 class 告诉:嘿!注册存在此 class 的包中的所有 classes,包括此 class

因此,在您的回答中,所有这些 class 将 component-scanned 存在于 MyConfiguration.class 的包中

因此,Myconfiguration.class 充当 配置 class以及 marker class 来组件扫描其他 classes 。这也意味着所有带注释的 classes 都将被注册,它们存在于 MyConfiguration.class 所在的包中,包括 MyConfiguration.class 因为它是用 @Configuration 注释 注释的

basepackageclasses 属性也可以有其他 classes,比如 com.abc.org.Marker.class

好处:
因此,如果您重命名包,没有问题,因为您有标记 classes,这有助于 spring 找到包。这些标记 classes 可能包含也可能不包含任何内容,因为它只是作为查找包的标记。