• Java设计模式之观察者模式再温习


    观察者模式,定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并完成处理。观察者模式的应用场景是优化执行流程,将非核心流程由串行执行改为异步执行,如下单成功后发送消息。

    观察者模式的核心类:

    • Observerable:被观察者,核心方法:添加观察者、移除观察者、通知观察者
    • Observer:观察者接口
    • ObserverImp:观察者实现

    实例

    public interface Observer {
        /**
         * 观察者事件
         */
        void doEvent();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    public class EmailObserver implements Observer {
        @Override
        public void doEvent() {
            System.out.println("发送email消息");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    public class MobileNoObserver implements Observer {
        @Override
        public void doEvent() {
            System.out.println("发送短信消息");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    public class Observerable {
    
        private List<Observer> observers = new ArrayList<>();
    
        /**
         * 添加观察者
         */
        public void addObserver(Observer observer) {
            observers.add(observer);
        }
    
        /**
         * 移除观察者
         */
        public void removeObserver(Observer observer) {
            observers.remove(observer);
        }
    
        /**
         * 通知
         * @return
         */
        public void notifyAllObserver(int state) {
            if (state != 1) {
                System.out.println("非通知状态");
                return;
            }
            for (Observer observer : observers) {
                observer.doEvent();
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    		// 创建订单成功,返回状态
            int insert = 1;
            // 创建被观察者
            Observerable observerable = new Observerable();
            // 添加观察者
            observerable.addObserver(new EmailObserver());
            // 添加观察者
            observerable.addObserver(new MobileNoObserver());
            // 通知观察者
            observerable.notifyAllObserver(insert);
            System.out.println("下单成功");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在spring框架中,也有观察者模式的应用,Spring ApplicationEvent事件。
    事件机制在一些大型项目中被经常使用,Spring ApplicationEvent就是Spring专门提供的一套事件机制的接口,满足了架构原则上的解耦。
    ApplicationContext 通过 ApplicationEvent 类和 ApplicationListener 接口进行事件处理。如果将实现 ApplicationListener 接口的 bean 注入到上下文中,则每次使用 ApplicationContext 发布 ApplicationEvent 时,都会通知该实现 ApplicationListener 接口的 bean。ApplicationEvent 是由 Spring 提供的所有 Event 类的基类。
    实例
    自定义业务事件子类,继承 ApplicationEvent,通过泛型注入业务模型参数类

    public class AbstractGenericEvent<T> extends ApplicationEvent {
    
        public AbstractGenericEvent(Object source) {
            super(source);
        }
    
        public AbstractGenericEvent(Object source, Clock clock) {
            super(source, clock);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    事件实现类

    public class OrderEvent extends AbstractGenericEvent<OrderModel> {
    
        public OrderEvent(OrderModel source) {
            super(source);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    事件监听器类,实现ApplicationListener 接口

    @Component
    public class OrderEventListener implements ApplicationListener<OrderEvent> {
    
        @Override
        public void onApplicationEvent(OrderEvent event) {
            //
            System.out.println(Thread.currentThread().getName() + "-receive msg: " + JSON.toJSONString(event.getSource()));
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    @Component
    public class EmailEventListener implements ApplicationListener<OrderEvent> {
    
        @Override
        public void onApplicationEvent(OrderEvent event) {
            //
            System.out.println(Thread.currentThread().getName() + "-send email: " + JSON.toJSONString(event.getSource()));
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    测试

    	@GetMapping("hello")
        public Object hello() {
            OrderModel orderModel = new OrderModel();
            orderModel.setId("1");
            orderModel.setName("caocao");
            // 发布Spring事件通知
            SpringBeanUtil.getApplicationContext().publishEvent(new OrderEvent(orderModel));
            System.out.println(Thread.currentThread().getName() + "-publish: ");
            return "hello";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    结果如下
    在这里插入图片描述
    从结果发现,无论是发布事件,还是监听事件使用了同一个线程,spring框架的事件机制默认是同步堵塞的,要想实现异步调用,需手动创建一个配置类,并设置线程池,如下

    @Component
    public class SpringConfiguration {
    
        @Bean
        public SimpleApplicationEventMulticaster applicationEventMulticaster(@Qualifier("defaultThreadPoolExecutor") ThreadPoolExecutor defaultThreadPoolExecutor) {
            SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();
            simpleApplicationEventMulticaster.setTaskExecutor(defaultThreadPoolExecutor);
            return simpleApplicationEventMulticaster;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    结果如下
    在这里插入图片描述
    从结果发现,发布和监听由不同的线程执行。
    那SimpleApplicationEventMulticaster 实例化和系统默认的实例化加载顺序如如何?
    在spring源码中,处理逻辑在 AbstractApplicationContext的initApplicationEventMulticaster 方法中,通过 beanFactory 查找是否有自定义的 Bean,如果没有,容器会自己 new 一个 SimpleApplicationEventMulticaster 对象注入到容器中。
    在这里插入图片描述
    还需继续分析spring中应用的设计模式及底层原理。

  • 相关阅读:
    Linux中Too many open files
    Netty学习------2024/02/19
    百度文心一言与谷歌Gemini的对比
    没那么简单!浅析伦敦金与美元的关系
    DBRichEdit关联ClientDataSet不能保存的Bug
    代码随想录算法训练营第二十八天| LeetCode93. 复原 IP 地址、LeetCode78. 子集、LeetCode90. 子集 II
    特征交叉系列:FM和深度神经网络的结合,DeepFM原理简述和实践
    Android手机为何不再卡顿?性能优化才是安卓起飞关键
    【抓包分析】通过ChatGPT解密还原某软件登录算法实现绕过手机验证码登录
    5+非肿瘤生信思路经典思路,没有机器学习,WGCNA也能撑起大局,还有多个实验验证的强势助攻
  • 原文地址:https://blog.csdn.net/leijie0322/article/details/125593899