在spring中,提供了@Qualifier注解,帮助我们精确的注入需要的bean实例。这边文章主要介绍该注解在spring开发中的两种使用方式,能够帮助我们优雅的实现代码。
首先开始学习时,先查看下该注解的源码,以及注解方式,然后再以demo的方式实现。
@Qualifier源码
/**
* This annotation may be used on a field or parameter as a qualifier for
* candidate beans when autowiring. It may also be used to annotate other
* custom annotations that can then in turn be used as qualifiers.
*
* @author Mark Fisher
* @author Juergen Hoeller
* @since 2.5
* @see Autowired
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {
String value() default "";
}
通过源码注解可以得知, 该注解使用有两种场景:
- 通过配合
@Autowired注解实现精准bean注入 - 自动注解,然后将自定义注解上加入
@Qualifier注解,派生出新的注解
DEMO实现
接下来将通过代码的方式演示以上两种使用方式,下面我们通过定义配置类型,生成我们需要bean对象. 具体代码如下:
import org.spring.learn.eureka.client.annotation.MyQualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author xianglujun
* @date 2021/9/17 11:06
* @since
*/
@Configuration
public class MyQualifierConfiguration {
public class BaseService {
}
@MyQualifier
@Bean
public BaseService baseService() {
return new BaseService();
}
@Bean
public BaseService noQualifierBaseService() {
return new BaseService();
}
}
在以上代码中,我自定义一个注解@MyQualifier, 该注解又被@Qualifier注解。因此@MyQualifier注解是@Qualifier注解的一个派生。具体代码如下:
/**
* @author xianglujun
* @date 2021/9/17 11:04
* @since
*/
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier
public @interface MyQualifier {
}
在configuration的配置类中,我们创建了两个bean对象:
baseService的bean, 该bean是被自定义注解@MyQualifier修饰noQualifierBaseService则是一个普通的bean对象,没有区别。
当以上类型配置完成之后,接下来我们验证这两个bean在使用上的差别,这里我们新建一个类型MyQualifierService,具体源码如下:
import java.util.List;
import javax.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.spring.learn.eureka.client.annotation.MyQualifier;
import org.spring.learn.eureka.client.config.MyQualifierConfiguration.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
/**
* @author xianglujun
* @date 2021/9/17 11:09
* @since
*/
@Slf4j
@Service
public class MyQualifierService {
@Autowired
private List<BaseService> baseServices;
@Qualifier("baseService")
@Autowired
private BaseService onlyOneService;
@MyQualifier
@Autowired
private BaseService baseService;
@PostConstruct
public void init() {
log.info("baseService: {}", baseServices);
log.info("baseService: {}", baseService);
}
}
在这个类中包含了三个属性, 具体特点如下:
baseServices: 在spring容器中查找所有BaserService类型的bean对象onlyOneService: 在spring容器中查找bean名称为baseService的实例baseService: 则是查找类型为BaseService并且被@MyQualifier注解修饰的实例
我们将spring容器启动起来,并查看到日志内容如下:
2021-09-17 11:42:05.420 INFO 110960 --- [ main] o.s.l.e.c.service.MyQualifierService : onlyOneService: org.spring.learn.eureka.client.config.MyQualifierConfiguration$BaseService@4375b013 2021-09-17 11:42:05.422 INFO 110960 --- [ main] o.s.l.e.c.service.MyQualifierService : baseService: [org.spring.learn.eureka.client.config.MyQualifierConfiguration$BaseService@4375b013, org.spring.learn.eureka.client.config.MyQualifierConfiguration$BaseService@1cf0cacc] 2021-09-17 11:42:05.422 INFO 110960 --- [ main] o.s.l.e.c.service.MyQualifierService : baseService: org.spring.learn.eureka.client.config.MyQualifierConfiguration$BaseService@4375b013
可以看到,程序能够正常的执行,并且能够正常的将所依赖的实体注入。并且跟上面我们对程序执行的推断也是正确的。
总结
当我们在平日开发中, 我们可以利用派生注解的方式,避免@Qualifier("name")这种硬代码注入bean. 所在在代码开发上,其实显得更加优雅一点吧。