这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
@Qualifier
public @interface Default {
public static final class Literal extends AnnotationLiteral<Default> implements Default {
public static final Literal INSTANCE = new Literal();
private static final long serialVersionUID = 1L;
}
}
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface MyQualifier {
@Nonbinding String value();
}
先按照前面的假设将接口和实现类准备好,造成一个接口有多个实现bean的事实,然后,再用修饰符匹配来准确选定bean
首先是接口HelloQualifier,如下所示
package com.bolingcavalry.service;
public interface HelloQualifier {
String hello();
}
package com.bolingcavalry.service.impl;
import com.bolingcavalry.service.HelloQualifier;
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class HelloQualifierA implements HelloQualifier {
@Override
public String hello() {
return this.getClass().getSimpleName();
}
}
package com.bolingcavalry;
import com.bolingcavalry.service.HelloQualifier;
import com.bolingcavalry.service.impl.HelloQualifierA;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
@QuarkusTest
public class QualifierTest {
@Inject
HelloQualifier helloQualifier;
@Test
public void testQualifier() {
Assertions.assertEquals(HelloQualifierA.class.getSimpleName(),
helloQualifier.hello());
}
}
package com.bolingcavalry.annonation;
import javax.enterprise.util.Nonbinding;
import javax.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface MyQualifier {
@Nonbinding String value();
}
第二步:用MyQualifier修饰HelloQualifierA,下图红框是新增的代码
第三步:在业务代码的注入点,用MyQualifier修饰HelloQualifier类型的成员变量,下图红框是新增的代码
改动完成了,再次执行单元测试,顺利通过
回头看刚才的代码,如果保留HelloQualifierA的MyQualifier修饰,但是删除QualifierTest的成员变量helloQualifier的MyQualifier修饰,会发生什么呢?咱们来分析一下:
首先,QualifierTest的成员变量helloQualifier会被quarkus默认添加Default修饰
其次,HelloQualifierB和HelloQualifierC都会被quarkus默认添加Default修饰
所以,注入helloQualifier的时候,quarkus去找Default修饰的bean,结果找到了两个:HelloQualifierB和HelloQualifierC,因此启动会失败
您可以自行验证结果是否和预期一致
看到这里,您应该掌握了修饰符匹配的用法,也应该发现其不便之处:要新增注解,这样下去随着业务发展,注解会越来越多,有没有什么方法来解决这个问题呢?
方法是有的,就是接下来要看的Named注解
Named注解的功能与前面的Qualifier修饰符是一样的,其特殊之处在于通过注解属性来匹配修饰bean和注入bean
以刚才的业务代码为例来演示Named注解,修改HelloQualifierA,如下图红框,将@MyQualifier("")换成@Named("A"),重点关注Named注解的属性值,这里等于A
接下来修改注入处的代码,如下图红框,在注入位置也用@Named("A")来修饰,和bean定义处的一模一样
如此,bean定义和bean注入的两个地方,通过Named注解的属性完成了匹配,至于单元测试您可以自行验证,这里就不赘述了
至此,详细您已经知道了Named注解的作用:功能与前面的Qualifier修饰符一样,不过bean的定义和注入处的匹配逻辑是Named注解的属性值
以上就是修饰符匹配的全部内容
使用优先级来选择注入是一种简洁的方式,其核心是用Alternative和Priority两个注解修饰所有备选bean,然后用Priority的属性值(int型)作为优先级,该值越大代表优先级越高
在注入位置,quarkus会选择优先级最高的bean注入
接下来编码演示
新增演示用的接口HelloPriority.java
public interface HelloPriority {
String hello();
}
@ApplicationScoped
@Alternative
@Priority(1001)
public class HelloPriorityA implements HelloPriority {
@Override
public String hello() {
return this.getClass().getSimpleName();
}
}
@ApplicationScoped
@Alternative
@Priority(1002)
public class HelloPriorityB implements HelloPriority {
@Override
public String hello() {
return this.getClass().getSimpleName();
}
}
@ApplicationScoped
@Alternative
@Priority(1003)
public class HelloPriorityC implements HelloPriority {
@Override
public String hello() {
return this.getClass().getSimpleName();
}
}
@QuarkusTest
public class PriorityTest {
@Inject
HelloPriority helloPriority;
@Test
public void testSelectHelloInstanceA() {
Assertions.assertEquals(HelloPriorityC.class.getSimpleName(),
helloPriority.hello());
}
}
package com.bolingcavalry.service;
public interface HelloInstance {
String hello();
}
package com.bolingcavalry.service.impl;
import com.bolingcavalry.service.HelloInstance;
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class HelloInstanceA implements HelloInstance {
@Override
public String hello() {
return this.getClass().getSimpleName();
}
}
package com.bolingcavalry;
import com.bolingcavalry.service.HelloInstance;
import com.bolingcavalry.service.impl.HelloInstanceA;
import com.bolingcavalry.service.impl.HelloInstanceB;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
@QuarkusTest
public class InstanceTest {
@Inject
Instance<HelloInstance> instance;
@Test
public void testSelectHelloInstanceA() {
Class<HelloInstanceA> clazz = HelloInstanceA.class;
Assertions.assertEquals(clazz.getSimpleName(),
instance.select(clazz).get().hello());
}
@Test
public void testSelectHelloInstanceB() {
Class<HelloInstanceB> clazz = HelloInstanceB.class;
Assertions.assertEquals(clazz.getSimpleName(),
instance.select(clazz).get().hello());
}
}
执行单元测试,顺利通过,符合预期
至此,连续两篇关于注入bean的方式全部验证完毕,如此丰富的手段,相信可以满足您日常开发的需要