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

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

观察者模式

public class Client {

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

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

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

        boolean detach(IObserver<E> observer);

        void notify(E event);
    }

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

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

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

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

        public void notify(E event) {
            for (IObserver<E> 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<CustomSpringEvent> {
	@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<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值