我们来通过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(),
这才是真正进行匹配的方法
匹配事件和源类型是否一致,一致才算做可以发送