Spring是目前Java企业级开发应用广泛的框架之一,其具有强大的生态,且得益于其提供的高扩展能力,能够减少开发成本,提高开发效率。如此优秀的框架,当然离不开各种设计模式,本文主要介绍设计模式中的观察者模式在Spring框架中的应用。
观察者模式属于三种设计模式分类中的** 行为型模式**,当对象之间存在一对多,且“一”变化时,需要“多”进行同步变化/通知的行为时,则可以使用观察者模式来实现。观察者模式的设计可以通过在被观察者对象中存放观察者对象的集合,当被观察的变化信息需要通知到观察者时,则去遍历执行观察者对象集合中的每一个观察者,实现一对多的通知。通过集合来完成一对多关系的依赖,从而实现行为通知,可以降低耦合程度。下面我们来看下观察者模式的简单实现。
//观察的主题(被观察者)
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();
}
//观察者实现1
public class AddObserver{
public AddObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "加法观察者:" + subject.getState());
}
}
//观察者实现2
public class MinusObserver{
public AddObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "减法观察者:" + subject.getState());
}
}
Spring框架中对观察者模式的应用也很多,在Spring容器启动过程中涉及到很多监听器(listener)的注册以及委托多路广播(ApplicationEventMulticaster)进行事件(event)的发布(publish),其运用到的就是观察者模式。通过时间的发布/广播通知到各个注册的监听器实现一对多的行为,使得一对多的依赖耦合程度降低,下面来看一下其源码实现过程。
//我们从Spring容器的刷新refresh方法开始
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
initMessageSource();
//1.初始化应用事件多路广播Bean对象,将Bean对象添加到Spring容器中
initApplicationEventMulticaster();
onRefresh();
//2.注册监听器
registerListeners();
finishBeanFactoryInitialization(beanFactory);
//3.完成刷新
finishRefresh();
}
//...省略
首先,在Spring容器刷新过程中,会先将ApplicationEventMulticaster进行初始化,将其对象创建并添加在Spring容器中。
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);
//...省略日志
}
else {
//没有则创建一个SimpleApplicationEventMulticaster对象并通过registerSingleton注册到Spring容器中,方便后面使用
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
//...省略日志
}
}
然后,便会将实现了ApplicationListener的监听器注册到上述初始化完成的ApplicationEventMulticaster广播器当中,并执行最早的应用事件的广播,将事件通知到注册在多路广播器的监听器中。
protected void registerListeners() {
//注册监听器
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
//发布最早的应用事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
//委托广播器,对监听器进行事件的发布,下面的时间广播方法
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
//如果存在线程池,使用异步通知方式,如果不存在则使用同步通知方式
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
Spring会委托多路广播进行事件的发布通知时,当有线程池存在时,则会使用异步通知的方式来实现观察者模式,若不存在则使用同步方式来通知观察者。
//此时,完成监听器的事件通知
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
//调用下面方法
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
//此处完成观察者的事件通知
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
//...省略
}
}
再梳理一遍Spring整个观察者模式的设计思路:
1、首先是应用事件ApplicationEvent,它继承于Java API中的EventObject,用于观察者(监听器)的通知入参对象。
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 ApplicationEvent(Object source, Clock clock) {
super(source);
this.timestamp = clock.millis();
}
public final long getTimestamp() {
return this.timestamp;
}
}
2、然后就是观察者的设计也即ApplicationListener应用监听器的设计,通过重写onApplicationEvent方法来实现不同的观察者,此接口也是使用函数式接口,可以利用lambda表达式来实现。
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
//事件通知方法
void onApplicationEvent(E event);
static <T> ApplicationListener<PayloadApplicationEvent<T>> forPayload(Consumer<T> consumer) {
return event -> consumer.accept(event.getPayload());
}
}
3、最后,是ApplicationEventMulticaster应用事件多路广播器接口,实际上它是在被观察者上进行的扩展,用于注册监听器,卸载监听器以及实现事件广播,利用广播器来实现观察者模式设计过程中观察者与被观察者的强耦合。
public interface ApplicationEventMulticaster {
//注册监听器
void addApplicationListener(ApplicationListener<?> listener);
void addApplicationListenerBean(String listenerBeanName);
//卸载监听器
void removeApplicationListener(ApplicationListener<?> listener);
void removeApplicationListenerBean(String listenerBeanName);
void removeApplicationListeners(Predicate<ApplicationListener<?>> predicate);
void removeApplicationListenerBeans(Predicate<String> predicate);
void removeAllListeners();
//事件广播(通知每一个监听器/观察者)
void multicastEvent(ApplicationEvent event);
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
本文简述了设计模式中的观察者模式以及Spring容器启动过程中观察者模式的应用,它是一种解决一对多关系,且一个变化需要通知到另外多个变化的场景。通过观察者模式的设计,可以减少一对多之间的强依赖和强耦合关系,并将变化一方封装,实现可复用性。Spring框架中的监听器即是在观察者设计模式上的演变,通过事件event,监听器listener以及广播器caster来实现观察者模式,可以将应用启动过程中的每一个步骤都进行观察,每到一个步骤时进行通知,从而降低框架耦合程度,并提供应用启动的可扩展空间。