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](#beans-annotation-config))
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.
本章的大部分示例使用 XML 来指定在 Spring 容器中产生每个 `BeanDefinition`
的配置元数据。上一节(基于注解的容器配置)展示了如何通过源级别注解提供大量的配置元数据。然而,即使在那些示例中,"基础"的
bean
定义也是显式地在 XML 文件中定义的,而注解仅驱动依赖注入。
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.
本节描述了一种通过扫描类路径隐式检测候选组件的选项。候选组件是与过滤器标准匹配的类,并且已在容器中注册了相应的 bean
定义。
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.
这消除了使用 XML 进行 bean 注册的需求。相反,你可以使用注解(例如, `@Component` ),AspectJ
类型表达式或你自己的自定义过滤器标准来选择哪些类在容器中注册了
bean 定义。
Starting with Spring 3.0, many features provided by the Spring JavaConfig project are part of the core Spring
Framework.
This allows you to define beans using Java rather than using the traditional XML files. Take a look at the
`@Configuration`, `@Bean`, `@Import`, and `@DependsOn` annotations for examples of how to use these new features.
从 Spring 3.0 开始,Spring JavaConfig 项目提供的许多功能已成为 Spring 核心框架的一部分。这允许你使用 Java 而不是传统的
XML
文件来定义 Bean。查看 `@Configuration` 、 `@Bean` 、 `@Import` 和 `@DependsOn` 注解,了解如何使用这些新功能的示例。
## (#beans-stereotype-annotations)1.10.1. `@Component` and Further Stereotype Annotations
1.10.1. `@Component` 以及进一步的类型注解
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](https://docs.spring.io/spring-framework/docs/5.3.39/reference/html/data-access.html#orm-exception-translation).
`@Repository` 注解是任何扮演或符合仓库角色或刻板印象的类的标记(也称为数据访问对象或 DAO)。此标记的使用之一是自动翻译异常,如异常翻译中所述。
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` can 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.
Spring 提供了进一步的类型注解: `@Component` , `@Service` ,和 `@Controller` 。 `@Component` 是任何 Spring
管理的组件的通用类型注解。
`@Repository` , `@Service` ,和 `@Controller` 是 `@Component` 的专门化,分别用于更具体的用例(在持久层、服务层和表示层)。因此,你可以使用
`@Component` 注解你的组件类,但是,通过使用 `@Repository` , `@Service` 或 `@Controller`
来注解它们,你的类更适合由工具处理或与方面关联。例如,这些类型注解是切入点理想的靶子。 `@Repository` , `@Service` 和
`@Controller` 在 Spring 框架的未来版本中也可以携带额外的语义。因此,如果你在为服务层选择使用 `@Component` 或
`@Service` ,
`@Service` 显然是更好的选择。同样,如前所述, `@Repository` 已经作为自动异常转换的标记在持久层中得到支持。
## (#beans-meta-annotations)1.10.2. Using Meta-annotations and Composed Annotations
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](#beans-stereotype-annotations) is meta-annotated with `@Component`, as the following example
shows:
```
@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`.
```
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Component (1)
annotation class Service {
// ...
} ```
**1**
The `@Component` causes `@Service` to be treated in the same way as `@Component`.
You can also combine meta-annotations to create “composed annotations”. For example, the `@RestController`
annotation
from Spring MVC is composed of `@Controller` and `@ResponseBody`.
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 hardcodes the scope name to `session` but still allows customization of the
`proxyMode`. The following listing shows the definition of the `SessionScope` annotation:
```
@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
)
```
You can then use `@SessionScope` without declaring the `proxyMode` as follows:
你可以使用 `@SessionScope` 而不需要按照以下方式声明 `proxyMode` :
```
@Service
@SessionScope
public class SessionScopedService {
// ...
} ```
```
@Service
@SessionScope
class SessionScopedService {
// ...
} ```
You can also override the value for the `proxyMode`, as the following example shows:
你也可以覆盖 `proxyMode` 的值,如下例所示:
```
@Service
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
public class SessionScopedUserService implements UserService {
// ...
} ```
```
@Service
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
class SessionScopedUserService : UserService {
// ...
} ```
## (#beans-scanning-autodetection)1.10.3. Automatically Detecting Classes and Registering Bean Definitions
1.10.3. 自动检测类并注册 Bean 定义
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:
Spring 可以自动检测模式化类,并使用 `ApplicationContext` 注册相应的 `BeanDefinition` 实例。例如,以下两个类符合这种自动检测的条件:
```
@Service
public class SimpleMovieLister {
private MovieFinder movieFinder;
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
} } ```
```
@Service
class SimpleMovieLister(private val movieFinder: MovieFinder)
```
```
@Repository
public class JpaMovieFinder implements MovieFinder {
// implementation elided for clarity
} ```
```
@Repository
class JpaMovieFinder : MovieFinder {
// implementation elided for clarity
} ```
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.)
```
@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig {
// ...
} ```
```
@Configuration
@ComponentScan(basePackages = ["org.example"])
class AppConfig {
// ...
} ```
For brevity, the preceding example could have used the `value` attribute of the annotation (that is,
`@ComponentScan("org.example")`).
为了简洁,前面的例子可以使用注解的 `value` 属性(即 `@ComponentScan("org.example")` )。
The following alternative uses XML:
以下替代方案使用 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 `
context:component-scanimplicitly enables the functionality of
context:annotation-config. There is usually no need to include the
context:annotation-configelement when using
context:component-scan.
context:component-scan的使用隐式启用了
context:annotation-config的功能。在使用
context:component-scan 时,通常无需包含
context:annotation-config` 元素。
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.
类路径包的扫描需要类路径中存在相应的目录条目。当你使用 Ant 构建 JAR 文件时,请确保不要激活 JAR 任务的仅文件开关。
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](https://stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources)).
此外,在某些环境中的安全策略可能不会暴露 classpath 目录——例如,JDK 1.7.0\_45
及更高版本的独立应用程序(这需要在你的清单中进行“Trusted-Library”设置——请参阅
https://stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources)。
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 `module-info` descriptors. If you expect Spring to invoke non-public members
of
your classes, make sure that they are 'opened' (that is, that they use an `opens` declaration instead of an
`exports`
declaration in your `module-info` descriptor).
在 JDK 9 的模块路径(Jigsaw)上,Spring 的类路径扫描通常按预期工作。但是,请确保你的组件类已在你的 `module-info`
描述符中导出。如果你希望
Spring 调用你类的非公共成员,请确保它们是“已打开的”(即,在你的 `module-info` 描述符中使用 `opens` 声明而不是 `exports`
声明)。
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.
此外,当你使用组件扫描元素时, `AutowiredAnnotationBeanPostProcessor` 和 `CommonAnnotationBeanPostProcessor`
都会被隐式包含。这意味着这两个组件会被自动检测并连接起来——而无需在 XML 中提供任何 bean 配置元数据。
You can disable the registration of `AutowiredAnnotationBeanPostProcessor` and `CommonAnnotationBeanPostProcessor`
by
including the `annotation-config` attribute with a value of `false`.
## (#beans-scanning-filters)1.10.4. Using Filters to Customize Scanning
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-scanelement in XML configuration). Each filter element requires thetypeandexpression`
attributes. The following table describes the filtering options:
Table 5. Filter Types
表 5. 过滤器类型
Filter Type 过滤器类型
Example Expression 示例表达式
Description 描述
annotation (default)注释(默认)
`org.example.SomeAnnotation`
An annotation to be *present* or *meta-present* at the type level in target components.
目标组件中类型级别的存在或元存在注释。
assignable 可分配的
`org.example.SomeClass`
A class (or interface) that the target components are assignable to (extend or implement).
一个目标组件可以分配到(扩展或实现)的类(或接口)。
aspectj
`org.example..*Service+`
An AspectJ type expression to be matched by the target components.
目标组件需要匹配的 AspectJ 类型表达式。
regex 正则表达式
`org\.example\.Default.*`
A regex expression to be matched by the target components' class names.
正则表达式,用于匹配目标组件的类名。
custom 自定义
`org.example.MyTypeFilter`
A custom implementation of the `org.springframework.core.type.TypeFilter` interface.
自定义的 `org.springframework.core.type.TypeFilter` 接口实现。
The following example shows the configuration ignoring all `@Repository` annotations and using “stub” repositories
instead:
以下示例显示了忽略所有 `@Repository` 注释并使用“stub”仓库的配置:
```
@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 {
// ...
} ```
The following listing shows the equivalent XML:
以下列表显示了等效的 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 `useDefaultFilters=false` on the annotation or by providing
`use-default-filters="false"` as an attribute of the `
<component-scan/>` element. This effectively disables automatic
detection of classes annotated or meta-annotated with `@Component`, `@Repository`, `@Service`, `@Controller`,
`@RestController`, or `@Configuration`.
你也可以通过在注释中设置 `useDefaultFilters=false` 或提供 `use-default-filters="false"` 作为 `
<component-scan/>`
元素的属性来禁用默认过滤器。这有效地禁用了对用 `@Component` 、 `@Repository` 、 `@Service` 、 `@Controller` 、
`@RestController` 或 `@Configuration` 注释或元注释的类进行自动检测。
## (#beans-factorybeans-annotations)1.10.5. Defining Bean Metadata within Components
1.10.5. 在组件中定义 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:
Spring 组件也可以向容器贡献 Bean 定义元数据。你可以使用与在 `@Configuration` 注解类中定义 Bean 元数据相同的 `@Bean`
注解来完成此操作。以下示例展示了如何进行:
```
@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
} } ```
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.
前一个类是一个 Spring 组件,其 `doWork()` 方法中包含特定应用代码。然而,它还贡献了一个包含引用 `publicInstance()`
方法的工厂方法的
bean 定义。 `@Bean` 注解标识了工厂方法和其他 bean 定义属性,例如通过 `@Qualifier` 注解的限定符值。其他可以指定的方法级别注解包括
`@Scope` 、 `@Lazy` 和自定义限定符注解。
In addition to its role for component initialization, you can also place the `@Lazy` annotation on injection points
marked with `@Autowired` or `@Inject`. In this context, it leads to the injection of a lazy-resolution proxy.
However,
such a proxy approach is rather limited. For sophisticated lazy interactions, in particular in combination with
optional
dependencies, we recommend `ObjectProvider<MyTargetBean>` instead.
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:
```
@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)
} ```
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.
示例自动将 `String` 方法参数 `country` 绑定到另一个名为 `privateInstance` 的 bean 上 `age` 属性的值。Spring 表达式语言元素通过
`#{ <expression> }` 表示法定义属性的值。对于 `@Value` 注解,预先配置了一个表达式解析器,在解析表达式文本时查找 bean 名称。
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.
截至 Spring Framework 4.3 版本,你还可以声明一个类型为 `InjectionPoint` (或其更具体的子类: `DependencyDescriptor`
)的工厂方法参数,以访问触发当前 bean 创建的请求注入点。请注意,这仅适用于实际创建 bean 实例,不适用于现有实例的注入。
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).
对于其他范围,工厂方法仅看到触发在给定范围内创建新 bean 实例的注入点(例如,触发创建懒加载单例 bean 的依赖项)。
You can use the provided injection point metadata with semantic care in such scenarios. The following example shows
how
to use `InjectionPoint`:
你可以使用提供的注入点元数据,在以下场景中谨慎使用语义。以下示例展示了如何使用 `InjectionPoint` :
```
@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}")
} ```
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.
在常规 Spring 组件中的 `@Bean` 方法与 Spring `@Configuration` 类内部的对应方法处理方式不同。区别在于 `@Component`
类不会被
CGLIB 增强以拦截方法或字段的调用。CGLIB 代理是通过在 `@Configuration` 类中的 `@Bean` 方法内调用方法或字段,创建协作对象的
bean 元数据引用的方式。
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.
此类方法不是使用正常的 Java 语义调用的,而是通过容器来提供通常的生命周期管理和 Spring bean 的代理,即使在通过程序调用
`@Bean` 方法来引用其他 bean 时也是如此。相比之下,在普通的 `@Component` 类中的 `@Bean` 方法中调用方法或字段具有标准的
Java
语义,没有特殊的 CGLIB 处理或其他约束。
You may declare `@Bean` methods as `static`, allowing for them to be called without creating their containing
configuration class as an instance. This makes particular sense when defining post-processor beans (for example, of
type
`BeanFactoryPostProcessor` or `BeanPostProcessor`), since such beans get initialized early in the container
lifecycle
and should avoid triggering other parts of the configuration at that point.
Calls to static `@Bean` methods never get intercepted by the container, not even within `@Configuration` classes (as
described earlier in this section), due to technical limitations: CGLIB subclassing can override only non-static
methods. As a consequence, a direct call to another `@Bean` method has standard Java semantics, resulting in an
independent instance being returned straight from the factory method itself.
The Java language visibility of `@Bean` methods does not have an immediate impact on the resulting bean definition
in
Spring’s container. You can freely declare your factory methods as you see fit in non-`@Configuration` classes and
also
for static methods anywhere. However, regular `@Bean` methods in `@Configuration` classes need to be overridable —
that
is, they must not be declared as `private` or `final`.
`@Bean` methods are also discovered on base classes of a given component or configuration class, as well as on Java
8
default methods declared in interfaces implemented by the component or configuration class.
This allows for a lot of flexibility in composing complex configuration arrangements, with even multiple inheritance
being possible through Java 8 default methods as of Spring 4.2.
Finally, a single class may hold multiple `@Bean` methods for the same bean, as an arrangement of multiple factory
methods to use depending on available dependencies at runtime.
This is the same algorithm as for choosing the “greediest” constructor or factory method in other configuration
scenarios: The variant with the largest number of satisfiable dependencies is picked at construction time, analogous
to
how the container selects between multiple `@Autowired` constructors.
## (#beans-scanning-name-generator)1.10.6. Naming Autodetected Components
1.10.6. 自动检测组件命名
When a component is autodetected as part of the scanning process, its bean name is generated by the
`BeanNameGenerator`
strategy known to that scanner. By default, any Spring stereotype annotation (`@Component`, `@Repository`,
`@Service`,
and `@Controller`) that contains a name `value` thereby provides that name to the corresponding bean definition.
当组件在扫描过程中被自动检测为扫描的一部分时,该组件的 bean 名称由该扫描器所知的 `BeanNameGenerator`
策略生成。默认情况下,任何包含名称
`value` 的 Spring stereotypes 注解( `@Component` , `@Repository` , `@Service` ,和 `@Controller` )因此将该名称提供给相应的
bean 定义。
If such an annotation contains no name `value` 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`:
如果这样的注解不包含名称 `value` 或任何其他检测到的组件(例如通过自定义过滤器发现的组件),则默认的 Bean
名称生成器返回未大写的非限定类名。例如,如果检测到以下组件类,名称将是 `myMovieLister` 和 `movieFinderImpl` :
```
@Service("myMovieLister")
public class SimpleMovieLister {
// ...
} ```
```
@Service("myMovieLister")
class SimpleMovieLister {
// ...
} ```
```
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
} ```
```
@Repository
class MovieFinderImpl : MovieFinder {
// ...
} ```
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`](https://docs.spring.io/spring-framework/docs/5.3.39/javadoc-api/org/springframework/beans/factory/support/BeanNameGenerator.html)
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.
如果你不想依赖默认的 bean 命名策略,你可以提供一个自定义的 bean 命名策略。首先,实现 `BeanNameGenerator`
接口,并确保包含一个默认的无参构造函数。然后,在配置扫描器时提供完全限定的类名,如下面的示例注解和 bean 定义所示。
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 `BeanNameGenerator`
that
defaults to the fully qualified class name for the generated bean name. As of Spring Framework 5.2.3, the
`FullyQualifiedAnnotationBeanNameGenerator` located in package `org.springframework.context.annotation` can be used
for
such purposes.
如果你遇到多个自动检测到的组件具有相同的非限定类名(即具有相同名称但位于不同包中的类)的命名冲突,你可能需要配置一个默认为生成
bean 名称的完全限定类名的 `BeanNameGenerator` 。截至 Spring 框架 5.2.3 版本,位于包
`org.springframework.context.annotation` 中的 `FullyQualifiedAnnotationBeanNameGenerator` 可用于此类目的。
```
@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.
一般来说,当其他组件可能明确引用它时,应考虑在注释中指定名称。另一方面,当容器负责连接时,自动生成的名称是足够的。
## (#beans-scanning-scope-resolver)1.10.7. Providing a Scope for Autodetected Components
1.10.7. 为自动检测到的组件提供范围
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:
与 Spring 管理的组件一样,自动检测组件的默认和最常见的作用域是 `singleton` 。然而,有时你可能需要一个不同的作用域,这可以通过
`@Scope` 注解来指定。你可以在注解中提供作用域的名称,如下例所示:
```
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
} ```
```
@Scope("prototype")
@Repository
class MovieFinderImpl : MovieFinder {
// ...
} ```
`@Scope` annotations are only introspected on the concrete bean class (for annotated components) or the factory
method (
for `@Bean` methods). In contrast to XML bean definitions, there is no notion of bean definition inheritance, and
inheritance hierarchies at the class level are irrelevant for metadata purposes.
For details on web-specific scopes such as “request” or “session” in a Spring context,
see [Request, Session, Application, and WebSocket Scopes](#beans-factory-scopes-other). 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.
To provide a custom strategy for scope resolution rather than relying on the annotation-based approach, you can
implement the [
`ScopeMetadataResolver`](https://docs.spring.io/spring-framework/docs/5.3.39/javadoc-api/org/springframework/context/annotation/ScopeMetadataResolver.html)
interface. Be sure to include a default no-arg constructor. Then you can provide the fully qualified class name when
configuring the scanner, as the following example of both an annotation and a bean definition shows:
```
@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>
```
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](#beans-factory-scopes-other-injection). 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:
当使用某些非单例作用域时,可能需要为作用域对象生成代理。这种推理在《作用域 Bean
作为依赖》中进行了描述。为此,组件扫描元素上提供了一个作用域代理属性。可能的三个值是:
`no` , `interfaces` ,和 `targetClass` 。例如,以下配置会导致标准的 JDK 动态代理:
```
@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>
```
## (#beans-scanning-qualifiers)1.10.8. Providing Qualifier Metadata with Annotations
1.10.8. 使用注释提供限定符元数据
The `@Qualifier` annotation is discussed
in [Fine-tuning Annotation-based Autowiring with Qualifiers](#beans-autowired-annotation-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:
`@Qualifier` 注解在《基于限定符的细粒度注解自动装配微调》中进行了讨论。该部分中的示例展示了如何使用 `@Qualifier`
注解和自定义限定符注解在解决自动装配候选者时提供细粒度控制。因为那些示例基于 XML 的 bean 定义,所以通过在 XML 的
`bean`
元素的 `qualifier` 或 `meta` 子元素中提供限定符元数据,在候选 bean
定义上提供了限定符元数据。当依赖于类路径扫描来自动检测组件时,你可以在候选类上使用类型级别的注解来提供限定符元数据。以下三个示例展示了这种技术:
```
@Component
@Qualifier("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
} ```
```
@Component
@Qualifier("Action")
class ActionMovieCatalog : MovieCatalog
```
```
@Component
@Genre("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
} ```
```
@Component
@Genre("Action")
class ActionMovieCatalog : MovieCatalog {
// ...
} ```
```
@Component
@Offline
public class CachingMovieCatalog implements MovieCatalog {
// ...
} ```
```
@Component
@Offline
class CachingMovieCatalog : MovieCatalog {
// ...
} ```
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.
与大多数基于注解的替代方案一样,请注意,注解元数据绑定到类定义本身,而 XML 的使用允许相同类型的多个 bean
提供其限定符元数据的变体,因为该元数据是按实例而不是按类提供的。
## (#beans-scanning-index)1.10.9. Generating an Index of Candidate Components
1.10.9. 生成候选组件索引
While classpath scanning is very fast, it is possible to improve the startup performance of large applications by
creating a static list of candidates at compilation time. In this mode, all modules that are targets of component
scanning must use this mechanism.
尽管类路径扫描非常快,但在编译时创建候选者的静态列表,可以改善大型应用的启动性能。在此模式下,所有成为组件扫描目标的所有模块都必须使用此机制。
Your existing `@ComponentScan` or `
<context:component-scan/>` directives must remain unchanged to request the context to
scan candidates in certain packages. When the `ApplicationContext` detects such an index, it automatically uses it
rather than scanning the classpath.
你现有的 `@ComponentScan` 或 `
<context:component-scan/>` 指令必须保持不变,以请求在特定包中扫描候选者。当
`ApplicationContext` 检测到这样的索引时,它会自动使用它,而不是扫描类路径。
To generate the index, add an additional dependency to each module that contains components that are targets for
component scan directives. The following example shows how to do so with Maven:
为了生成索引,向包含组件扫描指令目标组件的每个模块添加一个额外的依赖。以下示例展示了如何使用 Maven 进行操作:
```
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-indexer</artifactId>
<version>5.3.39</version>
<optional>true</optional>
</dependency>
</dependencies>
```
With Gradle 4.5 and earlier, the dependency should be declared in the `compileOnly` configuration, as shown in the
following example:
在 Gradle 4.5 及更早版本中,依赖项应在 `compileOnly` 配置中声明,如下例所示:
```
dependencies {
compileOnly "org.springframework:spring-context-indexer:5.3.39"
} ```
With Gradle 4.6 and later, the dependency should be declared in the `annotationProcessor` configuration, as shown in
the
following example:
使用 Gradle 4.6 及更高版本,依赖项应在 `annotationProcessor` 配置中声明,如下例所示:
```
dependencies {
annotationProcessor "org.springframework:spring-context-indexer:5.3.39"
} ```
The `spring-context-indexer` artifact generates a `META-INF/spring.components` file that is included in the jar
file.
`spring-context-indexer` 工件生成一个包含在 jar 文件中的 `META-INF/spring.components` 文件。
When working with this mode in your IDE, the `spring-context-indexer` must be registered as an annotation processor
to
make sure the index is up-to-date when candidate components are updated.
当在你的 IDE 中使用此模式时,必须将 `spring-context-indexer` 注册为注解处理器,以确保在候选组件更新时索引保持最新。
The index is enabled automatically when a `META-INF/spring.components` file is found on the classpath. If an index
is
partially available for some libraries (or use cases) but could not be built for the whole application, you can fall
back to a regular classpath arrangement (as though no index were present at all) by setting `spring.index.ignore` to
`true`, either as a JVM system property or via the [
`SpringProperties`](https://docs.spring.io/spring-framework/docs/5.3.39/reference/html/appendix.html#appendix-spring-properties)
mechanism.
索引在类路径上找到 `META-INF/spring.components` 文件时自动启用。如果某些库(或用例)的索引部分可用,但无法为整个应用程序构建索引,你可以通过将
`spring.index.ignore` 设置为 `true` ,要么作为 JVM 系统属性,要么通过 `SpringProperties` 机制,回退到常规类路径安排(就好像没有索引一样)。