自定义注解
自定义注解 @MovieQualifier
,它是基于 Spring 的 @Qualifier
注解之上的一个扩展。通过 元注解 和自定义属性(genre
和 format
)来实现精确的依赖注入。
自定义注解的定义
@MovieQualifier
是一个 自定义的注解,它通过标注 @Qualifier
来继承了 @Qualifier
的功能,同时扩展了其能力。
@Target({ElementType.FIELD, ElementType.PARAMETER}) // 允许注解作用于字段或参数
@Retention(RetentionPolicy.RUNTIME) // 运行时保留此注解
@Qualifier // 声明这是一个扩展自 @Qualifier 的注解
public @interface MovieQualifier {
String genre(); // 定义一个名为 "genre" 的属性
Format format(); // 定义一个名为 "format" 的枚举类型属性
}
解读代码:
@Target
:定义了注解可以作用的范围。在这里,允许@MovieQualifier
用于字段(FIELD
)和参数(PARAMETER
)。@Retention
:定义了注解的生命周期。在这里,RUNTIME
表明注解在运行时仍然保留,可供反射使用。@Qualifier
:继承了 Spring 的@Qualifier
特性,使这个注解可以参与 Spring 的依赖注入流程。- 自定义属性:
genre
:一个字符串,用于描述电影的类型(如 “Action”、“Comedy”)。format
:一个枚举类型,用于描述电影的格式,比如是 2D、3D 等。
使用自定义 @MovieQualifier
的场景
我们可以用这个注解来标识特定的Bean,并在注入时通过提供对应的 genre
和 format
值来精确匹配。
示例:定义多个符合条件的Bean
import org.springframework.stereotype.Component;
@Component
@MovieQualifier(genre = "Action", format = Format.DIGITAL)
public class ActionDigitalMovie implements Movie {
// Bean 示例
}
@Component
@MovieQualifier(genre = "Comedy", format = Format.DVD)
public class ComedyDvdMovie implements Movie {
// Bean 示例
}
在这里,我们定义了两个实现类 ActionDigitalMovie
和 ComedyDvdMovie
,并通过 @MovieQualifier
注解分别标注了 genre
和 format
的属性值。
示例:使用 @MovieQualifier
进行注入
public class MovieService {
@Autowired
@MovieQualifier(genre = "Action", format = Format.DIGITAL)
private Movie actionMovie;
@Autowired
@MovieQualifier(genre = "Comedy", format = Format.DVD)
private Movie comedyMovie;
public void playMovies() {
actionMovie.play();
comedyMovie.play();
}
}
运行时注入逻辑:
- Spring 会扫描到
@MovieQualifier
注解中的属性(如genre = "Action"
和format = Format.DIGITAL
)。 - 通过这些属性值,Spring 在容器中查找标识为
@MovieQualifier(genre = "Action", format = Format.DIGITAL)
的Bean。 - 匹配成功后,将对应的
ActionDigitalMovie
注入到actionMovie
字段中。
为什么可以不带参数?
实际上 @MovieQualifier
本身的属性(genre
和 format
)就是用于自定义精确匹配规则的参数。如果你省略了这些属性值,Spring 无法匹配到具体的Bean,会导致注入失败。
错误示例
@Autowired
@MovieQualifier // 没有参数,Spring 无法识别要注入的Bean
private Movie movie;
Spring 会抛出类似下面的异常:
No qualifying bean of type 'Movie' available: expected single matching bean but found 2.
原因是 @MovieQualifier
的属性(genre
和 format
)是注解的 必填项,你必须提供它们的值,否则 Spring 无法辨别要注入哪个Bean。
如何改进?
如果确实希望 @MovieQualifier
能够不带参数,可以为其属性定义默认值。但请注意,这可能导致歧义,因为默认值可能与多个Bean匹配。
示例:为属性提供默认值
public @interface MovieQualifier {
String genre() default "Action"; // 默认值为 "Action"
Format format() default Format.DIGITAL; // 默认值为 Format.DIGITAL
}
使用示例
@Autowired
@MovieQualifier // 没有参数,默认使用 genre = "Action", format = Format.DIGITAL
private Movie movie;
总结
- 自定义
@MovieQualifier
是@Qualifier
的扩展版本,通过增加属性(如genre
和format
),可以实现更精确的依赖注入。 - 如果不带参数,Spring 无法通过
@MovieQualifier
的属性值匹配Bean,注入就会失败。 - 可以通过为注解的属性设置默认值来支持不带参数的使用,但默认值可能会引起歧义,需要谨慎设计。