本章中的大多数示例都使用 XML 来指定生成
每个都包含在 Spring 容器中。上一节
(基于注释的容器配置)演示了如何提供大量配置
元数据。然而,即使在这些例子中,“基础”
Bean 定义在 XML 文件中显式定义,而 Comments 仅驱动
依赖项注入。本节介绍用于隐式检测
candidate 组件。候选组件是
匹配过滤条件,并在
容器。这样就不需要使用 XML 来执行 Bean 注册。相反,您
可以使用注解(例如)、AspectJ 类型表达式或您自己的
自定义过滤条件,用于选择哪些类注册了 Bean 定义
容器。BeanDefinition
@Component
您可以使用 Java 而不是 XML 文件来定义 bean。查看 、 、 和 注释 以获取有关如何
使用这些功能。 |
您可以使用 Java 而不是 XML 文件来定义 bean。查看 、 、 和 注释 以获取有关如何
使用这些功能。 |
@Component
和进一步的 Stereotype Annotations
注解是满足存储库角色或构造型(也称为数据访问对象或 DAO)的任何类的标记。用途
的标记是异常的自动转换,如 异常转换中所述。@Repository
Spring 提供了进一步的构造型 Comments: , , , 和 。 是任何 Spring Management 组件的通用构造型。、 和 是 的特化
更具体的使用案例(在 Persistence、Service 和 Presentation 中
层)。因此,您可以使用 , 来注释组件类,但是,通过使用 , , 来注释它们,或者,您的类更适合通过工具或关联进行处理
与方面。例如,这些原型注释是
切入点。、 、 和 may also
在 Spring Framework 的未来版本中携带其他语义。因此,如果你是
在使用 或 for your service layer 之间进行选择是
显然是更好的选择。同样,如前所述,已经
支持作为持久层中自动异常转换的标记。@Component
@Service
@Controller
@Component
@Repository
@Service
@Controller
@Component
@Component
@Repository
@Service
@Controller
@Repository
@Service
@Controller
@Component
@Service
@Service
@Repository
使用元注释和组合注释
Spring 提供的许多 Comments 都可以用作
自己的代码。元注释是可以应用于另一个注释的注释。
例如,前面提到的 Comments 使用 进行元注释,如下例所示:@Service
@Component
-
Java
-
Kotlin
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component (1)
public @interface Service {
// ...
}
1 | 原因的处理方式与 .@Component @Service @Component |
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Component (1)
annotation class Service {
// ...
}
1 | 原因的处理方式与 .@Component @Service @Component |
您还可以组合元注释来创建 “组合注释”。例如
Spring MVC 的 Comments 由 和 组成。@RestController
@Controller
@ResponseBody
此外,组合注释可以选择从
meta-annotations 允许自定义。当您
希望仅公开 meta-annotation 属性的子集。例如,Spring 的注解将范围名称硬编码为,但仍然允许
的自定义 .下面的清单显示了 annotation 的定义:@SessionScope
session
proxyMode
SessionScope
-
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
)
然后,无需声明 the 即可使用,如下所示:@SessionScope
proxyMode
-
Java
-
Kotlin
@Service
@SessionScope
public class SessionScopedService {
// ...
}
@Service
@SessionScope
class SessionScopedService {
// ...
}
您还可以覆盖 的值,如下例所示:proxyMode
-
Java
-
Kotlin
@Service
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
public class SessionScopedUserService implements UserService {
// ...
}
@Service
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
class SessionScopedUserService : UserService {
// ...
}
有关更多详细信息,请参阅 Spring Annotation Programming Model wiki 页面。
1 | 原因的处理方式与 .@Component @Service @Component |
1 | 原因的处理方式与 .@Component @Service @Component |
自动检测类并注册 Bean 定义
Spring 可以自动检测构造型类并使用 .例如,以下两个类
符合此类自动检测的条件:BeanDefinition
ApplicationContext
-
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
-
Java
-
Kotlin
@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig {
// ...
}
@Configuration
@ComponentScan(basePackages = ["org.example"])
class AppConfig {
// ...
}
为简洁起见,前面的示例可以使用
注释(即 )。value @ComponentScan("org.example") |
以下替代方法使用 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>
使用 隐式启用 的功能。使用 .<context:component-scan> <context:annotation-config> <context:annotation-config> <context:component-scan> |
扫描 classpath 包需要存在相应的目录 条目。使用 Ant 构建 JAR 时,请确保不要 激活 JAR 任务的 files-only 开关。此外,类路径目录可能不是 在某些环境中根据安全策略公开,例如,独立应用程序 JDK 1.7.0_45 及更高版本(需要在清单中设置“Trusted-Library”——请参阅 stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources)。 在 JDK 9 的模块路径(拼图)上, Spring 的 Classpath 扫描通常按预期工作。
但是,请确保在 Descriptors 中导出组件类。如果你希望 Spring 调用类的非公共成员,请将
确保它们已“打开”(即,它们在描述符中使用声明而不是声明)。 |
此外,当您使用
component-scan 元素。这意味着这两个组件是自动检测的,并且
连接在一起 — 所有这些都没有以 XML 形式提供任何 bean 配置元数据。AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
您可以通过添加
的值为 .AutowiredAnnotationBeanPostProcessor CommonAnnotationBeanPostProcessor annotation-config false |
为简洁起见,前面的示例可以使用
注释(即 )。value @ComponentScan("org.example") |
使用 隐式启用 的功能。使用 .<context:component-scan> <context:annotation-config> <context:annotation-config> <context:component-scan> |
扫描 classpath 包需要存在相应的目录 条目。使用 Ant 构建 JAR 时,请确保不要 激活 JAR 任务的 files-only 开关。此外,类路径目录可能不是 在某些环境中根据安全策略公开,例如,独立应用程序 JDK 1.7.0_45 及更高版本(需要在清单中设置“Trusted-Library”——请参阅 stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources)。 在 JDK 9 的模块路径(拼图)上, Spring 的 Classpath 扫描通常按预期工作。
但是,请确保在 Descriptors 中导出组件类。如果你希望 Spring 调用类的非公共成员,请将
确保它们已“打开”(即,它们在描述符中使用声明而不是声明)。 |
您可以通过添加
的值为 .AutowiredAnnotationBeanPostProcessor CommonAnnotationBeanPostProcessor annotation-config false |
使用过滤器自定义扫描
默认情况下,使用 、 、 、 或 本身使用 Comments 的自定义 Comments 的类是
唯一检测到的候选组件。但是,您可以修改和扩展此行为
通过应用自定义筛选器。将它们添加为 或 属性
注释(或 AS 或元素的子元素
XML 配置)。每个 filter 元素都需要 and 属性。
下表描述了筛选选项:@Component
@Repository
@Service
@Controller
@Configuration
@Component
includeFilters
excludeFilters
@ComponentScan
<context:include-filter />
<context:exclude-filter />
<context:component-scan>
type
expression
过滤器类型 | 示例表达式 | 描述 |
---|---|---|
annotation (默认) |
|
目标组件中类型级别存在或元存在的 Annotation。 |
可分配的 |
|
目标组件可分配给 (扩展或实现) 的类 (或接口) 。 |
AspectJ |
|
要由目标组件匹配的 AspectJ 类型表达式。 |
正则表达式 |
|
要与目标组件的类名称匹配的正则表达式。 |
习惯 |
|
接口的自定义实现。 |
以下示例显示了忽略所有注释的配置
并使用 “stub” 存储库:@Repository
-
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:
<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>
您还可以通过在
注解或通过作为元素的属性提供。这实际上禁用了类的自动检测
使用 、、、、 或 进行批注或元批注。useDefaultFilters=false use-default-filters="false" <component-scan/> @Component @Repository @Service @Controller @RestController @Configuration |
过滤器类型 | 示例表达式 | 描述 |
---|---|---|
annotation (默认) |
|
目标组件中类型级别存在或元存在的 Annotation。 |
可分配的 |
|
目标组件可分配给 (扩展或实现) 的类 (或接口) 。 |
AspectJ |
|
要由目标组件匹配的 AspectJ 类型表达式。 |
正则表达式 |
|
要与目标组件的类名称匹配的正则表达式。 |
习惯 |
|
接口的自定义实现。 |
您还可以通过在
注解或通过作为元素的属性提供。这实际上禁用了类的自动检测
使用 、、、、 或 进行批注或元批注。useDefaultFilters=false use-default-filters="false" <component-scan/> @Component @Repository @Service @Controller @RestController @Configuration |
在组件中定义 Bean 元数据
Spring 组件还可以向容器提供 bean 定义元数据。你可以做
这与用于定义 Comments 类中的 Bean 元数据的 Comments 相同。以下示例显示了如何执行此操作:@Bean
@Configuration
-
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 组件,其方法中包含特定于应用程序的代码。但是,它还提供了一个 bean 定义,该定义具有 factory
方法引用方法 。注释标识
Factory 方法和其他 Bean 定义属性,例如通过
注释。可以指定的其他方法级注释包括 、 和 自定义限定符注释。doWork()
publicInstance()
@Bean
@Qualifier
@Scope
@Lazy
除了其在组件初始化中的作用外,您还可以将注释放置在标有 或 的注入点上。在此上下文中,
它会导致注入延迟分辨率代理。但是,这种代理方法
相当有限。用于复杂的惰互,特别是组合
对于可选依赖项,我们建议改用。@Lazy @Autowired @Inject ObjectProvider<MyTargetBean> |
如前所述,支持自动装配的字段和方法,并带有额外的
支持方法的自动装配。以下示例显示了如何执行此操作:@Bean
-
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)
}
该示例将 method 参数自动连接到另一个名为 .Spring Expression Language 元素
通过表示法定义属性的值 。对于 Comments,表达式解析器被预先配置为在
解析表达式文本。String
country
age
privateInstance
#{ <expression> }
@Value
从 Spring Framework 4.3 开始,您还可以将类型(或其更具体的子类:)的工厂方法参数声明为
访问触发当前 Bean 创建的请求注入点。
请注意,这仅适用于 bean 实例的实际创建,而不适用于
注入现有实例。因此,此功能最适合
prototype 范围的 bean。对于其他作用域,工厂方法只看到
触发在给定范围内创建新 bean 实例的注入点
(例如,触发创建惰性单例 Bean 的依赖项)。
在这种情况下,您可以谨慎使用提供的注入点元数据。
以下示例演示如何使用:InjectionPoint
DependencyDescriptor
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 组件中的方法的处理方式与它们的
对应的 Spring 类中。区别在于,类没有使用 CGLIB 进行增强以拦截方法和字段的调用。
CGLIB 代理是调用方法或方法中的字段的方法
IN CLASSES 创建对协作对象的 Bean 元数据引用。
这些方法不是用普通的 Java 语义调用的,而是通过
container 来提供 Spring 的通常生命周期管理和代理
bean,即使通过对方法的编程调用引用其他 bean 也是如此。
相比之下,在普通类中调用方法中的方法或字段具有标准的 Java 语义,没有特殊的 CGLIB 处理或其他
约束适用。@Bean
@Configuration
@Component
@Bean
@Configuration
@Bean
@Bean
@Component
您可以将方法声明为 ,允许在没有
创建其包含的 Configuration 类作为实例。这使得特别
sense 在定义后处理器 bean(例如,type 或 )时,因为这样的 bean 在容器的早期就被初始化了
生命周期,并且应避免在此时触发配置的其他部分。 由于技术原因,对静态方法的调用永远不会被容器拦截,即使在类中也不会(如本节前面所述)。
限制: CGLIB 子类化只能覆盖非静态方法。因此,
对另一个方法的直接调用具有标准的 Java 语义,从而
在直接从工厂方法本身返回的独立实例中。 方法的 Java 语言可见性不会对
Spring 容器中生成的 bean 定义。您可以自由地声明您的
你认为适合 non- classes 和 static 的 factory 方法
方法。但是,类中的常规方法需要
才能被覆盖 — 也就是说,它们不能被声明为 或 。
最后,单个类可以包含多个方法
bean,作为多个工厂方法的安排,根据可用情况使用
运行时的依赖项。这与选择“最贪婪”的算法相同
constructor 或 factory 方法:具有
在构造时选择最大数量的 satisfiable dependencies,
类似于容器在多个构造函数之间进行选择的方式。 |
除了其在组件初始化中的作用外,您还可以将注释放置在标有 或 的注入点上。在此上下文中,
它会导致注入延迟分辨率代理。但是,这种代理方法
相当有限。用于复杂的惰互,特别是组合
对于可选依赖项,我们建议改用。@Lazy @Autowired @Inject ObjectProvider<MyTargetBean> |
您可以将方法声明为 ,允许在没有
创建其包含的 Configuration 类作为实例。这使得特别
sense 在定义后处理器 bean(例如,type 或 )时,因为这样的 bean 在容器的早期就被初始化了
生命周期,并且应避免在此时触发配置的其他部分。 由于技术原因,对静态方法的调用永远不会被容器拦截,即使在类中也不会(如本节前面所述)。
限制: CGLIB 子类化只能覆盖非静态方法。因此,
对另一个方法的直接调用具有标准的 Java 语义,从而
在直接从工厂方法本身返回的独立实例中。 方法的 Java 语言可见性不会对
Spring 容器中生成的 bean 定义。您可以自由地声明您的
你认为适合 non- classes 和 static 的 factory 方法
方法。但是,类中的常规方法需要
才能被覆盖 — 也就是说,它们不能被声明为 或 。
最后,单个类可以包含多个方法
bean,作为多个工厂方法的安排,根据可用情况使用
运行时的依赖项。这与选择“最贪婪”的算法相同
constructor 或 factory 方法:具有
在构造时选择最大数量的 satisfiable dependencies,
类似于容器在多个构造函数之间进行选择的方式。 |
命名自动检测到的组件
当组件在扫描过程中被自动检测时,其 Bean 名称为
由该扫描程序已知的策略生成。BeanNameGenerator
默认情况下,使用 the 。对于 Spring 构造型 Comments,
如果您通过 Annotation 的属性提供 name,则该 name 将用作
相应 bean 定义中的名称。此约定也适用于
使用以下 JSR-250 和 JSR-330 注释来代替 Spring 构造型
注释:、、 和 .AnnotationBeanNameGenerator
value
@jakarta.annotation.ManagedBean
@javax.annotation.ManagedBean
@jakarta.inject.Named
@javax.inject.Named
从 Spring Framework 6.1 开始,用于指定
bean 名称不再需要为 。自定义构造型注释可以
声明具有不同名称 ((如 ) 的属性) 并注释该属性
跟。查看源代码
声明 of 作为一个具体的例子。value
name
@AliasFor(annotation = Component.class, attribute = "value")
ControllerAdvice#name()
从 Spring Framework 6.1 开始,不推荐使用基于约定的原型名称
,并将在框架的未来版本中删除。因此,自定义 stereotype
注解 must use 来声明属性的显式别名
在。有关具体示例,请参阅 和 的源代码声明。 |
如果无法从此类 Comments 或任何其他 Comments 派生显式 bean 名称
detected 组件(例如自定义过滤器发现的组件),则默认 bean 名称
generator 返回未大写的非限定类名。例如,如果
检测到以下组件类,名称为 和 。myMovieLister
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
接口,并确保包含一个默认的 no-arg 构造函数。然后,提供完整的
限定的类名,如以下示例注释
和 bean 定义显示。
如果由于多个自动检测到的组件具有
相同的非限定类名(即,具有相同名称但驻留在
不同的软件包),你可能需要配置一个,默认为
生成的 Bean 名称的完全限定类名。从 Spring Framework 5.2.3 开始,位于 package 中可用于此类目的。BeanNameGenerator FullyQualifiedAnnotationBeanNameGenerator org.springframework.context.annotation |
-
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>
作为一般规则,请考虑在使用 Comments 指定名称时,每当其他 组件可能会显式引用它。另一方面, 每当容器负责 wiring 时,自动生成的名称就足够了。
从 Spring Framework 6.1 开始,不推荐使用基于约定的原型名称
,并将在框架的未来版本中删除。因此,自定义 stereotype
注解 must use 来声明属性的显式别名
在。有关具体示例,请参阅 和 的源代码声明。 |
如果由于多个自动检测到的组件具有
相同的非限定类名(即,具有相同名称但驻留在
不同的软件包),你可能需要配置一个,默认为
生成的 Bean 名称的完全限定类名。从 Spring Framework 5.2.3 开始,位于 package 中可用于此类目的。BeanNameGenerator FullyQualifiedAnnotationBeanNameGenerator org.springframework.context.annotation |
为自动检测的组件提供范围
与一般的 Spring 管理组件一样,默认和最常见的
autodetected components 为 。但是,有时您需要不同的范围
这可以通过 Annotation 指定。您可以提供
范围,如下例所示:singleton
@Scope
-
Java
-
Kotlin
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
@Scope("prototype")
@Repository
class MovieFinderImpl : MovieFinder {
// ...
}
@Scope 注解仅在具体的 Bean 类上被内省(对于带注解的
组件)或工厂方法(用于方法)。与 XML Bean 相比
定义,没有 bean 定义继承的概念,而继承
类级别的层次结构与元数据目的无关。@Bean |
有关 Spring 上下文中特定于 Web 的范围(例如“request”或“session”)的详细信息,
请参阅 Request、Session、Application 和 WebSocket 范围。与这些范围的预构建注释一样,
您还可以使用 Spring 的元注释编写自己的范围注释
方法:例如,使用 、
也可能声明自定义范围代理模式。@Scope("prototype")
要为范围解析提供自定义策略,而不是依赖
基于注释的方法,您可以实现 ScopeMetadataResolver 接口。请务必包含默认的 no-arg 构造函数。然后,您可以提供
完全限定的类名,如以下示例所示
注释和 bean 定义显示: |
-
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>
当使用某些非单例作用域时,可能需要为
scoped 对象。原因在 Scoped Bean as Dependencies 中进行了描述。
为此,component-scan 上提供了 scoped-proxy 属性
元素。三个可能的值是:、 和 。例如
以下配置将生成标准 JDK 动态代理:no
interfaces
targetClass
-
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>
@Scope 注解仅在具体的 Bean 类上被内省(对于带注解的
组件)或工厂方法(用于方法)。与 XML Bean 相比
定义,没有 bean 定义继承的概念,而继承
类级别的层次结构与元数据目的无关。@Bean |
要为范围解析提供自定义策略,而不是依赖
基于注释的方法,您可以实现 ScopeMetadataResolver 接口。请务必包含默认的 no-arg 构造函数。然后,您可以提供
完全限定的类名,如以下示例所示
注释和 bean 定义显示: |
提供带有注释的限定符元数据
Fine-tuning Annotation-based Autowiring with Qualifiers中讨论了该注解。
该部分中的示例演示了 annotation 和
自定义限定符注释,用于在解析 autowire 时提供精细控制
候选人。因为这些示例是基于 XML Bean 定义的,所以限定符
通过使用 XML 中元素的 or 子元素,在候选 Bean 定义上提供元数据。当依赖 Classpath 扫描
自动检测组件,则可以提供类型级
Candidate 类的注释。以下三个示例演示了这一点
技术:@Qualifier
@Qualifier
qualifier
meta
bean
-
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 {
// ...
}
与大多数基于 Comments 的替代方案一样,请记住,Comments 元数据是 绑定到类定义本身,而 XML 的使用允许多个 bean 的 SAME 类型在其限定符元数据中提供变体,因为 元数据是按实例而不是按类提供的。 |
与大多数基于 Comments 的替代方案一样,请记住,Comments 元数据是 绑定到类定义本身,而 XML 的使用允许多个 bean 的 SAME 类型在其限定符元数据中提供变体,因为 元数据是按实例而不是按类提供的。 |