Spring(15)——基于注解的配置(二)

简介: 15.4 @Qualifier 15.4.1 简介 @Qualifier通常是配合@Autowired的一起使用的。我们知道使用@Autowired进行注入时默认是按照类型进行注入的。

15.4 @Qualifier

15.4.1 简介

@Qualifier通常是配合@Autowired的一起使用的。我们知道使用@Autowired进行注入时默认是按照类型进行注入的。打个比方当我们使用@Autowired的定义beanA需要自动注入一个类型为BeanB的bean时,如果在bean容器中存在多个类型为BeanB的bean,那么Spring就会抛出异常。这个时候我们就可以使用@Qualifier来指定需要进行注入的到底是哪个BeanB类型的bean,具体bean是通过@Qualifier注解的value属性来进行指定的。以下示例表示我们通过@Qualifier指定我们需要注入的是beanName为world的那个World,这个时候需要两者都满足的bean才能被注入,即要求被注入的bean既是World类型的,又必须对应的beanName为“world”。

public class Hello {
	
	@Qualifier("world")
	@Autowired
	private World world;

}

对于通过构造方法或普通方法注入的形式,我们可以将@Qualifier标注在对应的方法参数上,以确定到底需要注入哪个对象。如下我们在构造方法参数world上使用@Qualifier标注了我们需要进行注入的是beanName为world1的那个World类型的bean。

public class Hello {
	
	private World world;
	private BeanA beanA;
	
	@Autowired
	public Hello(@Qualifier("world1") World world, BeanA beanA) {
		this.world = world;
		this.beanA = beanA;
	}
	
}

@Qualifier注解的value属性值默认对应的是对应bean定义的beanName,而实际上@Qualifier寻找的是对应的qualifier,只是在没有指定对应的qualifier时默认会取beanName。对应的qualifier可以在进行bean定义时通过qualifier元素进行定义。如下示例我们在定义bean定义时指定了对应的qualifier为abc,那么之后我们在通过@Qualifier指定需要注入该bean时就只能使用@Qualifier(“abc”),而不能使用@Qualifier(“world1”)。

<bean id="world1" class="com.app.World">
	<qualifier value="abc"/>
</bean>

qualifier元素除了可以通过value属性指定当前元素对应的qualifier之外,还需要指定一个type属性,该属性的默认值是org.springframework.beans.factory.annotation.Qualifier。只有这两者的结合才能对应一个qualifier。如在上述示例中当我们在字段上使用@Qualifier(“abc”)进行标注时,实际上Spring将会去寻找value为“abc”,type为org.springframework.beans.factory.annotation.Qualifier的qualifier对应的对应类型的bean进行注入,如果不存在对应类型的qualifier,则取beanName为“abc”的那个bean进行注入。此外还支持给一个bean定义多个qualifier,即定义多个qualifier元素。

在使用qualifier元素定义一个bean的qualifier时允许有重复的qualifier存在,即不要求每个元素的qualifier在当前bean容器内是唯一的。

15.4.2 自定义@Qualifier

@Qualifier还可以标注在其它注解上,这样就形成了一个自定义的Qualifier。在使用@Autowired的时候我们也可以使用自定义的Qualifier来标识我们需要进行注入的具体是哪一个bean。我们先来自定义一个Qualifier,叫MyQualifier。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@Qualifier
public @interface MyQualifier {
	
	public String value() default "";
	
}

然后就可以在我们的代码中使用@MyQualifier进行标识需要注入的bean了。

public class Hello {
	
	@MyQualifier("world1")
	@Autowired
	private World world;

}

根据前面的介绍我们知道这里使用@MyQualifier(“world1”)进行标注后,Spring将寻找type为com.app.MyQualifier,value为world1的Qualifier对应com.app.World类型的bean进行注入。当没有找到时就会取beanName为world1的World类型的bean进行注入。所以我们的World类型的bean可以如下定义:

<bean id="world" class="com.app.World" p:id="10">
	<qualifier type="com.app.MyQualifier" value="world1"/>
</bean>

也可以不指定qualifier,然后指定其beanName为world1,这个时候也可以有其它类型的Qualifier定义,但是切不可有MyQualifier类型的Qualifier定义。如下这种定义是可以的。

