观察者模式
观察者模式:Observer Pattern,又称为发布-订阅(Publish-Subscribe)模式,对象之间存在一对多或者一对一依赖,当一个对象改变状态,依赖它的对象会收到通知并自动更新。MQ其实就属于一致观察者模式,发布者发布消息,订阅者获取消息,订阅了就能收到信息,没有订阅的就收不到信息。其核心是将观察者和被观察者进行解耦,以类似消息/广播发送的机制联动两者,使被观察者的变动能通知到感兴趣的观察者们,从而做出响应。
特点
其优点是可以建立一对多的触发机制,但如果观察者的数量过多,则通知会耗时较长。
应用场景
比如初始化时将变动不是很大的数据加载进行,比如常用的配置信息、常用的字典数据、城市地区数据、相关商品分类、药品分类等.
扩展配置的方式
在ApplicationContext这个上下文中,进行初始化配置扩展的方法:
实现InitializingBean接口重写afterPropertiesSet方法
使用@PostConstruct
实现BeanPostProcessor后置处理器
采用FactoryBean
实现ApplicationListener接口
观察者模式例子
下面我们来看观察者模式中的一种:实现ApplicationListener接口
public class SpringApplicationTest {
/*****
* 1.创建ApplicationContext
* 2.执行相关事件ApplicationEvent:容器初始化完成
* 3.监听事件执行信息ApplicationListener
*/
public static void main(String[] args) {
//1.创建ApplicationContext,会立即加载Bean,加载完毕就相当于执行了事件
ApplicationContext act = new ClassPathXmlApplicationContext("spring-event.xml");
}
}
配置spring-event.xml信息:
<bean class="com.study.spring.ApplicationContextListener"></bean>
执行初始化,将数据放入到内存中,方便使用
public class ApplicationEventListener implements ApplicationListener<ContextRefreshedEvent> {
//发生指定事件后会触发该方法执行
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
ApplicationContext act = contextRefreshedEvent.getApplicationContext();
System.out.println("监听到容器初始化完成!");
//启动->从数据库加载对应的数据(省市区)、药品相关数据->填充Redis
}
}
执行的结果:
从执行的结果上看,其确实是执行了监听方法,是不是感觉很神奇。
调用过程:
下面我们来看看实现的过程:首先通过ClassPathXmlApplicationContext将配置进行读取、转换,变成bean,此时会将bean放入到:BeanDefintionMap中,初始化initApplicationEventMulticaster,调用注册监听方法 registerListeners(),将监听bean进行注册。然后调用 finishRefresh(),此时会将我们需要发布事件publishEvent进行执行,调用publishEvent,最终会调用doInvokerListenr,调用我们写的onApplicationEvent。
流程
下面看代码:
找到:
执行刷新操作,也是ClassPathXmlApplicationContext中最重要的方法。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//准备需要刷新的上下文
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//告诉子类去刷新bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//准备bean工厂
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//后置处理器bean工厂 ,运行后置处理bean工厂在子类上下文中
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//激活工厂处理器注册成bean在上下文中
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//注册拦截Bean创建的Bean处理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//为此上下文初始化消息源
initMessageSource();
// Initialize event multicaster for this context.
//为上下文初始化事件广播
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//在特定上下文子类中初始化其他特殊bean。
onRefresh();
// Check for listener beans and register them.
//检查监听器bean和注册它们
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//实例化所有剩余的(非延迟初始化)单例。
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//最后一步:发布相应的事件。
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
//最终放入缓存中
resetCommonCaches();
}
}
}
在prepareRefresh中:此时会创建this.earlyApplicationListeners:ApplicationListener对象 数据结构:LinkedHashedSet。
/**
* Prepare this context for refreshing, setting its startup date and
* active flag as well as performing any initialization of property sources.
*/
protected void prepareRefresh() {
// Initialize any placeholder property sources in the context environment.
initPropertySources();
// Store pre-refresh ApplicationListeners...
//存储前置刷新的ApplicationListener,可以看到其数据结构是LinkedHashSet
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
//ApplicationListener,可以看到其数据结构是LinkedHashSet
this.earlyApplicationEvents = new LinkedHashSet<>();
}
执行初始化initApplicationEventMulticaster(),此时会将我们定义的监听进行注册:此时BeanDefintionMap中已经放入
com.study.spring.ApplicationContextListener。
/**
* Initialize the ApplicationEventMulticaster.
* Uses SimpleApplicationEventMulticaster if none defined in the context.
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
*/
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() + "]");
}
}
}
SimpleApplicationEventMulticaster
/**
* Create a new SimpleApplicationEventMulticaster for the given BeanFactory.
*/
public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
setBeanFactory(beanFactory);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
if (beanFactory instanceof ConfigurableBeanFactory) {
ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;
if (this.beanClassLoader == null) {
this.beanClassLoader = cbf.getBeanClassLoader();
}
this.retrievalMutex = cbf.getSingletonMutex();
}
}
进行事件监听注册
/**
* Add beans that implement ApplicationListener as listeners.
* Doesn't affect other listeners, which can be added without being beans.
*/
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 (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
在执行FinshRefresh中会发布event:
/**
* Publish the given event to all listeners.
* <p>Note: Listeners get initialized after the MessageSource, to be able
* to access it within listener implementations. Thus, MessageSource
* implementations cannot publish events.
* @param event the event to publish (may be application-specific or a
* standard framework event)
*/
@Override
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
执行发布Event
/**
* Publish the given event to all listeners.
* @param event the event to publish (may be an {@link ApplicationEvent}
* or a payload object to be turned into a {@link PayloadApplicationEvent})
* @param eventType the resolved event type, if known
* @since 4.2
*/
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
//重要:拿到通过ApplicationEventMulticaster调用multicastEvent方法
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
查看multicastEvent
@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);
}
}
}
查看invokerListener
/**
* Invoke the given listener with the given event.
* @param listener the ApplicationListener to invoke
* @param event the current event to propagate
* @since 4.1
*/
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);
}
}
找到doInvokerListener
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
//调用onApplicationEvent
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// 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.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
调用我们写的方法
public class ApplicationContextListener implements ApplicationListener<ContextRefreshedEvent> {
//监听 ContextRefreshedEvent:容器完成初始化加载事件
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("事件执行完成之后监听方法");
ApplicationContext act = event.getApplicationContext();
//初始化数据数据操作
}
}
除此之外,还可以使用MessageEvent进行事件监听
使用MessageEvent进行事件监听
public class MessageEvent extends ApplicationEvent {
/***
* 可以用于传递数据
*/
public MessageEvent(Object source) {
super(source);
}
}
public class SpringContextTest {
public static void main(String[] args) {
ApplicationContext act = new ClassPathXmlApplicationContext("spring-event.xml");
//添加一个自定义事件
act.publishEvent(new MessageEvent("hello!"));
}
}
public class ApplicationContextListener implements ApplicationListener<ContextRefreshedEvent> {
//监听 ContextRefreshedEvent:容器完成初始化加载事件
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("事件执行完成之后监听方法");
ApplicationContext act = event.getApplicationContext();
//初始化数据数据操作
}
}
xml文件:
<bean class="com.study.spring.ApplicationEventListener"></bean>