博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
限定符注解
阅读量:5155 次
发布时间:2019-06-13

本文共 6333 字,大约阅读时间需要 21 分钟。

学而不思则罔,思而不学则殆。

应用场景

  Spring使用自动装配将bean引用注入到构造参数和属性中时,仅有一个bean匹配所需的结果时,自动装配才是有效的,如果不止一个bean能够匹配,这种歧义性会阻碍Spring自动装配属性、构造器参数或方法参数,且会抛出NoUniqueBeanDefinitionException。

  如下有Computer:

package chapter3;public interface Computer {    void play();}

  类AppleComputer,LenovoComputer,HaierComputer都实现了接口Computer,且均使用了@Component注解:

package chapter3;import org.springframework.stereotype.Component;@Componentpublic class AppleComputer implements Computer {    public void play() {        System.out.println("apple computer playing...");    }}
package chapter3;import org.springframework.stereotype.Component;@Componentpublic class LenovoComputer implements Computer {    public void play() {        System.out.println("lenovo computer playing...");    }}
package chapter3;import org.springframework.stereotype.Component;@Componentpublic class HaierComputer implements Computer {    public void play() {        System.out.println("haier computer playing...");    }}

  在Spring试图自动装配时,Spring无法做出选择,只好宣告失败并抛出异常:

package chapter3;import org.springframework.stereotype.Component;@Componentpublic class HaierComputer implements Computer {    public void play() {        System.out.println("haier computer playing...");    }}
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'chapter3.ComputerTest': Unsatisfied dependency expressed through method 'setComputer' parameter 0; nested exception is org.springframework.beans. factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'chapter3.Computer' available: expected single matching bean but found 3: appleComputer,haierComputer,lenovoComputer Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'chapter3. Computer' available: expected single matching bean but found 3: appleComputer,haierComputer,lenovoComputer

  当遇到这种歧义性的时候,Spring提供了多种可选方案来解决这样的问题:设置首选的bean;使用限定符。

 

设定首选的bean

  在Spring中可以通过@Primary来指定首选的bean,@Primary能够与@Component组合用在组件扫描的bean上,也可以与@Bean组合用在Java配置的bean声明中。

  如下使用@Component与@Primary组合指定AppleComputer为首选的bean,那么当创建Computer引用时,Spring会使用首选的bean。

package chapter3;import org.springframework.context.annotation.Primary;import org.springframework.stereotype.Component;@Component@Primarypublic class AppleComputer implements Computer {    public void play() {        System.out.println("apple computer playing...");    }}
package chapter3;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;@Configuration@ComponentScanpublic class ComputerConfig {        @Bean    @Primary    public Computer appleComputer() {        return new AppleComputer();    }}

  在XML中使用primary属性指定首选的bean

  @Primary无法指定唯一的、无歧义性的bean,如果你在LenovoComputer或HaierComputer类上也加上@Primary,那么也带来了新的歧义性问题。

 

使用限定符限定自动装配的bean

  @Qualifier注解是使用限定符的主要方式。它可以与@Autowired和@Inject协同使用,在注入的时候指定想要注入的bean ID。

package chapter3;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=ComputerConfig.class)public class ComputerTest {        private Computer computer;        @Autowired    @Qualifier("appleComputer")    public void setComputer(Computer computer) {        this.computer = computer;    }        @Test    public void run() {        computer.play();    }    }

  因为@Qualifier限定符与要注入的bean的名称时紧耦合的,假设修改AppleComputer类的名称,那么限定符会失效,这个时候我们可以创建自定义的限定符,而不是依赖于将bean ID作为限定条件。

package chapter3;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.stereotype.Component;@Component@Qualifier("apple")public class AppleComputer implements Computer {    public void play() {        System.out.println("apple computer playing...");    }}
package chapter3;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=ComputerConfig.class)public class ComputerTest {        private Computer computer;        @Autowired    @Qualifier("apple")    public void setComputer(Computer computer) {        this.computer = computer;    }        @Test    public void run() {        computer.play();    }    }

  还是存在一个问题,仅使用一个@Qualifier仍然无法确定唯一的、无歧义性的bean。

   Java 8 允许出现重复的注解,只要这个注解本身在定义时带有@Repeatable注解,但是@Qualifier注解在定义时没有该定义。

* Copyright 2002-2011 the original author or authors.package org.springframework.beans.factory.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * 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@Documentedpublic @interface Qualifier {    String value() default "";}

  虽然我们无法只借助@Qualifier限定符注解就确定唯一、无歧义的bean,但是,我们可以创建自定义的限定符注解,然后进行任意组合直至将可选范围缩小到只有一个bean满需需求。

 

创建自定义的限定符注解

  创建@Apple限定符注解

package chapter3;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import org.springframework.beans.factory.annotation.Qualifier;@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Qualifierpublic @interface Apple {}

 

转载于:https://www.cnblogs.com/dandelZH/p/8799192.html

你可能感兴趣的文章
kubernetes_book
查看>>
侧边栏广告和回到顶部
查看>>
https://blog.csdn.net/u012106306/article/details/80760744
查看>>
海上孤独的帆
查看>>
处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“Manag
查看>>
01: socket模块
查看>>
mysql触发器
查看>>
淌淌淌
查看>>
win10每次开机都显示“你的硬件设置已更改,请重启电脑……”的解决办法
查看>>
C++有关 const & 内敛 & 友元&静态成员那些事
查看>>
函数积累
查看>>
Swift 入门之简单语法(六)
查看>>
〖Python〗-- IO多路复用
查看>>
栈(括号匹配)
查看>>
Java学习 · 初识 面向对象深入一
查看>>
源代码如何管理
查看>>
vue怎么将一个组件引入另一个组件?
查看>>
bzoj1040: [ZJOI2008]骑士
查看>>
LeetCode 74. Search a 2D Matrix(搜索二维矩阵)
查看>>
利用SignalR来同步更新Winfrom
查看>>