Spring事件驱动

Spring事件驱动

提示: 本材料只做个人学习参考,不作为系统的学习流程,请注意识别!!!



一. 事件驱动简介

  1. 事件驱动模型基于发布-订阅的编程模型,设计思想为:观察者设计模式
  2. 定义了对象之间的一对多关系,当一个对象状态发生改变(发布),其观察者(订阅者)就可以接收到其改变的通知。
  3. 观察者是如何处理的,发布者是无需干涉,这也是事件驱动主要用来进行代码解耦原因。

事件驱动模型的核心构建包含:

  1. 事件源:负责生产事件的对象。比如前端button按钮。
  2. 事件监听器(处理器):负责处理事件的对象。
  3. 事件(事件对象):事件源和事件监听之间的信息桥梁,是整个事件驱动模型的核心。

二. 观察者(Observer)模式简介

观察者模式:
指多个对象之间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都能够得到通知并被自动更新。又称:发布-订阅模式、模型-视图模式,它是对象行为型模式。
优点:
观察者和被观察者是抽象耦合的,他们之间形成了一套触发机制。
缺点:
如果被观察者有很多直接或间接观察者的话,通知所有的观察者可能会耗费很长的时间。
如果观察者和被观察者之间形成循环依赖的话,观察目标会触发它们之间的循环调用,引起系统崩溃。
观察者模式不能够让观察者知道所观察目标对象是如何发生变化的,而仅仅知道观察目标发生了变化。
示例代码:
发布者:

import java.util.ArrayList;
import java.util.List;

/**
* 发布者
*/
public class Subject {
   //观察者列表
   private List<Observer> observers = new ArrayList<Observer>();
   //状态
   private int state;

   public int getState() {
       return state;
   }

   public void setState(int state) {
       this.state = state;
       notifyAllObservers();
   }

   public void attach(Observer observer) {
       observers.add(observer);
   }

   /**
    * 通知所有的观察者
    */
   public void notifyAllObservers() {
       for (Observer observer : observers) {
           observer.update();
       }
   }
}

观察者抽象类:

/**
* 观察者抽象类
*/
public abstract class Observer {
  //观察者观察的发布者
  protected Subject subject;
  //观察者事件处理方法
  public abstract void update();
}

观察者实现类:

public class Observer1 extends Observer {

   public Observer1(Subject subject) {
       this.subject = subject;
       this.subject.attach(this);
   }

   @Override
   public void update() {
       System.out.println("Observer1111..." + subject.getState());
   }
}
public class Observer2 extends Observer {

   public Observer2(Subject subject) {
       this.subject = subject;
       this.subject.attach(this);
   }

   @Override
   public void update() {
       System.out.println("Observer2222..." + subject.getState());
   }
}

测试类:

public class ObserverPatternDemo {
   public static void main(String[] args) {
       Subject subject = new Subject();

       new Observer1(subject);
       new Observer2(subject);

       System.out.println("First state change: 111111");
       subject.setState(111111);
       System.out.println("Second state change: 222222");
       subject.setState(222222);
   }
}

测试结果:

First state change: 111111
Observer1111...111111
Observer2222...111111
Second state change: 222222
Observer1111...222222
Observer2222...222222

除了上述自定义的观察者模式外,javaBean规范中提供了一种监听属性变化的事件驱动模型(这里我们不做拓展)。此外JDK为我们提供了现成的观察者实现,简单介绍(附部分源码):

观察者接口:

public interface Observer {
    /**
     * This method is called whenever the observed object is changed. An
     * application calls an <tt>Observable</tt> object's
     * <code>notifyObservers</code> method to have all the object's
     * observers notified of the change.
     *
     * @param   o     the observable object.
     * @param   arg   an argument passed to the <code>notifyObservers</code>
     *                 method.
     */
    void update(Observable o, Object arg);
}

被观察者接口:

package java.util;

