• Spring源码之spring中的观察者模式和监听器的使用


    声明:本文根据鲁班学院子路老师spring中观察者模式课程整理得来

    观察者模式特点:

      被观察者持有监听的观察者的引用。

      被观察者支持增加和删除的观察者。

      被观察者状态改变通知观察者。

    JDK中观察者implements Observer接口,重写update()方法

      当观察者发生变化,收到通知进行具体的处理

      可以随时取消

    松耦合:

      观察者增加或者删除无需修改被观察者的代码,只需调用被观察者对应的增加或则删除的方法即可

      被观察者只负责通知观察者,但无需了解观察者如何处理通知

      观察者只需等待被观察者通知,无需观察被观察者细节

    通知不会错过:

      由于被动接受,正常情况下不会错过主体的改变通知,而主动获取的话,由于时机选择问题,可能导致错过某些状态

    Java实现

      Java中有观察者模式使用的API

        Java.util.Observable 这是一个类

        java.util.Observer 这是一个接口

    开关的重要性

      可以筛选通知

      可以撤销通知

      可以控制通知

    Spring中的观察者模式

    在Spring中定义和应用程序上下文相关的事件时需要继承ApplicationEvent
    public abstract class ApplicationEvent extends EventObject {
        /** use serialVersionUID from Spring 1.2 for interoperability. */
        private static final long serialVersionUID = 7099057708183571937L;
        /** System time when the event happened. */
        private final long timestamp;
        /**
         * Create a new {@code ApplicationEvent}.
         * @param source the object on which the event initially occurred or with
         * which the event is associated (never {@code null})
         */
        public ApplicationEvent(Object source) {
            super(source);
            this.timestamp = System.currentTimeMillis();
        }
        /**
         * Return the system time in milliseconds when the event occurred.
         */
        public final long getTimestamp() {
            return this.timestamp;
        }
    }

      在ApplicationEvent的父类EventObject类(这个是java源码中的类)中有一个得到事件源的方法getSource()

      

     Spring中的Events

      事件通过**org.springframework.context.ApplicationEvent**实例来表示。这个抽象类继承扩展了**java.util.EventObject**,可以使用**EventObject中的getSource**方法,我们可以很容易地获得所发生的给定事件的对象。这里,事件存在两种类型。

      1. **与应用程序上下文相关联**

        所有这种类型的事件都继承自**org.springframework.context.event.ApplicationContextEvent**类。

        它们应用于由**org.springframework.context.ApplicationContext**引发的事件(其构造函数传入的是`ApplicationContext`类型的参数)。

        这样,我们就可以直接通过应用程序上下文的生命周期得到所发生的事件:`ContextStartedEvent`在上下文启动时被启动,当它停止时启动`ContextStoppedEvent`,当上下文被刷新时产生`ContextRefreshedEvent`,最后在上下文关闭时产生`ContextClosedEvent`。

       

       以ContextStartedEvent这个类为例,实现SpringEvent的扩展功能,这个事件在context.start()的时候来进行监听处理。

    public class ContextStartedEvent extends ApplicationContextEvent {
    
        /**
         * Create a new ContextStartedEvent.
         * @param source the {@code ApplicationContext} that has been started
         * (must not be {@code null})
         */
        public ContextStartedEvent(ApplicationContext source) {
            super(source);
        }
    
    }

      1.首先创建一个listener类

    /**
     * spring通过实现ApplicationListener这个接口,同时传入一个泛型(ContextStartedEvent)就可以
     * 监听到这个泛型对应的事件
     */
    @Component
    public class SpringListenerStart implements ApplicationListener<ContextStartedEvent> {
        @Override
        public void onApplicationEvent(ContextStartedEvent event) {
            System.out.println("----- spring application start listener------");
        }
    }

      2.创建测试类

    public class Test {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WkApplication.class);
            context.start();//在调用context的start()方法时,会触发spring的监听器,调用ContextStartedEvent对应的事件方法
      } 
    }

      3.运行结果

      

    Spring监听器的应用(模拟一个发邮件的监听器):

      1.创建一个SpringMailEvent类,使它继承ApplicationEvent类(这个是Spring的事件类,自己的事件都要继承它)

    public class SpringMailEvent extends ApplicationEvent implements Serializable {
        //需要序列化,要不会报错。我也不知道为什么
        private static final long serialVersionUID=762508508425139227l;
    
        private String content;
        /**
         * Create a new {@code ApplicationEvent}.
         *
         * @param source the object on which the event initially occurred or with
         *               which the event is associated (never {@code null})
         */
        public SpringMailEvent(Object source) {
            super(source);
        }
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    }

      2.创建一个SpringMailListener监听器类,使他实现ApplicationListener接口,同时泛型中穿我们自己定义的事件<SpringMailEvent>

    @Component
    public class SpringMailListener implements ApplicationListener<SpringMailEvent> {
        /**
         * 当程序调用了一个发邮件的方法时,这个监听器就会监听到,
         * 同时在onApplicationEvent方法中做出响应
         * @param event the event to respond to
         */
        @Override
        public void onApplicationEvent(SpringMailEvent event) {
            System.out.println("mail send ");
        }
    }

      3.创建一个类,使自定义的监听器和事件与spring容器关联起来

    /**
     * 创建自己的类,使自定义的监听器和事件与spring容器关联起来
     */
    @Component
    public class MailBean {
        @Autowired
        ApplicationContext context;//注入Sprig应用程序上下文
    
        /**
         * 我们之前只是定义了SpringMailEvent类,但是这个类并没有和Spring容器关联起来,
         * 所以我们需要借助ApplicationContext的publishEvent()方法,把这个事件发布出去
         */
        public void sendMail(){
            context.publishEvent(new SpringMailEvent(context));
        }
    }

      4.测试类

    public class Test {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WkApplication.class);
    //        context.start();
            //触发发邮件的事件
            context.getBean(MailBean.class).sendMail();
        }
    }

      5.测试结果

      

    2. **与request 请求相关联**

      由**org.springframework.web.context.support.RequestHandledEvent**实例来表示,当在ApplicationContext中处理请求时,它们被引发。

     Spring如何将事件分配给专门的监听器?

      这个过程由事件广播器来实现,由**org.springframework.context.event.ApplicationEventMulticaster**接口的实现表示。此接口定义了3种方法

        1. **addApplicationListener()**  添加新的监听器**:定义了两种方法来添加新的监听器:**addApplicationListener(ApplicationListener<?> listener)**和**addApplicationListenerBean(String listenerBeanName)**。当监听器对象已知时,可以应用第一个。如果使用第二个,我们需要将bean name 得到listener对象(`依赖查找DL`),然后再将其添加到`listener`列表中

        2. **removeApplicationListenerBean(String listenerBeanName)** **删除监听器**:添加方法一样,我们可以通过传递对象来删除一个监听器(**removeApplicationListener(ApplicationListener<?> listener)**或通过传递bean名称。第三种方法,**removeAllListeners()**用来删除所有已注册的监听器。

        3. **multicastEvent(ApplicationEvent event)****将事件发送到已注册的监听器**。

        

  • 相关阅读:
    JS面向(基于)对象编程--构造方法(函数)
    一个超简单的马里奥游戏
    JavaScript基于对象编程
    JavaScript基础之函数与数组
    Learn CSS
    The first day of HTML
    mysql cmd 无法登录
    datagrid 扩展 页脚 合计功能
    this高级应用
    (xxx.55).toFixed(1) 无法正确进位处理
  • 原文地址:https://www.cnblogs.com/wk-missQ1/p/13277111.html
Copyright © 2020-2023  润新知