truct:生命周期拦截器,bean创建后执行
PreDestroy:生命周期拦截器,bean销毁前执行
AroundConstruct:生命周期拦截器,拦截bean构造方法
- 现在问题来了:拦截器能拦截静态方法吗?
- 答案是可以,但是有限制,具体的限制如下
- 仅支持方法级别的拦截(即拦截器修饰的是方法)
- private型的静态方法不会被拦截
- 下图是拦截器实现的常见代码,通过入参InvocationContext的getTarget方法,可以得到被拦截的对象,然而,在拦截静态方法时,getTarget方法的返回值是null,这一点尤其要注意,例如下图红框中的代码,在拦截静态方法是就会抛出空指针异常
All更加直观的注入
public interface SayHello {
void hello();
}
public class InjectAllTest {
/**
* 用Instance接收注入,得到所有SayHello类型的bean
*/
@Inject
Instance<SayHello> instance;
@Test
public void testInstance() {
// instance中有迭代器,可以用遍历的方式得到所有bean
for (SayHello sayHello : instance) {
sayHello.hello();
}
}
}
- quarkus提供了另一种方式,借助注解io.quarkus.arc.All,可以将所有SayHello类型的bean注入到List中,如下所示
@QuarkusTest
public class InjectAllTest {
/**
* 用All注解可以将SayHello类型的bean全部注入到list中,
* 这样更加直观
*/
@All
List<SayHello> list;
@Test
public void testAll() {
for (SayHello sayHello : list) {
sayHello.hello();
}
}
}
- 和CDI规范相比,使用All注解可以让代码显得更为直观,另外还有以下三个特点
-
此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() );
}
}
}
- 代码的执行结果如下图红框所示,可见注入bean及其作用域都能成功取得(要注意的是注入bean是代理bean)
统一处理异步事件的异常
-
需要提前说一下,本段落涉及的知识点和AsyncObserverExceptionHandler类有关,而《quarkus依赖注入》系列所用的quarkus-2.7.3.Final版本中并没有AsyncObserverExceptionHandler类,后来将quarkus版本更新为2.8.2.Final,就可以正常使用AsyncObserverExceptionHandler类了
-
本段落的知识点和异步事件有关:如果消费异步事件的过程中发生异常,而开发者有没有专门写代码处理异步消费结果,那么此异常就默默无闻的被忽略了,我们也可能因此错失了及时发现和处理问题的时机
-
来写一段代码复现上述问题,首先是事件定义TestEvent.java,就是个普通类,啥都没有
public class TestEvent {
}
- 然后是事件的生产者TestEventProducer.java,注意其调用fireAsync方法发送了一个异步事件
@ApplicationScoped
public class TestEventProducer {
@Inject
Event<TestEvent> event;
/**
* 发送异步事件
*/
public void asyncProduce() {
event.fireAsync(new TestEvent());
}
}
- 事件的消费者TestEventConsumer.java,这里在消费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();
}
}
- 运行EventExceptionHandlerTest,结果如下图,DefaultAsyncObse