spring-jsr/spring-jsr330-qualifier/README.md
✒️ 作者 - Lex 📝 博客 - 我的CSDN 📚 文章目录 - 所有文章 🔗 源码地址 - @Qualifier源码
@Qualifier 注解是 Java 的标准注解,来源于 JSR 330: Dependency Injection for Java。主要用于解决依赖注入中的歧义性,当有多个同类型的 bean 或实例可供选择时,指导容器明确选择哪一个进行注入。
@Qualifier 表示它是一个基础注解,主要用于创建其他的自定义注解,这些新的注解通常用于限定和解决依赖注入时的歧义性。这与 Spring 和 JSR 330 中 @Qualifier 的定义和目的是一致的。
@Target({ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Qualifier {
}
@Qualifier 用于指定哪一个具体的 bean 应该被注入。@Autowired 和 @Inject 配合使用
org.springframework.beans.factory.annotation.Qualifier 通常与 org.springframework.beans.factory.annotation.Autowired 配合使用。这是为了从Spring容器中解析bean时解决歧义。javax.inject.Qualifier 是一个元注解,用于定义新的注解作为限定符。这些自定义的限定符注解然后可以与 javax.inject.Inject 配合使用,以解决歧义。@Qualifier 用于创建其他自定义注解,这些新定义的注解随后可以用作限定符。@Qualifier 或基于它的自定义注解,代码更具有描述性,更容易理解应注入哪个特定的 bean。首先来看看启动类入口,上下文环境使用AnnotationConfigApplicationContext(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个MyConfiguration组件类。然后从Spring上下文中获取一个MyController类型的bean并调用了showMessage方法。
public class QualifierApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
MessageController messageController = context.getBean(MessageController.class);
messageController.showMessage();
}
}
在MyConfiguration类中,使用了@ComponentScan("com.xcs.spring")注解告诉 Spring 在指定的包(在这里是 "com.xcs.spring")及其子包中搜索带有 @Component、@Service、@Repository 和 @Controller 等注解的类,并将它们自动注册为 beans。这样,spring就不必为每个组件明确写一个 bean 定义。Spring 会自动识别并注册它们。
@Configuration
@ComponentScan("com.xcs.spring")
public class MyConfiguration {
}
我们定义了两个自定义注解,@Email 和 @SMS,它们都被标记为 @Qualifier。这意味着它们都可以被用作限定符注解。
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Email {
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface SMS {
}
EmailServiceImpl & SMSServiceImpl这两个类都实现了 MessageService 接口,但分别带有 @Email 和 @SMS 限定符注解,意味着它们在被注入时可以被明确区分。
public interface MessageService {
String getMessage();
}
@Email
@Named
public class EmailServiceImpl implements MessageService {
@Override
public String getMessage() {
return "Email message";
}
}
@SMS
@Named
public class SMSServiceImpl implements MessageService {
@Override
public String getMessage() {
return "SMS message";
}
}
MessageController 注入了两种 MessageService 的实现:一种用于Email,另一种用于SMS。通过使用自定义的限定符注解 @Email 和 @SMS,确保了正确的服务实现被注入到对应的字段中。showMessage 方法用于显示这两个服务实现返回的消息。
@Controller
public class MessageController {
@Inject
@Email
private MessageService emailService;
@Inject
@SMS
private MessageService smsService;
public void showMessage() {
System.out.println("EmailService: " + emailService.getMessage());
System.out.println("SMSService: " + smsService.getMessage());
}
}
运行结果发现,@Email 限定符确保了 EmailServiceImpl 被注入到 emailService 字段。@SMS 限定符确保了 SMSServiceImpl 被注入到 smsService 字段。@Qualifier 注解在这里起到了关键的作用,确保了正确的服务实现被注入,从而使得运行结果符合预期。
EmailService: Email message
SMSService: SMS message
sequenceDiagram
Title: @Qualifier注册时序图
QualifierApplication->>AnnotationConfigApplicationContext:AnnotationConfigApplicationContext(componentClasses)
Note over AnnotationConfigApplicationContext: 上下文初始化开始,传入了一些组件类
AnnotationConfigApplicationContext->>AnnotationConfigApplicationContext:AnnotationConfigApplicationContext()
Note over AnnotationConfigApplicationContext: 上下文构造器调用
AnnotationConfigApplicationContext->>AnnotatedBeanDefinitionReader:AnnotatedBeanDefinitionReader(registry)
Note over AnnotatedBeanDefinitionReader: 为给定的注册中心创建一个Bean定义读取器
AnnotatedBeanDefinitionReader->>AnnotatedBeanDefinitionReader:AnnotatedBeanDefinitionReader(registry,environment)
Note over AnnotatedBeanDefinitionReader: 读取器构造器使用特定的环境设置
AnnotatedBeanDefinitionReader->>AnnotationConfigUtils:registerAnnotationConfigProcessors(registry)
Note over AnnotationConfigUtils: 注册注解配置处理器
AnnotationConfigUtils->>AnnotationConfigUtils:registerAnnotationConfigProcessors(registry,source)
Note right of AnnotationConfigUtils: 注册注解配置处理器
AnnotationConfigUtils->>QualifierAnnotationAutowireCandidateResolver:QualifierAnnotationAutowireCandidateResolver()
Note over QualifierAnnotationAutowireCandidateResolver: 创建一个新的限定符自动装配候选解析器
QualifierAnnotationAutowireCandidateResolver->>QualifierAnnotationAutowireCandidateResolver:this.qualifierTypes.add("javax.inject.Qualifier");
Note right of QualifierAnnotationAutowireCandidateResolver: 添加javax.inject.Qualifier到限定符类型列表
QualifierAnnotationAutowireCandidateResolver->>AnnotationConfigUtils:返回Resolver
Note right of AnnotationConfigUtils: 解析器创建完毕,现在返回给调用者
AnnotationConfigUtils->>DefaultListableBeanFactory:setAutowireCandidateResolver(autowireCandidateResolver)
Note over DefaultListableBeanFactory: 在Bean工厂中设置自动装配候选解析器
sequenceDiagram
Title: @Qualifier解析时序图
InjectionMetadata->>AutowiredFieldElement:inject(bean,beanName,pvs)
Note over AutowiredFieldElement: 开始注入字段
AutowiredFieldElement->>AutowiredFieldElement:resolveFieldValue(field, bean, beanName)
Note over AutowiredFieldElement: 尝试解析字段的值
AutowiredFieldElement->>DefaultListableBeanFactory:resolveDependency(desc,beanName,autowiredBeanNames,typeConverter)
Note over DefaultListableBeanFactory: 解决字段的依赖关系
DefaultListableBeanFactory->>DefaultListableBeanFactory:doResolveDependency(descriptor,requestingBeanName,autowiredBeanNames,typeConverter)
Note over DefaultListableBeanFactory: 执行依赖解析
DefaultListableBeanFactory->>DefaultListableBeanFactory:findAutowireCandidates(beanName,type,descriptor)
Note over DefaultListableBeanFactory: 查找可能的自动装配候选者
DefaultListableBeanFactory->>DefaultListableBeanFactory:isAutowireCandidate(candidate,descriptor)
Note over DefaultListableBeanFactory: 检查候选bean是否是合适的自动装配候选者
DefaultListableBeanFactory->>DefaultListableBeanFactory:isAutowireCandidate(beanName,descriptor,resolver)
Note right of DefaultListableBeanFactory: 进一步检查,使用解析器
DefaultListableBeanFactory->>DefaultListableBeanFactory:isAutowireCandidate(beanName,mbd,descriptor,resolver)
Note right of DefaultListableBeanFactory: 使用给定的bean定义进一步检查
DefaultListableBeanFactory->>QualifierAnnotationAutowireCandidateResolver:isAutowireCandidate(holder, descriptor)
Note over QualifierAnnotationAutowireCandidateResolver: 判断是否根据@Qualifier注解是自动装配的候选者
QualifierAnnotationAutowireCandidateResolver->>QualifierAnnotationAutowireCandidateResolver:checkQualifiers(bdHolder,annotationsToSearch)
Note over QualifierAnnotationAutowireCandidateResolver: 检查所有相关的限定符注解
QualifierAnnotationAutowireCandidateResolver->>QualifierAnnotationAutowireCandidateResolver:isQualifier(annotationType)
Note over QualifierAnnotationAutowireCandidateResolver: 判断给定的注解类型是否是一个有效的限定符
首先来看看启动类入口,上下文环境使用AnnotationConfigApplicationContext(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个MyConfiguration组件类。然后从Spring上下文中获取一个MyController类型的bean并调用了showMessage方法。
public class QualifierApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
MessageController messageController = context.getBean(MessageController.class);
messageController.showMessage();
}
}
在org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext构造函数中,执行了三个步骤,我们本次重点关注this()。
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
在org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext()方法中,初始化了的两个核心组件,一个用于读取注解定义的bean (AnnotatedBeanDefinitionReader)也是本次重点分析的内容,另一个用于扫描类路径并自动检测bean组件 (ClassPathBeanDefinitionScanner)。
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
在org.springframework.context.annotation.AnnotatedBeanDefinitionReader#AnnotatedBeanDefinitionReader(registry)方法中,又调用了另一个构造函数。
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
在org.springframework.context.annotation.AnnotatedBeanDefinitionReader#AnnotatedBeanDefinitionReader(registry,environment)方法中,这是一个重要的调用registerAnnotationConfigProcessors,会向容器注册一系列的后置处理器,这些后置处理器对于处理各种注解(如 @Inject, @Qualifier等)至关重要。
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
在org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(registry)方法中,又调用了另外一个重载的方法。
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
在org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(registry,source)方法中,在 Spring 的自动装配机制中,当有多个候选bean可以被注入到某个位置时,需要有一个方式来解决哪个bean是最佳的候选者。AutowireCandidateResolver 就是用来做这个决策的。
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
// ... [代码部分省略以简化]
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
// ... [代码部分省略以简化]
}
在org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#QualifierAnnotationAutowireCandidateResolver()方法中,目的是为解析器设置一些基本配置。其中最重要的部分是尝试加载 JSR-330 的 @Qualifier 注解,并将其添加到 qualifierTypes 集合中,以便在后续的依赖注入过程中能够正确处理这个注解。如果 JSR-330 不可用,解析器会简单地跳过这个步骤。
public QualifierAnnotationAutowireCandidateResolver() {
// ... [代码部分省略以简化]
try {
this.qualifierTypes.add((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Qualifier",
QualifierAnnotationAutowireCandidateResolver.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
在Spring中,AutowiredAnnotationBeanPostProcessor 负责处理多种依赖注入注解,包括 JSR-330 的 @Inject 注解。为了深入了解 @Inject 注解及其与 @Qualifier 注解的结合方式,研究这个后处理器是至关重要的。简而言之,为了完全掌握 @Inject 和 @Qualifier 的协同工作原理,深入阅读 @Inject 博客是非常必要的。这些博客为我们提供了对如何在 bean 生命周期中的关键阶段处理这些注解的深入理解。
@Inject 注解的背后原理。从 JSR-330 规范的引入,到如何在 Spring 中正确使用,以及与其他注解如 @Autowired 的差异,这篇博客为我们提供了全面的视角。在org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency方法中,首先尝试获取一个延迟解析代理。如果无法获得,它会进一步尝试解析依赖。doResolveDependency 是实际进行解析工作的方法。
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// ... [代码部分省略以简化]
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
在org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency方法中,主要目的是解析给定的依赖描述符 (DependencyDescriptor),并尝试找到一个合适的 bean 来满足这个依赖。
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// ... [代码部分省略以简化]
try {
// ... [代码部分省略以简化]
// 步骤1. 根据依赖描述符查找匹配的bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
// ... [代码部分省略以简化]
}
// ... [代码部分省略以简化]
}
在org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates方法中,首先基于给定的类型获取所有可能的bean名。接着,对于每一个可能的候选bean,它检查该bean是否是一个合适的自动注入候选,如果是,它将这个bean添加到结果集中。最后,方法返回找到的所有合适的候选bean。
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 根据所需的类型,包括所有父工厂中的bean,获取所有可能的bean名
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
// ... [代码部分省略以简化]
// 遍历所有候选bean名
for (String candidate : candidateNames) {
// 如果候选bean不是正在查找的bean本身并且它是一个合适的自动注入候选
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
// 添加这个候选bean到结果中
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// ... [代码部分省略以简化]
// 返回找到的所有候选bean
return result;
}
在org.springframework.beans.factory.support.DefaultListableBeanFactory#isAutowireCandidate(beanName, descriptor)方法中,首先是调用 getAutowireCandidateResolver() 方法时,我们会得到这里设置的那个解析器,会根据其实现来决定哪个 bean 是自动装配的候选者,尤其当存在多个可能的候选者时,会考虑到 @Qualifier 和其他相关的注解,然后会进一步调用 isAutowireCandidate 的另一个重载版本,并且会传入解析器。
@Override
public boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)
throws NoSuchBeanDefinitionException {
return isAutowireCandidate(beanName, descriptor, getAutowireCandidateResolver());
}
在org.springframework.beans.factory.support.DefaultListableBeanFactory#isAutowireCandidate(beanName,descriptor,resolver)方法中,首先是调用getMergedLocalBeanDefinition(bdName)来获取被依赖Bean的定义, 然后会进一步调用 isAutowireCandidate 的另一个重载版本,并且会传入合并的 bean 定义。
protected boolean isAutowireCandidate(
String beanName, DependencyDescriptor descriptor, AutowireCandidateResolver resolver)
throws NoSuchBeanDefinitionException {
String bdName = BeanFactoryUtils.transformedBeanName(beanName);
if (containsBeanDefinition(bdName)) {
return isAutowireCandidate(beanName, getMergedLocalBeanDefinition(bdName), descriptor, resolver);
}
// ... [代码部分省略以简化]
}
在org.springframework.beans.factory.support.DefaultListableBeanFactory#isAutowireCandidate(beanName, mbd,descriptor, resolver)方法中,首先是初始化了一个BeanDefinitionHolder,这是一个方便的数据结构,用于同时持有 BeanDefinition, bean 的名称和别名。这对于解析自动装配候选项很有用,因为有时我们需要知道 bean 的名称和别名,然后会进一步调用解析器的 isAutowireCandidate 方法,并且会传入BeanDefinitionHolder与依赖描述符 。
protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd,
DependencyDescriptor descriptor, AutowireCandidateResolver resolver) {
// ... [代码部分省略以简化]
BeanDefinitionHolder holder = (beanName.equals(bdName) ?
this.mergedBeanDefinitionHolders.computeIfAbsent(beanName,
key -> new BeanDefinitionHolder(mbd, beanName, getAliases(bdName))) :
new BeanDefinitionHolder(mbd, beanName, getAliases(bdName)));
return resolver.isAutowireCandidate(holder, descriptor);
}
在org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#isAutowireCandidate方法中,主要目的是增强了对 @Qualifier 注解的支持。如果一个bean或依赖被 @Qualifier 注解,并指定了一个bean的名称,那么只有名称匹配的bean会被认为是自动装配的候选者。如果没有指定名称,但指定了其他属性或元注解,那么只有匹配这些属性或元注解的bean会被认为是自动装配的候选者。
@Override
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
// 首先通过父类的方法进行基本的匹配检查。
boolean match = super.isAutowireCandidate(bdHolder, descriptor);
// 如果基本检查通过,则进一步检查 bdHolder 和 descriptor 中的注解是否匹配。
if (match) {
// 检查候选bean的资格符与依赖描述符的注解是否匹配。
match = checkQualifiers(bdHolder, descriptor.getAnnotations());
if (match) {
// 获取与依赖相关的方法参数(如果有的话,例如当依赖是一个setter方法的参数时)。
MethodParameter methodParam = descriptor.getMethodParameter();
// 如果有关联的方法参数,则进行进一步的检查。
if (methodParam != null) {
Method method = methodParam.getMethod();
// 如果方法是void返回类型(如setter方法),则检查它的注解与候选bean的资格符是否匹配。
if (method == null || void.class == method.getReturnType()) {
match = checkQualifiers(bdHolder, methodParam.getMethodAnnotations());
}
}
}
}
// 返回最终的匹配结果。
return match;
}
在org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#checkQualifiers方法中,主要目的是确保待注入的bean与所有相关的 @Qualifier 注解和元注解匹配。如果其中一个注解或元注解与bean定义不匹配,那么这个bean就不是当前注入点的合适候选。
protected boolean checkQualifiers(BeanDefinitionHolder bdHolder, Annotation[] annotationsToSearch) {
// 如果注解数组为空,直接返回 true
if (ObjectUtils.isEmpty(annotationsToSearch)) {
return true;
}
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
for (Annotation annotation : annotationsToSearch) {
Class<? extends Annotation> type = annotation.annotationType();
boolean checkMeta = true;
boolean fallbackToMeta = false;
// 检查当前注解是否是 @Qualifier 或自定义的资格符注解
if (isQualifier(type)) {
// 如果是,并且与bean定义匹配
if (!checkQualifier(bdHolder, annotation, typeConverter)) {
// 不匹配则可能需要检查元注解
fallbackToMeta = true;
} else {
// 匹配则不需要进一步检查元注解
checkMeta = false;
}
}
// 如果不是资格符注解或与bean定义不匹配,但有元注解是资格符注解
if (checkMeta) {
boolean foundMeta = false;
for (Annotation metaAnn : type.getAnnotations()) {
Class<? extends Annotation> metaType = metaAnn.annotationType();
// 检查元注解是否是资格符注解
if (isQualifier(metaType)) {
foundMeta = true;
// 只有当 @Qualifier 注解有值或其他条件满足时,才会接受元注解的匹配
if ((fallbackToMeta && ObjectUtils.isEmpty(AnnotationUtils.getValue(metaAnn))) ||
!checkQualifier(bdHolder, metaAnn, typeConverter)) {
// 元注解不匹配
return false;
}
}
}
if (fallbackToMeta && !foundMeta) {
return false; // 需要元注解,但没有找到
}
}
}
// 所有注解都匹配
return true;
}
在org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#isQualifier方法中,主要目的是确定给定的注解是否为一个"资格符"注解,也就是我们通常所说的限定符注解,如@Qualifier。这是通过检查注解是否存在于已知的qualifierTypes集合中,或者它是否带有这些资格符注解来完成的。
protected boolean isQualifier(Class<? extends Annotation> annotationType) {
// 遍历已知的资格符注解类型
for (Class<? extends Annotation> qualifierType : this.qualifierTypes) {
// 如果给定的注解是已知的资格符注解,或者它带有这样的元注解
if (annotationType.equals(qualifierType) || annotationType.isAnnotationPresent(qualifierType)) {
return true; // 是资格符注解
}
}
return false; // 不是资格符注解
}
@Qualifier 主要是为了解决Spring容器中有多个同类型Bean的问题。没有 @Qualifier,Spring将无法决定注入哪一个Bean。但使用 @Qualifier 时,我们需要确保给定的资格符名称确实存在,否则Spring会抛出异常。@Qualifier 通常与 @Autowired 或 @Inject 一起使用。确保在正确的地方使用它(字段、setter方法或构造函数)。@Qualifier 作为元注解。这样,我们可以创建具有特定命名或其他语义的资格符注解,使代码更具可读性。@Qualifier 默认使用字符串值来指定Bean的名称。这意味着,如果我们重命名了Bean或更改了其名称,我们也需要更改所有使用这个Bean名称的 @Qualifier 注解。@Bean 的方法名称作为资格符名称。这使得使用Java配置和 @Qualifier 更为一致。@Primary 的关系
@Primary 和 @Qualifier,则 @Qualifier 的优先级更高。也就是说,如果一个Bean被标记为 @Primary,但在注入点使用了 @Qualifier,则会使用 @Qualifier 指定的Bean。@Qualifier 主要用于通过名称进行匹配,但Spring仍然会验证匹配的Bean类型。所以,如果Bean名称匹配但类型不匹配,仍然会出现异常。@Qualifier 注解与JSR-330(Java的依赖注入规范)中的 javax.inject.Qualifier 注解兼容。但是,当使用JSR-330标准时,确保依赖注入提供程序(如Spring)正确支持它。AnnotationConfigApplicationContext 作为Spring容器,并通过构造参数指定配置类,使得Spring容器初始化过程清晰明了。@ComponentScan 注解,自动扫描指定包及其子包中的组件,减少了手动注册bean的工作,使代码更简洁、高效。@Email 和 @SMS 两个自定义限定符注解。这使得代码更有可读性,并提供了更明确的注入意图。MessageController 中,使用了自定义的 @Email 和 @SMS 注解与 @Inject 组合,确保了正确的 MessageService 实现被注入到相应的字段。showMessage 方法的输出,我们可以清晰地看到 @Qualifier 的作用,确保了不同的服务实现被正确注入。@Configuration 和 @ComponentScan,结合Java配置,Spring容器的初始化和bean的注册过程都变得更加直观和简洁。@Qualifier 作为元注解,自定义注解的方式体现了Spring的灵活性和注解的扩展性。AnnotationConfigApplicationContext时,它接收一个配置类(如MyConfiguration)作为参数,用于初始化Spring上下文。启动时,会从Spring上下文中获取并使用相应的Bean。AnnotationConfigApplicationContext执行了几个关键步骤,其中最核心的是this(),该方法初始化了两个组件:AnnotatedBeanDefinitionReader(负责读取注解定义的bean)和ClassPathBeanDefinitionScanner(负责扫描类路径并自动检测bean组件)。AnnotatedBeanDefinitionReader在其构造函数中调用registerAnnotationConfigProcessors,此方法向容器注册了一系列的后置处理器,这些后置处理器对于处理各种注解(如@Inject, @Qualifier等)是关键。QualifierAnnotationAutowireCandidateResolver实例时,它会尝试加载JSR-330的@Qualifier注解,并将其添加到qualifierTypes集合中。这使得在后续的依赖注入过程中,Spring可以正确处理这个注解。DefaultListableBeanFactory#resolveDependency。此方法首先尝试获取一个延迟解析代理,如果不能获得,则会尝试解析依赖,此过程涉及到doResolveDependency方法。findAutowireCandidates中,Spring首先找出所有可能的bean名称,然后检查每一个可能的候选bean,看看它是否是一个合适的自动装配候选。此检查涉及到isAutowireCandidate方法。isAutowireCandidate方法的工作是判断某个bean是否是自动装配的候选者。在有多个可能的候选bean时,AutowireCandidateResolver(这里的实例是QualifierAnnotationAutowireCandidateResolver)会被用来做决策,考虑到@Qualifier和其他相关的注解。QualifierAnnotationAutowireCandidateResolver的主要任务是增强对@Qualifier注解的支持。它确保待注入的bean与所有相关的@Qualifier注解和元注解匹配。如果其中一个注解或元注解与bean定义不匹配,那么这个bean就不是当前注入点的合适候选。isQualifier方法则用来确定给定的注解是否为一个资格符注解(限定符注解),例如@Qualifier。这是通过检查注解是否存在于已知的qualifierTypes集合中或它是否带有这些资格符注解来完成的。