Classpath Scanning and Managed Components
本章中的大多数示例都使用 XML 来指定在 Spring 容器中产生每个 BeanDefinition
的配置元数据。前面的部分 (Annotation-based Container Configuration) 演示了如何通过源级注释提供许多配置元数据。但是,即使在那些示例中,“基础”Bean 定义仍然在 XML 文件中显式定义,而注释仅驱动依赖注入。本部分描述了一种通过扫描类路径来隐式检测候选组件的选项。候选组件是与筛选标准匹配并在容器中注册了相应 Bean 定义的类。这消除了使用 XML 来执行 Bean 注册的需要。相反,你可以使用注释(例如,@Component
)、AspectJ 类型表达式或你自己的自定义筛选标准来选择向容器注册 Bean 定义的类。
Most examples in this chapter use XML to specify the configuration metadata that produces
each BeanDefinition
within the Spring container. The previous section
(Annotation-based Container Configuration) demonstrates how to provide a lot of the configuration
metadata through source-level annotations. Even in those examples, however, the "base"
bean definitions are explicitly defined in the XML file, while the annotations drive only
the dependency injection. This section describes an option for implicitly detecting the
candidate components by scanning the classpath. Candidate components are classes that
match against a filter criteria and have a corresponding bean definition registered with
the container. This removes the need to use XML to perform bean registration. Instead, you
can use annotations (for example, @Component
), AspectJ type expressions, or your own
custom filter criteria to select which classes have bean definitions registered with
the container.
可以使用 Java 而不是 XML 文件来定义 bean。请查看 You can define beans using Java rather than using XML files. Take a look at the
|
@Component
and Further Stereotype Annotations
"@49" 注解是任何实现存储库 (也称为数据访问对象或 DAO) 的角色或 "@50" 的类的标记。这个标记的用法之一是自动转换异常,如 "@51" 中所述。
The @Repository
annotation is a marker for any class that fulfills the role or
stereotype of a repository (also known as Data Access Object or DAO). Among the uses
of this marker is the automatic translation of exceptions, as described in
Exception Translation.
Spring 提供了更多陈规定型注释:@Component
、@Service
和 @Controller
。@Component
是任何 Spring 管理组件的通用陈规定型。@Repository
、@Service
和 @Controller
是 @Component
在更具体的用例(分别在持久化、服务和表示层)中的专业化。因此,可以使用 @Component
为组件类加上注释,但通过使用 @Repository
、@Service
或 @Controller
为它们加上注释,这些类更适合由工具处理或与切面关联。例如,这些陈规定型注释是切入点的理想目标。@Repository
、@Service
和 @Controller
在 Spring Framework 的未来版本中也可能包含其他语义。因此,如果你在为服务层选择使用 @Component
或 @Service
之间进行选择,@Service
明显是更好的选择。与此类似,如前所述,@Repository
已被支持为持久层中自动异常翻译的标记。
Spring provides further stereotype annotations: @Component
, @Service
, and
@Controller
. @Component
is a generic stereotype for any Spring-managed component.
@Repository
, @Service
, and @Controller
are specializations of @Component
for
more specific use cases (in the persistence, service, and presentation
layers, respectively). Therefore, you can annotate your component classes with
@Component
, but, by annotating them with @Repository
, @Service
, or @Controller
instead, your classes are more properly suited for processing by tools or associating
with aspects. For example, these stereotype annotations make ideal targets for
pointcuts. @Repository
, @Service
, and @Controller
may also
carry additional semantics in future releases of the Spring Framework. Thus, if you are
choosing between using @Component
or @Service
for your service layer, @Service
is
clearly the better choice. Similarly, as stated earlier, @Repository
is already
supported as a marker for automatic exception translation in your persistence layer.
Using Meta-annotations and Composed Annotations
Spring 提供的许多注解都可以作为你自己的代码中的元注解来使用。元注解是可以应用于另一个注解的注解。例如,"@52" 注解在 "@54" 中被提及,它被 "@53" 元注解,如下面的示例所示:
Many of the annotations provided by Spring can be used as meta-annotations in your
own code. A meta-annotation is an annotation that can be applied to another annotation.
For example, the @Service
annotation mentioned earlier
is meta-annotated with @Component
, as the following example shows:
- Java
-
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component (1) public @interface Service { // ... }
1 | The @Component causes @Service to be treated in the same way as @Component .
|
2 | The @Component causes @Service to be treated in the same way as @Component . |
还可以合并元注释以创建“复合注释
”。例如,Spring MVC 中的 @RestController
注释由 @Controller
和 @ResponseBody
组成。
You can also combine meta-annotations to create “composed annotations”. For example,
the @RestController
annotation from Spring MVC is composed of @Controller
and
@ResponseBody
.
此外,复合注释可以有选择地重新声明元注释中的属性以进行自定义。在你只想公开元注释属性的子集时,这可能特别有用。例如,Spring 的 @SessionScope
注释将范围名称硬编码为 session
,但仍然允许自定义 proxyMode
。以下清单显示了 SessionScope
注释的定义:
In addition, composed annotations can optionally redeclare attributes from
meta-annotations to allow customization. This can be particularly useful when you
want to only expose a subset of the meta-annotation’s attributes. For example, Spring’s
@SessionScope
annotation hard codes the scope name to session
but still allows
customization of the proxyMode
. The following listing shows the definition of the
SessionScope
annotation:
-
Java
-
Kotlin
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Scope(WebApplicationContext.SCOPE_SESSION)
public @interface SessionScope {
/**
* Alias for {@link Scope#proxyMode}.
* <p>Defaults to {@link ScopedProxyMode#TARGET_CLASS}.
*/
@AliasFor(annotation = Scope.class)
ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}
@Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Scope(WebApplicationContext.SCOPE_SESSION)
annotation class SessionScope(
@get:AliasFor(annotation = Scope::class)
val proxyMode: ScopedProxyMode = ScopedProxyMode.TARGET_CLASS
)
然后,可以如下所示使用 @SessionScope
而不声明 proxyMode
:
You can then use @SessionScope
without declaring the proxyMode
as follows:
-
Java
-
Kotlin
@Service
@SessionScope
public class SessionScopedService {
// ...
}
@Service
@SessionScope
class SessionScopedService {
// ...
}
也可以重写 proxyMode
的值,如下例所示:
You can also override the value for the proxyMode
, as the following example shows:
-
Java
-
Kotlin
@Service
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
public class SessionScopedUserService implements UserService {
// ...
}
@Service
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
class SessionScopedUserService : UserService {
// ...
}
有关更多详细信息,请参阅 Spring 注释编程模型wiki 页面。
For further details, see the Spring Annotation Programming Model wiki page.
Automatically Detecting Classes and Registering Bean Definitions
Spring 可以自动检测陈规定型类,并将相应的 BeanDefinition
实例注册到 ApplicationContext
。例如,以下两个类符合此类自动检测:
Spring can automatically detect stereotyped classes and register corresponding
BeanDefinition
instances with the ApplicationContext
. For example, the following two classes
are eligible for such autodetection:
-
Java
-
Kotlin
@Service
public class SimpleMovieLister {
private MovieFinder movieFinder;
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
@Service
class SimpleMovieLister(private val movieFinder: MovieFinder)
-
Java
-
Kotlin
@Repository
public class JpaMovieFinder implements MovieFinder {
// implementation elided for clarity
}
@Repository
class JpaMovieFinder : MovieFinder {
// implementation elided for clarity
}
要自动检测这些类并注册相应的 bean,需要将 @ComponentScan
添加到 @Configuration
类中,其中 basePackages
属性是两个类的公共父包。(或者,可以指定一个逗号分隔的、分号分隔的或空格分隔的列表,其中包含每个类的父包。)
To autodetect these classes and register the corresponding beans, you need to add
@ComponentScan
to your @Configuration
class, where the basePackages
attribute
is a common parent package for the two classes. (Alternatively, you can specify a
comma- or semicolon- or space-separated list that includes the parent package of each class.)
-
Java
-
Kotlin
@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig {
// ...
}
@Configuration
@ComponentScan(basePackages = ["org.example"])
class AppConfig {
// ...
}
为简洁起见,前面的示例可以使用该注释的 |
For brevity, the preceding example could have used the |
以下替代项使用了 XML:
The following alternative uses XML:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.example"/>
</beans>
使用 |
The use of |
扫描类路径包需要类路径中存在相应的目录条目。使用 Ant 构建 JAR 时,请确保未激活 JAR 任务的仅文件开关。此外,在某些环境中,类路径目录可能无法根据安全策略公开,例如 JDK 1.7.0_45 及更高版本上的独立应用程序(这需要在清单中设置“受信任库”——请参阅 https://stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources)。 The scanning of classpath packages requires the presence of corresponding directory entries in the classpath. When you build JARs with Ant, make sure that you do not activate the files-only switch of the JAR task. Also, classpath directories may not be exposed based on security policies in some environments — for example, standalone apps on JDK 1.7.0_45 and higher (which requires 'Trusted-Library' setup in your manifests — see https://stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources). 在 JDK 9 的模块路径(拼图)上,Spring 的类路径扫描通常按预期工作。但是,请确保在 On JDK 9’s module path (Jigsaw), Spring’s classpath scanning generally works as expected.
However, make sure that your component classes are exported in your |
此外,当你使用 component-scan
元素时,AutowiredAnnotationBeanPostProcessor
和 CommonAnnotationBeanPostProcessor
都隐含包含。这意味着这两个组件会被自动检测,并连接起来,而无需在 XML 中提供任何 bean 配置元数据。
Furthermore, the AutowiredAnnotationBeanPostProcessor
and
CommonAnnotationBeanPostProcessor
are both implicitly included when you use the
component-scan element. That means that the two components are autodetected and
wired together — all without any bean configuration metadata provided in XML.
你可以通过包括 |
You can disable the registration of |
Using Filters to Customize Scanning
默认情况下,只有用 @Component
、@Repository
、@Service
、@Controller
、@Configuration
或自定义注解(其中注解本身用 @Component
标记)标记的类才是唯一可以检测到的候选组件。但是,你可以通过应用自定义过滤器来修改和扩展此行为。将它们添加为 @ComponentScan
注解的 includeFilters
或 excludeFilters
属性(或作为 <context:component-scan>
元素在 XML 配置中的 <context:include-filter />
或 <context:exclude-filter />
子元素)。每个过滤器元素都需要 type
和 expression
属性。下表描述了筛选选项:
By default, classes annotated with @Component
, @Repository
, @Service
, @Controller
,
@Configuration
, or a custom annotation that itself is annotated with @Component
are
the only detected candidate components. However, you can modify and extend this behavior
by applying custom filters. Add them as includeFilters
or excludeFilters
attributes of
the @ComponentScan
annotation (or as <context:include-filter />
or
<context:exclude-filter />
child elements of the <context:component-scan>
element in
XML configuration). Each filter element requires the type
and expression
attributes.
The following table describes the filtering options:
Filter Type | Example Expression | Description |
---|---|---|
annotation (default) |
|
An annotation to be present or meta-present at the type level in target components. |
assignable |
|
A class (or interface) that the target components are assignable to (extend or implement). |
aspectj |
|
An AspectJ type expression to be matched by the target components. |
regex |
|
A regex expression to be matched by the target components' class names. |
custom |
|
A custom implementation of the |
以下示例展示了忽略所有 @Repository
注解并改为使用 “stub
” 存储库的配置:
The following example shows the configuration ignoring all @Repository
annotations
and using “stub” repositories instead:
-
Java
-
Kotlin
@Configuration
@ComponentScan(basePackages = "org.example",
includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
excludeFilters = @Filter(Repository.class))
public class AppConfig {
// ...
}
@Configuration
@ComponentScan(basePackages = ["org.example"],
includeFilters = [Filter(type = FilterType.REGEX, pattern = [".*Stub.*Repository"])],
excludeFilters = [Filter(Repository::class)])
class AppConfig {
// ...
}
以下清单展示了对应的 XML:
The following listing shows the equivalent XML:
<beans>
<context:component-scan base-package="org.example">
<context:include-filter type="regex"
expression=".*Stub.*Repository"/>
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
</beans>
你还可以通过在注释上设置 |
You can also disable the default filters by setting |
Defining Bean Metadata within Components
Spring 组件还可以将 bean 定义元数据添加到容器。你可以使用与用于在 @Configuration
标记类中定义 bean 元数据的 @Bean
注解相同。以下示例展示了如何执行此操作:
Spring components can also contribute bean definition metadata to the container. You can do
this with the same @Bean
annotation used to define bean metadata within @Configuration
annotated classes. The following example shows how to do so:
-
Java
-
Kotlin
@Component
public class FactoryMethodComponent {
@Bean
@Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
public void doWork() {
// Component method implementation omitted
}
}
@Component
class FactoryMethodComponent {
@Bean
@Qualifier("public")
fun publicInstance() = TestBean("publicInstance")
fun doWork() {
// Component method implementation omitted
}
}
前面的类是一个 Spring 组件,其 doWork()
方法中有特定于应用程序的代码。但是,它还提供了一个 bean 定义,其工厂方法引用 publicInstance()
方法。@Bean
注解标识工厂方法和其他 bean 定义属性,例如通过 @Qualifier
注解进行的限定符值。可以指定的其他方法级别注解包括 @Scope
、@Lazy
和自定义限定符注解。
The preceding class is a Spring component that has application-specific code in its
doWork()
method. However, it also contributes a bean definition that has a factory
method referring to the method publicInstance()
. The @Bean
annotation identifies the
factory method and other bean definition properties, such as a qualifier value through
the @Qualifier
annotation. Other method-level annotations that can be specified are
@Scope
, @Lazy
, and custom qualifier annotations.
除了组件初始化之外,你还可以将 |
In addition to its role for component initialization, you can also place the |
如前所述,支持自动装配的字段和方法,并额外支持对 @Bean
方法的自动装配。以下示例展示了如何执行此操作:
Autowired fields and methods are supported, as previously discussed, with additional
support for autowiring of @Bean
methods. The following example shows how to do so:
-
Java
-
Kotlin
@Component
public class FactoryMethodComponent {
private static int i;
@Bean
@Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
// use of a custom qualifier and autowiring of method parameters
@Bean
protected TestBean protectedInstance(
@Qualifier("public") TestBean spouse,
@Value("#{privateInstance.age}") String country) {
TestBean tb = new TestBean("protectedInstance", 1);
tb.setSpouse(spouse);
tb.setCountry(country);
return tb;
}
@Bean
private TestBean privateInstance() {
return new TestBean("privateInstance", i++);
}
@Bean
@RequestScope
public TestBean requestScopedInstance() {
return new TestBean("requestScopedInstance", 3);
}
}
@Component
class FactoryMethodComponent {
companion object {
private var i: Int = 0
}
@Bean
@Qualifier("public")
fun publicInstance() = TestBean("publicInstance")
// use of a custom qualifier and autowiring of method parameters
@Bean
protected fun protectedInstance(
@Qualifier("public") spouse: TestBean,
@Value("#{privateInstance.age}") country: String) = TestBean("protectedInstance", 1).apply {
this.spouse = spouse
this.country = country
}
@Bean
private fun privateInstance() = TestBean("privateInstance", i++)
@Bean
@RequestScope
fun requestScopedInstance() = TestBean("requestScopedInstance", 3)
}
示例将 String
方法参数 country
自动装配到名为 privateInstance
的另一个 bean 的 age
属性值。Spring 表达式语言元素通过符号 #{ <expression> }
定义属性值。对于 @Value
注解,预先配置一个表达式解析器,在解析表达式文本时查找 bean 名称。
The example autowires the String
method parameter country
to the value of the age
property on another bean named privateInstance
. A Spring Expression Language element
defines the value of the property through the notation #{ <expression> }
. For @Value
annotations, an expression resolver is preconfigured to look for bean names when
resolving expression text.
从 Spring Framework 4.3 开始,你还可以声明一个类型为 InjectionPoint
的工厂方法参数(或其更具体的子类:DependencyDescriptor
)以访问触发当前 bean 创建的请求注入点。请注意,这仅适用于 bean 实例的实际创建,而不适用于现有实例的注入。因此,此功能最适用于原型作用域的 bean。对于其他作用域,工厂方法只会看到触发给定作用域中新建 bean 实例的注入点(例如,触发延迟单例 bean 创建的依赖项)。在这种情况下,你可以谨慎地使用提供的注入点元数据。以下示例展示了如何使用 InjectionPoint
:
As of Spring Framework 4.3, you may also declare a factory method parameter of type
InjectionPoint
(or its more specific subclass: DependencyDescriptor
) to
access the requesting injection point that triggers the creation of the current bean.
Note that this applies only to the actual creation of bean instances, not to the
injection of existing instances. As a consequence, this feature makes most sense for
beans of prototype scope. For other scopes, the factory method only ever sees the
injection point that triggered the creation of a new bean instance in the given scope
(for example, the dependency that triggered the creation of a lazy singleton bean).
You can use the provided injection point metadata with semantic care in such scenarios.
The following example shows how to use InjectionPoint
:
-
Java
-
Kotlin
@Component
public class FactoryMethodComponent {
@Bean @Scope("prototype")
public TestBean prototypeInstance(InjectionPoint injectionPoint) {
return new TestBean("prototypeInstance for " + injectionPoint.getMember());
}
}
@Component
class FactoryMethodComponent {
@Bean
@Scope("prototype")
fun prototypeInstance(injectionPoint: InjectionPoint) =
TestBean("prototypeInstance for ${injectionPoint.member}")
}
常规 Spring 组件中的 @Bean
方法的处理方式与 Spring @Configuration
类中的同类方法不同。区别在于,@Component
类不会使用 CGLIB 增强,从而拦截方法和字段的调用。CGLIB 代理是 @Configuration
类中的 @Bean
方法中调用方法或字段创建对协作对象的 bean 元数据引用的方式。此类方法不会使用普通 Java 语义调用,而是通过容器提供 Spring bean 的通常生命周期管理和代理,即使通过对 @Bean
方法的编程调用引用其他 bean 也是如此。相比之下,在普通 @Component
类中的 @Bean
方法中调用方法或字段具有标准 Java 语义,不适用任何特殊 CGLIB 处理或其他约束。
The @Bean
methods in a regular Spring component are processed differently than their
counterparts inside a Spring @Configuration
class. The difference is that @Component
classes are not enhanced with CGLIB to intercept the invocation of methods and fields.
CGLIB proxying is the means by which invoking methods or fields within @Bean
methods
in @Configuration
classes creates bean metadata references to collaborating objects.
Such methods are not invoked with normal Java semantics but rather go through the
container in order to provide the usual lifecycle management and proxying of Spring
beans, even when referring to other beans through programmatic calls to @Bean
methods.
In contrast, invoking a method or field in a @Bean
method within a plain @Component
class has standard Java semantics, with no special CGLIB processing or other
constraints applying.
你可以将 You may declare 对 static Calls to static
The Java language visibility of
最后,一个类可以为同一个 bean 保存多个 Finally, a single class may hold multiple |
Naming Autodetected Components
当一个组件作为扫描过程的一部分被自动检测到时,其 bean 名称由该扫描器所知的 BeanNameGenerator
策略生成。
When a component is autodetected as part of the scanning process, its bean name is
generated by the BeanNameGenerator
strategy known to that scanner.
默认情况下,使用 "@55"。对于 Spring "@61",如果你通过注解的 "@56" 属性提供了一个名称,则该名称将用作相应 Bean 定义中的名称。当使用以下 JSR-250 和 JSR-330 注解代替 Spring 固定用法注解时,也会适用此约定:"@57"、"@58"、"@59" 和 "@60"。
By default, the AnnotationBeanNameGenerator
is used. For Spring
stereotype annotations,
if you supply a name via the annotation’s value
attribute that name will be used as
the name in the corresponding bean definition. This convention also applies when the
following JSR-250 and JSR-330 annotations are used instead of Spring stereotype
annotations: @jakarta.annotation.ManagedBean
, @javax.annotation.ManagedBean
,
@jakarta.inject.Named
, and @javax.inject.Named
.
从 Spring Framework 6.1 开始,不再需要用于指定 bean 名称的注解属性的名称为“value”。自定义 stereotype annotations 可以声明一个名称不同的属性(例如,“name”),并使用 @AliasFor(annotation = Component.class, attribute = "value")
注释该属性。请参阅 ControllerAdvice#name()
的源代码声明以获取具体示例。
As of Spring Framework 6.1, the name of the annotation attribute that is used to specify
the bean name is no longer required to be value
. Custom stereotype annotations can
declare an attribute with a different name (such as name
) and annotate that attribute
with @AliasFor(annotation = Component.class, attribute = "value")
. See the source code
declaration of ControllerAdvice#name()
for a concrete example.
从 Spring Framework 6.1 开始,对基于约定的 stereotype 名称的支持已弃用,并且将在框架的未来版本中移除。因此,自定义 stereotype annotations 必须使用 @AliasFor
为 @Component
中的 value
属性声明一个显式别名。请参阅 Repository#value()
和 ControllerAdvice#name()
的源代码声明以获取具体示例。
As of Spring Framework 6.1, support for convention-based stereotype names is deprecated
and will be removed in a future version of the framework. Consequently, custom stereotype
annotations must use @AliasFor
to declare an explicit alias for the value
attribute
in @Component
. See the source code declaration of Repository#value()
and
ControllerAdvice#name()
for concrete examples.
如果无法从此类注释或任何其他检测到的组件(例如自定义筛选器发现的组件)中获取明确的 bean 名称,则默认 Bean 名称生成器将返回非限定的类小写名称。例如,如果检测到了以下组件类,名称将为 myMovieLister
和 movieFinderImpl
。
If an explicit bean name cannot be derived from such an annotation or for any other
detected component (such as those discovered by custom filters), the default bean name
generator returns the uncapitalized non-qualified class name. For example, if the
following component classes were detected, the names would be myMovieLister
and
movieFinderImpl
.
-
Java
-
Kotlin
@Service("myMovieLister")
public class SimpleMovieLister {
// ...
}
@Service("myMovieLister")
class SimpleMovieLister {
// ...
}
-
Java
-
Kotlin
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
@Repository
class MovieFinderImpl : MovieFinder {
// ...
}
如果你不想依赖默认的 bean 命名策略,你可以提供一个自定义 bean 命名策略。首先,实现 BeanNameGenerator
接口,并且务必包括一个默认的无参数构造函数。然后,在配置扫描程序时提供完全限定的类名称,如下面的示例注释和 Bean 定义所示。
If you do not want to rely on the default bean-naming strategy, you can provide a custom
bean-naming strategy. First, implement the
BeanNameGenerator
interface, and be sure to include a default no-arg constructor. Then, provide the fully
qualified class name when configuring the scanner, as the following example annotation
and bean definition show.
如果你因有多个自动检测的组件具有相同的非限定类名称(即,在不同包中驻留的名称相同的类)而遇到命名冲突,则可能需要配置一个 |
If you run into naming conflicts due to multiple autodetected components having the
same non-qualified class name (i.e., classes with identical names but residing in
different packages), you may need to configure a |
-
Java
-
Kotlin
@Configuration
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
public class AppConfig {
// ...
}
@Configuration
@ComponentScan(basePackages = ["org.example"], nameGenerator = MyNameGenerator::class)
class AppConfig {
// ...
}
<beans>
<context:component-scan base-package="org.example"
name-generator="org.example.MyNameGenerator" />
</beans>
作为一个通用规则,只要有其他组件可能对它进行显式引用,就考虑用注解来指定该名称。另一方面,只要容器负责连接,自动生成的名称就足够了。
As a general rule, consider specifying the name with the annotation whenever other components may be making explicit references to it. On the other hand, the auto-generated names are adequate whenever the container is responsible for wiring.
Providing a Scope for Autodetected Components
与 Spring 管理的组件一样,自动检测组件的默认范围和最常见范围是 singleton
。但是,有时需要不同的范围,可由 @Scope
注解指定。您可以按照以下示例所示提供注解中的范围名称:
As with Spring-managed components in general, the default and most common scope for
autodetected components is singleton
. However, sometimes you need a different scope
that can be specified by the @Scope
annotation. You can provide the name of the
scope within the annotation, as the following example shows:
-
Java
-
Kotlin
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
@Scope("prototype")
@Repository
class MovieFinderImpl : MovieFinder {
// ...
}
|
|
有关 Spring 上下文中特定于 Web 的范围(例如 "@62" 或 "@63")的详细信息,请参阅 "@65"。与用于这些范围的预置注解一样,你也可以使用 Spring 的元注解方法来组合你自己的范围注解:例如,用 "@64" 进行元注解的自定义注解,也有可能声明自定义作用域代理模式。
For details on web-specific scopes such as “request” or “session” in a Spring context,
see Request, Session, Application, and WebSocket Scopes. As with the pre-built annotations for those scopes,
you may also compose your own scoping annotations by using Spring’s meta-annotation
approach: for example, a custom annotation meta-annotated with @Scope("prototype")
,
possibly also declaring a custom scoped-proxy mode.
要提供一个自定义的范围解析策略,而不是依赖于基于注释的方法,您可以实现https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/ScopeMetadataResolver.html[ |
To provide a custom strategy for scope resolution rather than relying on the
annotation-based approach, you can implement the
|
-
Java
-
Kotlin
@Configuration
@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class)
public class AppConfig {
// ...
}
@Configuration
@ComponentScan(basePackages = ["org.example"], scopeResolver = MyScopeResolver::class)
class AppConfig {
// ...
}
<beans>
<context:component-scan base-package="org.example" scope-resolver="org.example.MyScopeResolver"/>
</beans>
在使用某些非单例范围时,可能需要为范围对象生成代理。推理在 "@69" 中描述。为此,组件扫描元素中提供了 scoped-proxy 属性。三个可能的值是:"@66"、"@67" 和 "@68"。例如,以下配置将生成标准 JDK 动态代理:
When using certain non-singleton scopes, it may be necessary to generate proxies for the
scoped objects. The reasoning is described in Scoped Beans as Dependencies.
For this purpose, a scoped-proxy attribute is available on the component-scan
element. The three possible values are: no
, interfaces
, and targetClass
. For example,
the following configuration results in standard JDK dynamic proxies:
-
Java
-
Kotlin
@Configuration
@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)
public class AppConfig {
// ...
}
@Configuration
@ComponentScan(basePackages = ["org.example"], scopedProxy = ScopedProxyMode.INTERFACES)
class AppConfig {
// ...
}
<beans>
<context:component-scan base-package="org.example" scoped-proxy="interfaces"/>
</beans>
Providing Qualifier Metadata with Annotations
在 Fine-tuning Annotation-based Autowiring with Qualifiers 中讨论了 @Qualifier
注释。该部分中的示例演示了如何使用 @Qualifier
注释和自定义限定符注释在解析自动装配候选对象时提供细粒度控制。由于这些示例基于 XML Bean 定义,因此限定符元数据是使用 XML 中 bean
元素的 qualifier
或 meta
子元素在候选 Bean 定义上提供的。在依靠类路径扫描自动检测组件时,可以使用候选类上的类型级注释提供限定符元数据。以下三个示例演示了此技术:
The @Qualifier
annotation is discussed in Fine-tuning Annotation-based Autowiring with Qualifiers.
The examples in that section demonstrate the use of the @Qualifier
annotation and
custom qualifier annotations to provide fine-grained control when you resolve autowire
candidates. Because those examples were based on XML bean definitions, the qualifier
metadata was provided on the candidate bean definitions by using the qualifier
or meta
child elements of the bean
element in the XML. When relying upon classpath scanning for
auto-detection of components, you can provide the qualifier metadata with type-level
annotations on the candidate class. The following three examples demonstrate this
technique:
-
Java
-
Kotlin
@Component
@Qualifier("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}
@Component
@Qualifier("Action")
class ActionMovieCatalog : MovieCatalog
-
Java
-
Kotlin
@Component
@Genre("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}
@Component
@Genre("Action")
class ActionMovieCatalog : MovieCatalog {
// ...
}
-
Java
-
Kotlin
@Component
@Offline
public class CachingMovieCatalog implements MovieCatalog {
// ...
}
@Component
@Offline
class CachingMovieCatalog : MovieCatalog {
// ...
}
与大多数基于注释的替代方案一样,请记住注释元数据绑定到类定义本身,而使用 XML 允许具有相同类型的多个 Bean 在其品质元数据中提供变体,因为该元数据是按实例提供的,而不是按类提供的。 |
As with most annotation-based alternatives, keep in mind that the annotation metadata is bound to the class definition itself, while the use of XML allows for multiple beans of the same type to provide variations in their qualifier metadata, because that metadata is provided per-instance rather than per-class. |