本篇文章我们接着上一篇的文章,简单回顾一下
上一篇文章主要是看到Spring中在执行prepareBeanFactory方法的时候
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
会往容器中添加两个BeanPostProcessor接口的实现类的实例对象。接口中都有一个postProcessBeforeInitialization待实现的方法。而这个方法会在spring进行初始化bean对象的时候,会先通过以下方法获取得到接口的所有实现类名称。然后获取到想要对应的对象,将该对象放入List数组中,最后进行调用postProcessBeforeInitialization方法。String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
所以总结起来BeanPostProcessor接口的实现类,就像一节一节的管道,每当创建了一个bean。这个bean都会通过BeanPostProcessor接口实现类的postProcessBeforeInitialization方法进行处理一下。是一个串行的动作。
本篇文章我们来看一下Spring中的事件以及监听器。为什么要分析事件和监听器,其实源于beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); 其中ApplicationListenerDetecto部分源码如下
代码块一
class ApplicationListenerDetector implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor {
private static final Log logger = LogFactory.getLog(ApplicationListenerDetector.class);
private final transient AbstractApplicationContext applicationContext;
private final transient Map<String, Boolean> singletonNames = new ConcurrentHashMap<>(256);
public ApplicationListenerDetector(AbstractApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
this.singletonNames.put(beanName, beanDefinition.isSingleton());
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
// potentially not detected as a listener by getBeanNamesForType retrieval
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
// singleton bean (top-level or inner): register on the fly
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
}
else if (Boolean.FALSE.equals(flag)) {
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
// inner bean with other scope - can't reliably process events
logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
"but is not reachable for event multicasting by its containing ApplicationContext " +
"because it does not have singleton scope. Only top-level listener beans are allowed " +
"to be of non-singleton scope.");
}
this.singletonNames.remove(beanName);
}
}
return bean;
}
可以看到postProcessMergedBeanDefinition方法中先判断是不是监听器的实例。如果是的话就将其添加到一个list中,以备后用。
重点来了,Spring中监听器是监听事件的。而这个地方。使用到一种设计模式,叫观察者模式。本着能从Spring源码中学到更多的东西。所以我们先去分析一下观察者模式。
由于作者才疏学浅,对设计模式一知半解,如果读者想深入了解设计模式,推荐阅读设计模式之禅。我这里就简单的说一下这个设计模式自己的一些理解。
- 被观察者
也就是被观察的目标,目标对象。比如我们关注了某个公众号,那么这个公众号就是被观察者,我们自己就是观察者
- 观察者
关注公众号的读者,就是观察者
现在我们关注的公众号发布了一篇最新的文章,我们是怎么知道这发布了这篇最新的文章呢。其实有多种方式,
第一种:我们可以自己主动去浏览公众号发布的文章,可以找到最新发布的那一篇文章。(观察者主动)
第二种:公众号发布了最新的文章,然后微信通知了我们说你关注的公众号发布了最新的文章哟,请阅读。(观察者被动)
这里我们只讲解第二种方式
其实java jdk中已经提供了,观察者和被观察者的接口,我们可以看一下。
首先是被观察者,源码如下,首先这个被观察者有一个集合obs,其实是一个观察者的集合,也就类比,关注了公众号的读者集合。被观察者接口可以添加,删除观察者。最重要的是notifyObservers方法,这个方法是通知所有的观察者,通知说我已经有动作变更。(Observer)arrLocal[i]).update(this, arg)。可以看到notifyObservers这个方法当中,调用了观察者对象的update方法,将变更的消息传递过去。
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
/** Construct an Observable with zero Observers. */
public Observable() {
obs = new Vector<>();
}
/**
* Adds an observer to the set of observers for this object, provided
* that it is not the same as some observer already in the set.
* The order in which notifications will be delivered to multiple
* observers is not specified. See the class comment.
*
* @param o an observer to be added.
* @throws NullPointerException if the parameter o is null.
*/
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
/**
* Deletes an observer from the set of observers of this object.
* Passing <CODE>null</CODE> to this method will have no effect.
* @param o the observer to be deleted.
*/
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
/**
* If this object has changed, as indicated by the
* <code>hasChanged</code> method, then notify all of its observers
* and then call the <code>clearChanged</code> method to
* indicate that this object has no longer changed.
* <p>
* Each observer has its <code>update</code> method called with two
* arguments: this observable object and <code>null</code>. In other
* words, this method is equivalent to:
* <blockquote><tt>
* notifyObservers(null)</tt></blockquote>
*
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#hasChanged()
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void notifyObservers() {
notifyObservers(null);
}
/**
* If this object has changed, as indicated by the
* <code>hasChanged</code> method, then notify all of its observers
* and then call the <code>clearChanged</code> method to indicate
* that this object has no longer changed.
* <p>
* Each observer has its <code>update</code> method called with two
* arguments: this observable object and the <code>arg</code> argument.
*
* @param arg any object.
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#hasChanged()
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;
synchronized (this) {
/* We don't want the Observer doing callbacks into
* arbitrary code while holding its own Monitor.
* The code where we extract each Observable from
* the Vector and store the state of the Observer
* needs synchronization, but notifying observers
* does not (should not). The worst result of any
* potential race-condition here is that:
* 1) a newly-added Observer will miss a
* notification in progress
* 2) a recently unregistered Observer will be
* wrongly notified when it doesn't care
*/
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
/**
* Clears the observer list so that this object no longer has any observers.
*/
public synchronized void deleteObservers() {
obs.removeAllElements();
}
}
我们看一下观察者类的源码 ,它是一个接口,只有一个方法,update方法。我们的观察者只需要实现这个方法,那么他就是一个观察者类了。
package java.util;
/**
* A class can implement the <code>Observer</code> interface when it
* wants to be informed of changes in observable objects.
*
* @author Chris Warth
* @see java.util.Observable
* @since JDK1.0
*/
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
void update(Observable o, Object arg);
}
观察者模式我们就简单讲解到这里。接下来我们说一下Spring中是怎么应用这个观察者模式,实现了事件和监听器机制
首先我们可以看到在代码块有以下代码,往容器的ApplicationListener 这个set中添加了观察者,那这个时候我们可以把容器想成一个被观察者对象。
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
接着我们看一下我们的观察者ApplicationListener提供给被观察者调用的方法是哪一个。也就是传递消息到观察者的方法。源码如下可以看到有一个onApplicationEvent方法,也就是和上面的update方法一样,就是传递消息的。
/**
* Interface to be implemented by application event listeners.
* Based on the standard {@code java.util.EventListener} interface
* for the Observer design pattern.
*
* <p>As of Spring 3.0, an ApplicationListener can generically declare the event type
* that it is interested in. When registered with a Spring ApplicationContext, events
* will be filtered accordingly, with the listener getting invoked for matching event
* objects only.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @param <E> the specific ApplicationEvent subclass to listen to
* @see org.springframework.context.event.ApplicationEventMulticaster
*/
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
那么我们的被观察者,是在上面时候调用的呢。其实我们找到refresh()方法下面的 registerListeners()方法查看该方法的源码,首先把我们的所有已经创建好观察者遍历出来放入getApplicationEventMulticaster().addApplicationListener(listener);
protected void registerListeners() {
// Register statically specified listeners first.
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!
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 (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
然后最终执行的代码是,可以看到我们的被观察者调用了观察的对象的onApplication方法通知观察者。
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass().getName())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
本篇文章我们先讲解到这里。简单总结一下
因为我们的观察者也是一个bean,所以在初始化这个bean的时候,也是会遍历的执行容器中定义的BeanPostProcessor的接口实现类,实现的postProcessBeforeInitialization。或者我们自己实现的接口实现类实现的postProcessBeforeInitialization这个方法。观察者bean在执行到这个方法的是,会被添加到容器的观察者集合中。然后我们后面registerListeners()中容器会调用这些容器内已有观察者定义的onApplication方法。或者我们自定义观察者的方法。前提也是我们的实现了ApplicationListener 这个接口的观察者,需要注入到容器中。