<bean id="world1" class="com.app.World" p:id="10">
	<qualifier value="abc"/>
</bean>

我们也可以在使用@MyQualifier进行注入时不定义对应的参数,如:

public class Hello {
	
	@MyQualifier
	@Autowired
	private World world;

}

那么对应的在定义需要注入的bean时,也不能指定对应的参数,但是需要定义qualifier元素,并指定对应的type。

<bean id="world0" class="com.app.World" p:id="10">
	<qualifier type="com.app.MyQualifier"/>
</bean>

在自定义Qualifier的时候也可以给我们自定义的Qualifier加上其它额外的属性,如在下面示例中我们给MyQualifier多加了一个order属性的定义。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@Qualifier
public @interface MyQualifier {
	
	public String value() default "";
	
	public int order() default 0;
	
}

那么在使用MyQualifier进行标注的时候我们就可以使用新增加的属性进行定义了。

public class Hello {
	
	@MyQualifier(order=1, value="world1")
	@Autowired
	private World world;

}

对应的我们在定义bean时也需要通过qualifier定义对应的属性,这个时候对应的属性是通过qualifier的子元素attribute进行定义的。

<bean class="com.app.World" p:id="10">
	<qualifier type="com.app.MyQualifier" value="world1">
		<attribute key="order" value="1"/>
	</qualifier>
</bean>

对于使用注解进行扫描bean的情况其实我们还可以直接在对应的bean上使用@Qualifier进行标注来指定当前bean对应的qualifier。关于使用注解扫描bean并添加到bean容器中的内容将在后续文章中进行讲解。这里我们先来看一个对应的示例。

@Component
@Qualifier("abc")
public class World {

}

15.5 @Resource

@Resource是JSR250标准中的一个注解,Spring也对其提供了支持,我们可以使用@Resource标注在我们需要进行自动注入的field或set方法上,也可以是普通的非set方法上,但是对应方法只允许接收一个参数。其不能像@Autowired那样定义在构造方法上,也不允许通过一个方法同时注入多个bean对象。

public class Hello {
	
	@Resource
	private World world;
	private BeanA beanA;
	
	/**
	 * 通过普通方法进行注入,对应方法只允许拥有一个参数
	 * @param beanA
	 */
	@Resource
	public void otherMethod(BeanA beanA) {
		this.beanA = beanA;
	}

}

使用@Resource时默认是通过按照beanName来进行注入的。@Resource拥有一个name属性,我们可以通过它来指定我们需要注入的bean的beanName。当没有指定时默认将使用field的名称,或set方法去掉set前缀后的名称。当对应beanName的bean在bean容器中不存在时,Spring将尝试按照需要注入的类型寻找对应的bean给@Resource标注的field或方法进行注入,但此时如果对应类型的bean拥有多个时也一样会报异常。

public class Hello {
	
	/**
	 * 优先注入beanName为world1的bean,不存在时才注入一个类型为World的bean。
	 */
	@Resource(name="world1")
	private World world;

}

对于其它如数组、集合类型的注入,以及ApplicationContext等的注入@Resource也是一样支持的。

public class Hello {
	
	@Resource
	private World[] worldArray;
	@Resource
	private List<World> worldList;
	@Resource
	private Set<World> worldSet;
	@Resource
	private Map<String, World> worldMap;
	
	@Resource
	private ApplicationContext applicationContext;

}

因为元素类型的问题,我们不能直接通过@Autowired加@Qualifier的形式注入一个集合等类型的bean,但是这种情况我们可以通过@Resource来解决。如我们拥有如下这样一个ArrayList类型的bean定义。

<bean id="strList" class="java.util.ArrayList">
	<constructor-arg>
		<list>
			<value>abc</value>
			<value>bcd</value>
			<value>cde</value>
		</list>
	</constructor-arg>
</bean>

如果现在我们需要在我们的程序中自动注入这么一个bean,那么通过@Autowired加@Qualifier的形式是不行的,但是我们只能通过@Resource进行注入。

public class Hello {
	
	@Resource(name="strList")
	private List<String> strList;

}

其实,类似的支持自动注入的注解还有JSR330标准的@Inject注解,这个将在后续单独讲解。

15.6 @PostConstruct和@PreDestroy