/**
 * @author  Chris Warth
 * @see     java.util.Observable#notifyObservers()
 * @see     java.util.Observable#notifyObservers(java.lang.Object)
 * @see     java.util.Observer
 * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
 * @since   JDK1.0
 */
public class Observable {
    private boolean changed = false;
    private Vector<Observer> obs;
    /** Construct an Observable with zero Observers. */
    public Observable() {
        obs = new Vector<>();
    }

    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }

    public void notifyObservers() {
        notifyObservers(null);
    }

    public void notifyObservers(Object arg) {
        Object[] arrLocal;
        synchronized (this) {
            /* 这里存在2个潜在的糟糕结果:
             * 1) 一个新加入的观察者错过了正在执行的通知
             * 2) 一个刚刚删除的观察者不需要关心变更时有可能会错误地被通知
             */
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }
        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }

    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }

    protected synchronized void setChanged() {
        changed = true;
    }

    protected synchronized void clearChanged() {
        changed = false;
    }

    public synchronized boolean hasChanged() {
        return changed;
    }

    public synchronized int countObservers() {
        return obs.size();
    }
}

三.Spring事件驱动

1. 原理解析

Spring的事件驱动模型由三部分组成:

  1. 事件:ApplicationEvent,继承自JDK的EventObject,所有事件将继承它,并通过source得到事件源。
  2. 事件订阅者:ApplicationListener,继承自JDK的EventListener,所有监听器将继承它。
  3. 事件发布者:ApplicationEventPublisher及ApplicationEventMulticaster接口,使用这个接口,我们的Service就拥有了发布事件的能力。

下面对这几个类做下介绍:

ApplicationEvent:

public abstract class ApplicationEvent extends EventObject {
    private static final long serialVersionUID = 7099057708183571937L;
    private final long timestamp;
    public ApplicationEvent(Object source) {
        super(source);
        this.timestamp = System.currentTimeMillis();
    }
    public final long getTimestamp() {
        return this.timestamp;
    }
}

ApplicationEvent,继承自JDK的EventObject,所有事件将继承它,并通过source得到事件源。该类的实现类ApplicationContextEvent表示ApplicaitonContext的容器事件

public abstract class ApplicationContextEvent extends ApplicationEvent {

	public ApplicationContextEvent(ApplicationContext source) {
		super(source);
	}
	
	public final ApplicationContext getApplicationContext() {
		return (ApplicationContext) getSource();
	}

}

ApplicationListener:

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E event);
}

ApplicationListener继承自jdk的EventListener,所有的监听器都要实现这个接口,这个接口只有一个onApplicationEvent()方法,该方法接受一个ApplicationEvent或其子类对象作为参数。在方法体中,可以通过不同对Event类判断来进行相应的处理。当事件触发时所有的监听器都会收到消息,如果你需要对监听器的接收顺序有要求,可是实现该接口的一个实现SmartApplicationListener,通过这个接口可以指定监听器接收事件的顺序。

ApplicationContext:

ApplicationContext是spring中的全局容器,即"应用上下文"(IOC容器),它用来负责读取bean的配置文档,管理bean的加载,维护bean之间的依赖关系,可以说是负责bean整个生命周期。
Application作为一个事件源,需要显示的调用publishEvent方法,传入一个ApplicationEvent实现类对象,每当ApplicationContext发布ApplicationEvent时,所有的ApplicationListener就会被自动的触发。

ApplicationContext接口实现了ApplicationEventPublisher接口,后者有一个很重要的方法:

@FunctionalInterface
public interface ApplicationEventPublisher {
	//......
	void publishEvent(Object event);
}

