14.4 @Qualifier
14.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容器内是唯一的。
14.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 {
}
14.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注解,这个将在后续单独讲解。
14.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所写)
本文转自:https://elim.iteye.com/blog/2388585
相关推荐
在本主题中,我们将深入探讨Spring框架的2.5版本引入的一个重要特性——基于注解的Spring MVC配置。Spring MVC是Spring框架的一部分,专门用于构建Web应用程序,它提供了一个模型-视图-控制器(MVC)架构来组织和...
Spring 2.5基于注解驱动的SpringMVC配置方式代表了现代Web应用开发的一个重要趋势——减少XML配置,增强代码的自描述性和可维护性。通过上述核心注解的使用,开发人员能够更快速、高效地构建响应式、可扩展的Web应用...
Spring提供了三种配置方式:基于XML的配置、基于注解的配置和基于Java的配置。基于XML的配置方式需要在配置文件中声明bean,依赖和服务的配置,这样的配置方式有利于将配置信息和代码分离。 在Spring框架中,通常会...
### MyBatis与Spring整合方式详解:基于注解的实现 #### 一、概述 在实际的软件开发过程中,为了更好地实现项目的模块化管理和提高代码的可维护性,通常会将MyBatis与Spring框架进行整合。这种方式不仅能够简化...
### 使用 Spring 2.5 基于注解驱动的 Spring MVC #### 概述与背景 自从Spring 2.0版本对Spring MVC框架进行了重大升级之后,Spring 2.5再次对该框架进行了显著改进,引入了注解驱动的功能。这使得开发人员能够更加...
本文将深入探讨“Spring AOP——Schema”,这是Spring AOP的一种配置方式,通过XML schema定义切面和通知。 首先,我们需要理解AOP的基本概念。面向切面编程是一种编程范式,旨在提高软件的模块化程度,将关注点...
SpringCloud Zookeeper配置中心允许动态更新应用程序的配置,无需重启服务。此外,Zookeeper还可以作为分布式锁的实现,解决分布式环境下的并发问题。 总结来说,SpringCloud与Zookeeper的结合,使得开发者能够快速...
Spring MVC 是一个基于 Java 的轻量级 Web 开发框架,它是 Spring 框架的一部分,主要用来处理 Web 请求。在本文中,我们将深入探讨 Spring MVC 的基本使用,包括它的架构、配置、控制器、模型视图解析以及数据绑定...
Spring 3.0引入了基于注解的配置,使得我们不再需要为每个控制器创建单独的bean定义。例如,我们可以使用`@Controller`注解标记一个类作为Spring MVC的控制器: ```java @Controller @RequestMapping("/users") ...
以上就是基于注解的SpringMVC的一些核心概念。通过使用这些注解,开发者可以编写更简洁、更易于维护的代码,同时减少了XML配置的工作量。在实际项目中,还会涉及到更多高级特性,如拦截器、异常处理、视图解析等,...
通过XML或注解配置SQL语句,MyBatis能够将Java对象映射到数据库记录,实现数据的增删改查操作。结合Spring,可以实现DAO(Data Access Object)的自动管理,进一步简化开发流程。 项目开发环境包括Eclipse IDE,这...
它基于"约定优于配置"的原则,通过提供开箱即用的功能,让开发者能够快速地创建独立运行的、生产级别的基于Spring的应用。 **构建RESTful服务** REST(Representational State Transfer)是一种网络应用程序的设计...
- Spring支持基于代理的AOP和基于注解的AOP。 4. **IoC容器** - IoC容器是Spring的基石,负责管理对象的生命周期和对象之间的依赖关系。 - 容器通过读取配置元数据(XML、注解或Java配置类)来创建和管理Bean。 ...
SpringCloud是基于Spring Boot构建的云应用开发工具集,它为开发者提供了在分布式系统(如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态)操作中的...
Eureka是由Netflix公司开发的服务发现框架,它基于RESTful接口,可以方便地集成到Spring Cloud生态系统中。Eureka分为两个主要组件:Eureka Server(服务注册中心)和Eureka Client(服务提供者和服务消费者)。服务...
MyBatis可以使用简单的XML或注解来进行配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。 #### 三、Spring框架简介 Spring框架是用于构建企业级Java应用程序的...
在IT行业中,SSH2框架是三个非常著名的开源Java框架——Struts2、Spring和Hibernate的组合,用于构建高效、可维护的企业级Web应用程序。在这个基于Spring注解的SSH2框架集成中,我们将深入探讨如何将这三个组件有效...
这个“毕业设计——基于SSM的个人书签管理系统”项目,就是利用这三个框架搭建的一个实用系统,非常适合进行毕业设计或课程设计,同时也可以作为学习SSM框架的实例。 1. **Spring框架**:Spring是Java企业级应用的...
5. **配置元数据**:可以读取XML、注解或基于Java的配置来管理bean。 三、BeanFactory与ApplicationContext的区别 虽然BeanFactory是基础,但实际开发中更多使用的是其子类ApplicationContext。ApplicationContext...