@PostConstruct和@PreDestroy注解在之前讲解bean的生命周期回调方法的时候有讲解过。其实把它们放在这里来讲可能并不是很合适,因为这两个注解不需要我们在Spring的配置文件中配置启用Spring对注解的支持就可以使用,即不需要配置<context:annotation-config/>就可以用的注解。但既然本文是讲解Spring对使用注解进行配置的支持,那就还是顺便讲讲。使用@PostConstruct进行标注的方法会被当做是初始化方法,其会在对应bean实例化之后由Spring进行调用。使用@PreDestroy进行标注的方法会被当做是释放资源的方法,其会在bean容器销毁前由Spring进行调用。使用@PostConstruct和@PreDestroy进行标注的方法都是不能带参数。更多信息请参考之前介绍bean生命周期回调的那篇文章。

public class Hello {
	
	@PostConstruct
	public void doInit() {
		System.out.println("init****************");
	}
	
	@PreDestroy
	public void doDestroy() {
		System.out.println("destroy***************");
	}

}

(注:本文是基于Spring4.1.0所写)

目录
相关文章
|
16天前
|
Java Spring 容器
如何解决spring EL注解@Value获取值为null的问题
本文探讨了在使用Spring框架时,如何避免`@Value(&quot;${xxx.xxx}&quot;)`注解导致值为null的问题。通过具体示例分析了几种常见错误场景,包括类未交给Spring管理、字段被`static`或`final`修饰以及通过`new`而非依赖注入创建对象等,提出了相应的解决方案,并强调了理解框架原理的重要性。
56 4
|
6天前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
21 4
|
3天前
|
Java API 数据库
Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐
本文通过在线图书管理系统案例,详细介绍如何使用Spring Boot构建RESTful API。从项目基础环境搭建、实体类与数据访问层定义,到业务逻辑实现和控制器编写,逐步展示了Spring Boot的简洁配置和强大功能。最后,通过Postman测试API,并介绍了如何添加安全性和异常处理,确保API的稳定性和安全性。
8 0
|
13天前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
50 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
4天前
|
Java BI 调度
Java Spring的定时任务的配置和使用
遵循上述步骤,你就可以在Spring应用中轻松地配置和使用定时任务,满足各种定时处理需求。
20 1
|
5天前
|
架构师 Java 开发者
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
在40岁老架构师尼恩的读者交流群中,近期多位读者成功获得了知名互联网企业的面试机会,如得物、阿里、滴滴等。然而,面对“Spring Boot自动装配机制”等核心面试题,部分读者因准备不足而未能顺利通过。为此,尼恩团队将系统化梳理和总结这一主题,帮助大家全面提升技术水平,让面试官“爱到不能自已”。
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
|
9天前
|
XML Java 数据库
Spring boot的最全注解
Spring boot的最全注解
|
11天前
|
JSON NoSQL Java
springBoot:jwt&redis&文件操作&常见请求错误代码&参数注解 (九)
该文档涵盖JWT(JSON Web Token)的组成、依赖、工具类创建及拦截器配置,并介绍了Redis的依赖配置与文件操作相关功能,包括文件上传、下载、删除及批量删除的方法。同时,文档还列举了常见的HTTP请求错误代码及其含义,并详细解释了@RequestParam与@PathVariable等参数注解的区别与用法。
|
11天前
|
Java API Spring
springBoot:注解&封装类&异常类&登录实现类 (八)
本文介绍了Spring Boot项目中的一些关键代码片段,包括使用`@PathVariable`绑定路径参数、创建封装类Result和异常处理类GlobalException、定义常量接口Constants、自定义异常ServiceException以及实现用户登录功能。通过这些代码,展示了如何构建RESTful API,处理请求参数,统一返回结果格式,以及全局异常处理等核心功能。
|
17天前
|
Java Spring 容器
Springboot3.2.1搞定了类Service和bean注解同名同类型问题修复
这篇文章讨论了在Spring Boot 3.2.1版本中,同名同类型的bean和@Service注解类之间冲突的问题得到了解决,之前版本中同名bean会相互覆盖,但不会在启动时报错,而在配置文件中设置`spring.main.allow-bean-definition-overriding=true`可以解决这个问题。
51 0
Springboot3.2.1搞定了类Service和bean注解同名同类型问题修复