我们来通过Spring这个框架来讲解其中设计的设计模式,Spring中包含的设计模式可以说有 观察者模式 职责链模式 策略模式 ,我们剖析Spring框架为了支持可扩展特性用的2种设计模式,观察者模式和模板模式

观察者模式在Spring中应用

在Java和Guava中都提供了观察者模式的实现框架,Java提供的框架比较简单,只包含了Java.util.Observable和Java.util.Observer两个类,Guava提供了EventBus事件总线实现观察者模式,Spring也提供了观察者模式的实现框架

Spring中实现的观察者包含了三个部分 Event事件,Listen监听者,Publisher发送者(相当于被观察者)

// Event事件

public class DemoEvent extends ApplicationEvent {

private String message;

public DemoEvent(Object source, String message) {

super(source);

}

public String getMessage() {

return this.message;

}

}

// Listener监听者

@Component

public class DemoListener implements ApplicationListener<DemoEvent> {

@Override

public void onApplicationEvent(DemoEvent demoEvent) {

String message = demoEvent.getMessage();

System.out.println(message);

}

}

// Publisher发送者

@Component

public class DemoPublisher {

@Autowired

private ApplicationContext applicationContext;

public void publishEvent(DemoEvent demoEvent) {

this.applicationContext.publishEvent(demoEvent);

}

}

上面的代码中包含了三个部分,一个是继承ApplicationEvent的事件 DemoEvent,一个是实现了ApplicationListener的监听器,DemoListener,一个发送者 DemoPublisher,发送者调用ApplicationContext来发送事件消息

其中,ApplicationEvent和ApplicationListener的代码实现比较容易.内部并不需要太多的属性和方法,继承了ApplicationEvent的类是事件,实现ApplicationListener的类是监听器

public abstract class ApplicationEvent extends EventObject {

private static final long serialVersionUID = 7099057708183571937L;

private final long timestamp = System.currentTimeMillis();

public ApplicationEvent(Object source) {

super(source);

}

public final long getTimestamp() {

return this.timestamp;

}

}

public class EventObject implements java.io.Serializable {

private static final long serialVersionUID = 5516075349620653480L;

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 String toString() {

return getClass().getName() + “[source=” + source + “]”;

}

}

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

void onApplicationEvent(E var1);

}

在Spring中,我们将观察者注册到了ApplicationContext对象中,ApplicationContext这个类不只是给观察者模式服务的,其底层依赖于BeanFactory,提供了应用启动,运行时的上下文的信息

具体到源码上来说,ApplicationContext只是一个接口,具体的代码实现包含在其实现类AbstarctApplicationContext中,我们把其和观察者模式相关的代码摘抄到了下面,关于其如何发送事件和注册观察者我们需要仔细的看一下

public abstract class AbstractApplicationContext extends … {

private final Set<ApplicationListener<?>> applicationListeners;

public AbstractApplicationContext() {

this.applicationListeners = new LinkedHashSet();

//…

}

public void publishEvent(ApplicationEvent event) {

this.publishEvent(event, (ResolvableType)null);

}

public void publishEvent(Object event) {

this.publishEvent(event, (ResolvableType)null);

}

protected void publishEvent(Object event, ResolvableType eventType) {

//…

Object applicationEvent;

if (event instanceof ApplicationEvent) {

applicationEvent = (ApplicationEvent)event;

} else {

applicationEvent = new PayloadApplicationEvent(this, event);

if (eventType == null) {

eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();

}

}

if (this.earlyApplicationEvents != null) {

this.earlyApplicationEvents.add(applicationEvent);

} else {

this.getApplicationEventMulticaster().multicastEvent(

(ApplicationEvent)applicationEvent, eventType);

}

if (this.parent != null) {

if (this.parent instanceof AbstractApplicationContext) {

((AbstractApplicationContext)this.parent).publishEvent(event, eventType);

} else {

this.parent.publishEvent(event);

}

}

}

public void addApplicationListener(ApplicationListener<?> listener) {

Assert.notNull(listener, “ApplicationListener must not be null”);

if (this.applicationEventMulticaster != null) {

this.applicationEventMulticaster.addApplicationListener(listener);

} else {

this.applicationListeners.add(listener);

}

}

public Collection<ApplicationListener<?>> getApplicationListeners() {

return this.applicationListeners;

}

protected void registerListeners() {

Iterator var1 = this.getApplicationListeners().iterator();

while(var1.hasNext()) {

ApplicationListener<?> listener = (ApplicationListener)var1.next();     this.getApplicationEventMulticaster().addApplicationListener(listener);

}

String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false);

String[] var7 = listenerBeanNames;

int var3 = listenerBeanNames.length;

for(int var4 = 0; var4 < var3; ++var4) {

String listenerBeanName = var7[var4];

this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);

}

Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;

this.earlyApplicationEvents = null;

if (earlyEventsToProcess != null) {

Iterator var9 = earlyEventsToProcess.iterator();

while(var9.hasNext()) {

ApplicationEvent earlyEvent = (ApplicationEvent)var9.next();

this.getApplicationEventMulticaster().multicastEvent(earlyEvent);

}

}

}

}

