读spring源码了解监听者模式

今天有时间debug了下spring boot启动的源码,没跟几行code就看到了一个标准的监听者模式。索性花点时间写写监听者模式。

JDK对监听者的支持
以下是jdk对监听者模式提供的支持,后面的例子都会用到。

  • 事件类:java.util.EventObject 自带对象source,注意source不能为空。
public class EventObject implements java.io.Serializable {
    protected transient Object  source;
    public EventObject(Object source) {
        if (source == null)
            throw new IllegalArgumentException("null source");
        this.source = source;
    }
    public Object getSource() {
        return source;
    }
}
  • 监听接口:public interface EventListener 没有任何属性方法。

小王的苦逼生活
场景:小王每月工资1.5W,每年奖金3W。每月信用卡还款1W,一有钱就要还信用卡;另外,还想着发奖金的时候购物(买个7手奥拓,先定价2W吧,哥也不了解行情)。

下面开始用监听者模式模拟场景。

  • 先定义工资和奖金类(get和set方法忽略)。
public class Salary {

    private int month;

    private double money;

    public Salary(int month, double money) {
        this.month = month;
        this.money = money;
    }

}
public class Bonus extends Salary {

    public Bonus(double money) {
        super(0, money);
    }

    public Bonus(int month, double money) {
        super(month, money);
    }

}
  • 自定义事件,包括发工资和发奖金两种事件。将source类型定义为salary,方便事件的监听者使用。
public abstract class CustomEvent extends EventObject{

    public CustomEvent(Salary source) {
        super(source);
    }

    public Salary getSource() {
        return (Salary)source;
    }
}
  public class PaySalaryEvent extends CustomEvent {

    public PaySalaryEvent(Salary source) {
        super(source);
    }
}  
public class PayBonusEvent extends CustomEvent {

    public PayBonusEvent(Bonus source) {
        super(source);
    }
}
  • 定义两个监听器,分别是信用卡还款监听器和购物车监听器。
public interface CustomEventListener<E extends CustomEvent> extends EventListener{

    public void handleEvent(CustomEvent event);

}
//信用卡还款监听器要做的事情就是发现小王发了钱(包括工资和奖金),立即扣除。
public class CreditCardRepayListener implements CustomEventListener<CustomEvent>{

    private static double defaultPurchases = 10000;
    @Override
    public void handleEvent(CustomEvent event) {
        if(event.getSource().getMoney()< defaultPurchases) {
            System.out.println("Repay credit card, You are a poor man!");
            event.getSource().setMoney(0);
        }else {
            event.getSource().setMoney(event.getSource().getMoney() - defaultPurchases);
            System.out.println("Repay credit card, Surplus is " + event.getSource().getMoney());
        }
    }

}
//购物车监听器做的事情是发现小王发了奖金去happy。
public class ShoppingCartListener implements CustomEventListener<CustomEvent> {

    private static double defaultShoppingMoney = 20000;

    @Override
    public void handleEvent(CustomEvent event) {
        if(event instanceof PayBonusEvent) {
            if(event.getSource().getMoney()< defaultShoppingMoney) {
                System.out.println("Do not want to go shopping!");
            }else {
                event.getSource().setMoney(event.getSource().getMoney() - defaultShoppingMoney);
                System.out.println("After go shopping, Surplus is " + event.getSource().getMoney());
            }
        }
    }

}
  • 现在事件和监听器都有了,我们还需要建立两者之间的关系。这里使用一个事件管理员来维护这个关系。管理员能够使用doEvent发送事件。
public class EventManager {

    private List<CustomEventListener<?>> listeners = Arrays.asList(new CreditCardRepayListener(), new ShoppingCartListener());

    public void addListener(CustomEventListener<?> listener) {
        listeners.add(listener);
    }

    public void removeListener(CustomEventListener<?> eventListener){
        listeners.remove(eventListener);
    }

    public void doEvent(CustomEvent event){    
        listeners.stream().forEach(listener -> listener.handleEvent(event));
    }

}
  • 最后写测试类:
public class TestClass {