我们常用的ApplicationContext都继承了AbstractApplicationContext,例如:ClassPathXmlApplicationContext、XmlWebApplicationContex,AbstractApplicationcontext是ApplicationContext接口的抽象实现类,在该类中实现了publishEvent方法:

	@Override
	public void publishEvent(ApplicationEvent event) {
		publishEvent(event, null);
	}

	protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
		Assert.notNull(event, "Event must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("Publishing event in " + getDisplayName() + ": " + event);
		}

		// Decorate event as an ApplicationEvent if necessary
		ApplicationEvent applicationEvent;
		if (event instanceof ApplicationEvent) {
			applicationEvent = (ApplicationEvent) event;
		}
		else {
			applicationEvent = new PayloadApplicationEvent<>(this, event);
			if (eventType == null) {
				eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
			}
		}

		// Multicast right now if possible - or lazily once the multicaster is initialized
		if (this.earlyApplicationEvents != null) {
			this.earlyApplicationEvents.add(applicationEvent);
		}
		else {
			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
		}

		// Publish event via parent context as well...
		if (this.parent != null) {
			if (this.parent instanceof AbstractApplicationContext) {
				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
			}
			else {
				this.parent.publishEvent(event);
			}
		}
	}

这个方法中有个getApplicationEventMulticaster()方法,这就要牵扯到另一个类ApplicationEventMulticaster:
 
ApplicationEventMulticaster:

它属于事件广播器,作用是把Applicationcontext发布的Event广播给所有的监听器。在AbstractApplicationcontext中有一个applicationEventMulticaster成员变量,提供了监听器Listener的注册方法:

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext, DisposableBean {

  private ApplicationEventMulticaster applicationEventMulticaster;
  protected void registerListeners() {
        // Register statically specified listeners first.
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }
        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let post-processors apply to them!
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String lisName : listenerBeanNames) {
            getApplicationEventMulticaster().addApplicationListenerBean(lisName);
        }
    }
}

2. Spring 事件监听Demo

Demo1:
事件类:

public class MyEvent extends ApplicationEvent {

    public MyEvent(Object source) {
        super(source);
        System.out.println("MyEvent...");
    }
    public void print(){
        System.out.println("MyEvent print()...");
    }
}

监听类:

public class MyListener1  implements ApplicationListener{
    
    public void onApplicationEvent(ApplicationEvent event) {
        if(event instanceof MyEvent){
            System.out.println("MyListener1  ...");
            MyEvent myEvent=(MyEvent)event;
            myEvent.print();
        }
    }
}
public class MyListener2  implements ApplicationListener{
    
    public void onApplicationEvent(ApplicationEvent event) {
        if(event instanceof MyEvent){
            System.out.println("MyListener2  ...");
            MyEvent myEvent=(MyEvent)event;
            myEvent.print();
        }
    }
}

发布事件的类:

public class MyPubisher implements ApplicationContextAware {

    private ApplicationContext applicationContext;
    
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }
    
    public void publishEvent(ApplicationEvent event){
        System.out.println("MyPubisher publishEvent() ...");
        applicationContext.publishEvent(event);
    }
}

测试类:

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("classpath:spring/application.xml");
        MyPubisher myPubisher=(MyPubisher) context.getBean("myPublisher");
        myPubisher.publishEvent(new MyEvent("666"));
    }
}

Demo2:
事件类

/**
 * 账号信息变更事件
 */
public class ModifyEvent extends ApplicationEvent {

    private List<Integer> accNoList;

    public ModifyEvent(final Object source,List<Integer> accNoList) {
        super(source);
        this.accNoList = accNoList;
    }

	public List<Integer> getAccNoList() {
		return accNoList;
	}

	public void setAccNoList(List<Integer> accNoList) {
		this.accNoList = accNoList;
	}
}

监听类

@EnableAsync
@Component
public class ChangeListener {
    private static final Logger log = LoggerFactory.getLogger(ChangeListener.class);

    @EventListener //表示事件监听注解
    @Async //可以异步处理
    public void listenerModifyEvent(BalanceModifyEvent event) {
        try {
            Set<Integer> accNos = new HashSet<Integer>(event.getAccNoList());
           //...
           //业务逻辑
        } catch (Exception e) {
            log.error("业务处理异常", e);
        }
    }
}

事件发布类 && 测试类,参考上一个Demo。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值