其实真正的发送,是通过ApplicationEventMulticaster这个了完成的,也就是multicastEvent()消息发送函数.不过,它的代码并不复杂,其通过线程池,异步非阻塞,同步阻塞两种类型的观察者模式

public void multicastEvent(ApplicationEvent event) {

this.multicastEvent(event, this.resolveDefaultEventType(event));

}

public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {

ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);

Iterator var4 = this.getApplicationListeners(event, type).iterator();

while(var4.hasNext()) {

final ApplicationListener<?> listener = (ApplicationListener)var4.next();

Executor executor = this.getTaskExecutor();

if (executor != null) {

executor.execute(new Runnable() {

public void run() {

SimpleApplicationEventMulticaster.this.invokeListener(listener, event);

}

});

} else {

this.invokeListener(listener, event);

}

}

}

解除Spring提供的观察者框架,我们要在Spring中实现某个实践的发送和监听,只需要做很少的工作,定义事件,定义监听器,往ApplicationContext中发送事件就可以了,剩下的交给Spring框架来完成,实际上,体现了Spring框架的扩展性,在不修改任何代码的情况下,扩展新的事件和监听

模板模式在Spring中的应用

刚刚说的是观察者模式在Spring中的应用,再讲讲模板模式,

Spring中创建一个对象,会简单的分为两个步骤,对象的创建和对象的初始化

对象的创建是通过反射来动态的生成对象,而不是new,

而Spring中可以指定使用哪个构造函数,或者初始化函数

可以在配置文件汇总配置构造函数名

public class DemoClass {

//…

public void initDemo() {

//…初始化..

}

}

// 配置:需要通过init-method显式地指定初始化方法

<bean id=”demoBean” class=”com.xzg.cd.DemoClass” init-method=”initDemo”></bean>

这种初始化方法有一个缺点,初始化函数并不固定,由用户随意定义,这就需要Spring通过反射,在运行时候动态的调用这个初始化函数,而反射会影响到代码执行的性能

于是,可以使用第二种方法

让类实现Initializingbean接口,这个接口包含一个固定的初始化函数,afterProperitiesSet()函数,Spring初始化的时候,直接通过bean.afterPropertiresSet()方式,调用Bean上的函数,就不需要反射调用了

public class DemoClass implements InitializingBean{

@Override

public void afterPropertiesSet() throws Exception {

//…初始化…

}

}

// 配置:不需要显式地指定初始化方法

<bean id=”demoBean” class=”com.xzg.cd.DemoClass”></bean>

这种实现方式不会用到反射,执行效率提高了,但是业务代码和框架代码耦合在一起了,所以并不推荐,在Spring对一个Bean的生命周期的管理,还有一个跟初始化对应的过程,对Bean销毁的过程,这时候,也是如此,分别具有destory-methord指定类中的销毁函数,或者让类实现一个DisposableBean接口,和init接口相似

而且在Bean的生命周期中,还有初始化前置操作,初始化,初始化后置操作.其中,中间的初始化操作就是刚刚说的部分,至于初始化的前置和后置操作,定义在BeanPostProcessor中

public interface BeanPostProcessor {

Object postProcessBeforeInitialization(Object var1, String var2) throws BeansException;

Object postProcessAfterInitialization(Object var1, String var2) throws BeansException;

}

那么我们实现了一个BeanPostProcessor接口的处理器类,并在配置文件中像配置普通Bean就行了,那么需要被进行配置的Bean,就会被这些处理器去调用处理

图片

这就是Spring通过的模板模式,通过提供了扩展点,来把执行的函数封装成对象,传递给模板去执行

本章重点:

本章讲解了Spring中提供的两种支持扩展的设计模式,观察者模式和模板模式.

其中观察者模式在Java,Google Guava,Spring中都有对应的实现代码,在平时的项目开发中,我们也经常使用

Java提供的最为简单,只包含了java.util.Observable和java.util.Observer两个类,Google Guvava提供的框架比较完善,通过EventBus事件来完成的,Spring提供的观察者模式,包含了Event事件,Listener监听者,Publisher发送者三部分,事件发送到ApplicationContext中,最后发送到实现注册号的监听者中

除此之外,我们还说了模板方法在Spring中的一个典型应用,Bean的创建过程,创建包含两个大的部分,对象的创建和初始化,其中对象的初始化分为了三个小的步骤,初始化前置操作,初始化,初始化后置操作

课后小结:

Spring提供的观察者模式的实现中,能否也按照消息类型来匹配观察者呢?如果可以,如何实现的呢?

看了下源码,其流程可以从

图片

推送Event时候,去发送Event开始走

主要就是这个

void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);

在此方法中,会调用getApplicationListeners(event,eventType)函数

图片

在这个方法中,会获取到对应的所有监听者,如何获取到的,会先通过一个锁来从一个名为retrieverCache的map中尝试获取到对应的监听者

如果拿不到,会进入到retrieveApplicationListeners()这个函数之中

图片

在这个方法中,会在add返回的结果的时候,会调用一个方法supportsEvent(),

这才是真正进行匹配的方法

图片

匹配事件和源类型是否一致,一致才算做可以发送

发表评论

邮箱地址不会被公开。 必填项已用*标注