    public static void main(String[] args) {
        EventManager eventManager =new EventManager();
        System.out.println("Pay January salary, 15000");
        eventManager.doEvent(new PaySalaryEvent(new Salary(0, 15000)));
        System.out.println("--------------------------------------------");
        System.out.println("Pay Bonus, 30000");
        eventManager.doEvent(new PayBonusEvent(new Bonus(30000)));
    }
}
  • 打印结果:
Pay January salary, 15000
Repay credit card, Surplus is 5000.0
--------------------------------------------
Pay Bonus, 30000
Repay credit card, Surplus is 20000.0
After go shopping, Surplus is 0.0

监听者模式在spring boot里面的应用

spring boot是通过@SpringBootApplication和SpringApplication.run(×××,args)启动的。我们debug SpringApplication源码会进入如下:

public ConfigurableApplicationContext run(String... args) {
        ......
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        ......
}

方法getRunListeners返回值中默认只有一个对象org.springframework.boot.context.event.EventPublishingRunListener(配置文件spring.factories)。直接debug到主题类:SimpleApplicationEventMulticaster的multicastEvent方法。

@Override
    public void multicastEvent(ApplicationEvent event) {
        multicastEvent(event, resolveDefaultEventType(event));
    }

    @Override
    public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            Executor executor = getTaskExecutor();
            if (executor != null) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        invokeListener(listener, event);
                    }
                });
            }
            else {
                invokeListener(listener, event);
            }
        }
    }
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            listener.onApplicationEvent(event);
        }
        catch (ClassCastException ex) {
            .....   }

我们能看到入参就是一个事件对象,做的事情就是找到事件监听器然后发消息,这个和我们在小王的场景中使用的EventManager类做的事情相似。不同的是在getApplicationListeners(event, type))方法中,加了些事件监听器的过滤。
再来看看它的事件对象ApplicationEvent和事件监听器ApplicationListener。

public abstract class ApplicationEvent extends EventObject....

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

ApplicationEvent和我们在小王的场景中事件的CustomEvent是一样的。ApplicationListener对应CustomEventListener。
监听器的实现类是来自于spring boot配置文件spring.factories,默认如下:

org.springframework.context.ApplicationListener=
\org.springframework.boot.ClearCachesApplicationListener
,\org.springframework.boot.builder.ParentContextCloserApplicationListener
,\org.springframework.boot.context.FileEncodingApplicationListener
,\org.springframework.boot.context.config.AnsiOutputApplicationListener
,\org.springframework.boot.context.config.ConfigFileApplicationListener
,\org.springframework.boot.context.config.DelegatingApplicationListener
,\org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
,\org.springframework.boot.logging.ClasspathLoggingApplicationListener
,\org.springframework.boot.logging.LoggingApplicationListener

我们可以打开一个LoggingApplicationListener源码,看看它做了什么。
首先,我们会看看两个钩子方法。这两个方法的大体意思是检查这个监听器支持监听哪些事件,事件源可以通过这两个方法过滤监听器。

    @Override
    public boolean supportsEventType(ResolvableType resolvableType) {
        return isAssignableFrom(resolvableType.getRawClass(), EVENT_TYPES);
    }

    @Override
    public boolean supportsSourceType(Class<?> sourceType) {
        return isAssignableFrom(sourceType, SOURCE_TYPES);
    }

下面就是事件响应方法了,按事件干活。

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationStartingEvent) {
            onApplicationStartingEvent((ApplicationStartingEvent) event);
        }
        else if (event instanceof ApplicationEnvironmentPreparedEvent) {
            onApplicationEnvironmentPreparedEvent(
                    (ApplicationEnvironmentPreparedEvent) event);
        }
        else if (event instanceof ApplicationPreparedEvent) {
            onApplicationPreparedEvent((ApplicationPreparedEvent) event);
        }
        else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event)
                .getApplicationContext().getParent() == null) {
            onContextClosedEvent();
        }
        else if (event instanceof ApplicationFailedEvent) {
            onApplicationFailedEvent();
        }
    }

以上就是简单的监听者模式,类图就不画了。

  1. 监听者模式包含EventObject ,EventListener,EventSource(上面例子中对应的是事件管理者),事件源维护事件监听器,并且可以每个监听器发送事件对象。
  2. 事件对象和监听器没有必然关系,全靠事件源来联系它们从而做到解耦。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值