栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

可能是最卷的Spring源码系列(十一):spring中的事件

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

可能是最卷的Spring源码系列(十一):spring中的事件

spring实现了时间订阅发布的功能,所以使用spring时就不再需要自己实现或者使用jdk自带的观察者模式,使用spring自带的订阅发布功能即可。本文会从源码的角度来分析spring中事件的实现

观察者模式
public class Client {

    public static void main(String[] args) {
        // 被观察者(发布者)
        ISubject observable = new ConcreteSubject();
        // 观察者(订阅者)
        IObserver observer = new ConcreteObserver();
        // 注册
        observable.attach(observer);
        // 通知
        observable.notify("hello");
    }

    //抽象观察者
    public interface IObserver {
        void update(E event);
    }

    //抽象主题者
    public interface ISubject {
        boolean attach(IObserver observer);

        boolean detach(IObserver observer);

        void notify(E event);
    }

    //具体观察者
    static class ConcreteObserver implements IObserver {
        public void update(E event) {
            System.out.println("receive event: " + event);
        }
    }

    //具体主题者
    static class ConcreteSubject implements ISubject {
        private List> observers = new ArrayList>();

        public boolean attach(IObserver observer) {
            return !this.observers.contains(observer) && this.observers.add(observer);
        }

        public boolean detach(IObserver observer) {
            return this.observers.remove(observer);
        }

        public void notify(E event) {
            for (IObserver observer : this.observers) {
                observer.update(event);
            }
        }
    }
}

观察者模式分为两个角色,观察者和被观察者,被观察者对象中包含多个观察者,当往被观察者中发布消息时,被观察者会便利所有的观察者来通知观察者
至于观察者模式的优缺点以及使用场景,本文不再叙述

JDK自带的事件模型

jdk也为我们实现了一套事件模型,使用方法和上面类似,只不过上例只能发布string类型的事件,jdk事件模型可以支持各种类型的事件
首先定义一种事件

public class Question {
    private String userName;
    private String content;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

被观察者

public class GPer extends Observable {
    private String name = "GPer生态圈";
    private static final GPer gper = new GPer();

    private GPer() {}

    public static GPer getInstance(){
        return gper;
    }

    public String getName() {
        return name;
    }

    public void publishQuestion(Question question){
        System.out.println(question.getUserName() + "在" + this.name + "上提交了一个问题。");
        setChanged();
        notifyObservers(question);
    }
}

观察者

public class Teacher implements Observer {

    private String name;

    public Teacher(String name) {
        this.name = name;
    }

    public void update(Observable o, Object arg) {
        GPer gper = (GPer)o;
        Question question = (Question)arg;
        System.out.println("======================");
        System.out.println(name + "老师,你好!n" +
                        "您收到了一个来自" + gper.getName() + "的提问,希望您解答。问题内容如下:n" +
                        question.getContent() + "n" +
                        "提问者:" + question.getUserName());
    }
}

client

public class Test {
    public static void main(String[] args) {
        GPer gper = GPer.getInstance();
        Teacher tom = new Teacher("Tom");
        Teacher jerry = new Teacher("Jerry");

        gper.addObserver(tom);
        gper.addObserver(jerry);

        //用户行为
        Question question = new Question();
        question.setUserName("张三");
        question.setContent("观察者模式适用于哪些场景?");

        gper.publishQuestion(question);
    }
}
spring事件的使用

spring中的事件模型可以直接把观察者,被观察者直接注入到容器中,并且不用维护观察者和被观察者的关系,spring讲会通过事件的类型自动做关联

定义事件需要继承ApplicationEvent

import org.springframework.context.ApplicationEvent;
public class CustomSpringEvent extends ApplicationEvent {
   private String message;

   public CustomSpringEvent(Object source, String message) {
   	super(source);
   	this.message = message;
   }
   public String getMessage() {
   	return message;
   }
}

被观察者(发布者)有spring容器实现,这里只是在调用spring提供的发布接口

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

@Component
public class CustomSpringEventPublisher {
	@Autowired
	private ApplicationEventPublisher applicationEventPublisher;

	public void publishCustomEvent(final String message) {
		System.out.println("Publishing custom event. ");
		CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
		applicationEventPublisher.publishEvent(customSpringEvent);
	}
}

观察者(订阅者)

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class CustomSpringEventListener implements ApplicationListener {
	@Override
	public void onApplicationEvent(CustomSpringEvent event) {
		System.out.println("Received spring custom event - " + event.getMessage());
	}
}

注解形式

@Component
public class AnnotationCustomSpringEventListener  {
	@EventListener
	public void onApplicationEvent(CustomSpringEvent event) {
		System.out.println("AnnotationCustomSpringEventListener - " + event.getMessage());
	}
}

这里涉及到的泛型注入,后面会写文章专门分析

spring事件原理分析

正式进入今天的正题,也是接着上篇继续分析refresh()方法,接下来我们来到了initApplicationEventMulticaster()和registerListeners()方法

initApplicationEventMulticaster
protected void initApplicationEventMulticaster() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
			this.applicationEventMulticaster =
					beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
			if (logger.isTraceEnabled()) {
				logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
			}
		}
		else {
			this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
			beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
			if (logger.isTraceEnabled()) {
				logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
						"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
			}
		}
	}

这里注册了一个applicationEventMulticaster事件多播器
相当于所有的发布者的入口,他可以发布所有的事件,这里会根据事件的类型找到所有订阅了该事件的监听者,然后调用监听者的监听方法
所以我们这里需要分析一下applicationEventPublisher.publishEvent(customSpringEvent)方法,其实是调用的
AnnotationConfigApplicationContext#publishEvent,我们也可以直接调用这个方法

点进去


这里获取到了上面注册的多播器,交给多播器处理

获取到所有的listener来执行,再详细的内容不再叙述

registerListeners
protected void registerListeners() {
		// Register statically specified listeners first.
		// 把所有的listener交给多播器
		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!
		// bdmap中的listener交给多播器
		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
		for (String listenerBeanName : listenerBeanNames) {
			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}

		// Publish early application events now that we finally have a multicaster...
		//发布已经存在的事件 默认为空
		Set earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}

这个方法注册了一些Listener,并可能发布一些事件

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/679079.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号