设为首页 加入收藏

TOP

quarkus依赖注入之十三:其他重要知识点大串讲(终篇)(二)
2023-08-26 21:11:12 】 浏览:77
Tags:quarkus 赖注入 十三 (终篇
truct:生命周期拦截器,bean创建后执行
  • PreDestroy:生命周期拦截器,bean销毁前执行
  • AroundConstruct:生命周期拦截器,拦截bean构造方法
    • 现在问题来了:拦截器能拦截静态方法吗?
    • 答案是可以,但是有限制,具体的限制如下
    1. 仅支持方法级别的拦截(即拦截器修饰的是方法)
    2. private型的静态方法不会被拦截
    3. 下图是拦截器实现的常见代码,通过入参InvocationContext的getTarget方法,可以得到被拦截的对象,然而,在拦截静态方法时,getTarget方法的返回值是null,这一点尤其要注意,例如下图红框中的代码,在拦截静态方法是就会抛出空指针异常
    image-20220501162427008

    All更加直观的注入

    • 假设有个名为SayHello的接口,源码如下
    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();
            }
        }
    }
    
    • 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注解可以让代码显得更为直观,另外还有以下三个特点
    1. 此list是immutable的(内容不可变)

    2. list中的bean是按照priority排序的

    3. 如果您需要的不仅仅是注入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)

    image-20220502165300841

    统一处理异步事件的异常

    • 需要提前说一下,本段落涉及的知识点和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
    首页 上一页 1 2 3 下一页 尾页 2/3/3
    】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
    上一篇Docker容器编排 下一篇注册中心 —— SpringCloud Netfl..

    最新文章

    热门文章

    Hot 文章

    Python

    C 语言

    C++基础

    大数据基础

    linux编程基础

    C/C++面试题目