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,并可能发布一些事件