这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos
quarkus在CDI规范的基础上做了简化,可以让我们少写几行代码
将配置文件中名为greeting.message的配置项注入到bean的成员变量greetingMsg中,按照CDI规范的写法如下
@Inject
@ConfigProperty(name = "greeting.message")
String greetingMsg;
@ConfigProperty(name = "greeting.message")
String greetingMsg;
@ApplicationScoped
public class MyCoolService {
private SimpleProcessor processor;
MyCoolService() { // dummy constructor needed
}
@Inject // constructor injection
MyCoolService(SimpleProcessor processor) {
this.processor = processor;
}
}
@ApplicationScoped
public class MyCoolService {
private SimpleProcessor processor;
MyCoolService(SimpleProcessor processor) {
this.processor = processor;
}
}
class Producers {
@Produces
@ApplicationScoped
MyService produceServ
ice() {
return new MyService(coolProperty);
}
}
class Producers {
@ApplicationScoped
MyService produceService() {
return new MyService(coolProperty);
}
}
@QuarkusTest
public class WithCachingTest {
@Inject
Instance<HelloDependent> instance;
@Test
public void test() {
// 第一次调用Instance#get方法
HelloDependent helloDependent = instance.get();
helloDependent.hello();
// 第二次调用Instance#get方法
helloDependent = instance.get();
helloDependent.hello();
}
}
上述代码是种常见的bean注入和使用方式,我们的本意是在WithCachingTest实例中多次使用HelloDependent类型的bean,可能是在test方法中使用,也可能在WithCachingTest的其他方法中使用
如果HelloDependent的作用域是ApplicationScoped,上述代码一切正常,但是,如果作用域是Dependent呢?代码中执行了两次Instance#get,得到的HelloDependent实例是同一个吗?Dependent的特性是每次注入都实例化一次,这里的Instance#get又算几次注入呢?
最简单的方法就是运行上述代码看实际效果,这里先回顾HelloDependent.java的源码,如下所示,构造方法中会打印日志,这下好办了,只要看日志出现几次,就知道实例化几次了
@Dependent
public class HelloDependent {
public HelloDependent(InjectionPoint injectionPoint) {
Log.info("injecting from bean "+ injectionPoint.getMember().getDeclaringClass());
}
public String hello() {
return this.getClass().getSimpleName();
}
}
public interface SayHello {
void hello();
}
现在有三个bean都实现了SayHello接口,如果想要调用这三个bean的hello方法,应该怎么做呢?
按照CDI的规范,应该用Instance注入,然后使用Instance中的迭代器即可获取所有bean,代码如下
public class InjectAllTest {
/**
* 用Instance接收注入,得到所有SayHello类型的bean
*/
@Inject
Instance<SayHello> instance;
@Test
public void testInstance() {
// instance中有迭代器,可以用遍历的方式得到所有bean
for (SayHello sayHello : instance) {
sayHello.hello();
}
}
}
@QuarkusTest
public class InjectAllTest {
/**
* 用All注解可以将SayHello类型的bean全部注入到list中,
* 这样更加直观
*/
@All
List<SayHello> list;
@Test
public void testAll() {
for (SayHello sayHello : list) {
sayHello.hello();
}
}
}
此list是immutable的(内容不可变)
list中的bean是按照priority排序的
如果您需要的不仅仅是注入bean,还需要bean的元数据信息(例如bean的scope),可以将List中的类型从SayHello改为InstanceHandle<SayHello>,这样即可以得到注入bean,也能得到注入bean的元数据(在InjectableBean中),参考代码如下
@QuarkusTest
public class InjectAllTest {
@All
List<InstanceHandle<SayHello>> list;
@Test
public void testQuarkusAllAnnonation() {
for (InstanceHandle<SayHello> instanceHandle : list) {
// InstanceHandle#get可以得到注入bean
SayHello sayHello = instanceHandle.get();
// InjectableBean封装了注入bean的元数据信息
InjectableBean<SayHello> injectableBean = instanceHandle.getBean();
// 例如bean的作用域就能从InjectableBean中取得
Class clazz = injectableBean.getScope();
// 打印出来验证
Log.infov("bean [{0}], scope [{1}]", sayHello.getClass().getSimpleName(), clazz.getSimpleName() );
}
}
}
需要提前说一下,本段落涉及的知识点和AsyncObserverExceptionHandler类有关,而《quarkus依赖注入》系列所用的quarkus-2.7.3.Final版本中并没有AsyncObserverExceptionHandler类,后来将quarkus版本更新为2.8.2.Final,就可以正常使用AsyncObserverExceptionHandler类了
本段落的知识点和异步事件有关:如果消费异步事件的过程中发生异常,而开发者有没有专门写代码处理异步消费结果,那么此异常就默默无闻的被忽略了,我们也可能因此错失了及时发现和处理问题的时机
来写一段代码复现上述问题,首先是事件定义TestEvent.java,就是个普通类,啥都没有
public class TestEvent {
}
@ApplicationScoped
public class TestEventProducer {
@Inject
Event<TestEvent> event;
/**
* 发送异步事件
*/
public void asyncProduce() {
event.fireAsync(new TestEvent());
}
}
@ApplicationScoped
public class TestEventConsumer {
/**
* 消费异步事件,这里故意抛出异常
*/
public void aSyncConsume(@ObservesAsync TestEvent testEvent) throws Exception {
throw new Exception("exception from aSyncConsume");
}
}
@QuarkusTest
public class EventExceptionHandlerTest {
@Inject
TestEventProducer testEventProducer;
@Test
public void testAsync() throws InterruptedException {
testEventProducer.asyncProduce();
}
}
package com.bolingcavalry.service.impl;
import io.quarkus.arc.AsyncObserverExceptionHandler;
import io.quarkus.logging.Log;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.spi.EventContext;
import javax.enterprise.inject.spi.ObserverMethod;
@ApplicationScoped
public class NoopAsyncObserverExceptionHandler implements AsyncObserverExceptionHandler {
@Override
public void handle(Throwable throwable, ObserverMethod<?> observerMethod, EventContext<?> eventContext) {
// 异常信息
Log.info("exception is - " + throwable);
// 事件信息
Log.info("observer type is - " + observerMethod.getObservedType().getTypeName());
}
}