具有多个配置的@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-我们可以在@Configuration
class的任何中使用@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注册到容器中-
- 使用
@Configuration
在rootcontext
中注册bean或者
dispatchersevletcontext
.
- 在任何
@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被指定为@Componentscan
的basepackageclasses
属性的值?
首先,让我们知道:
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 可能包含也可能不包含任何内容,因为它只是作为查找包的标记。
根据 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-我们可以在@Configuration
class的任何中使用@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注册到容器中-
- 使用
@Configuration
在rootcontext
中注册bean或者dispatchersevletcontext
. - 在任何
@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被指定为@Componentscan
的basepackageclasses
属性的值?
首先,让我们知道:
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 可能包含也可能不包含任何内容,因为它只是作为查找包的标记。