观察者设计模式特性
被观察者有观察者的引用
观察者不能主动发起操作, 需要等被观察者通知
在JDK中通过继承Observable类作为一个被观察者, 实现Observer接口作为一个观察者
模拟场景 天气变化, 任何狗做出不同反应
public class WeatherObservable extends Observable {
private int temperature;
public int getTemperature() {
return temperature;
}
public void setTemperature(int temperature) {
this.temperature = temperature;
setChanged();
notifyObservers();
}
}
public class DogObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
if (o instanceof WeatherObservable) {
WeatherObservable weatherObservable = (WeatherObservable) o;
if (weatherObservable.getTemperature() < 0) {
System.out.println("狗不出窝");
} else if (weatherObservable.getTemperature() > 24) {
System.out.println("狗吐口水");
} else {
System.out.println("狗正常活动");
}
}
}
}
public class PersonObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
if (o instanceof WeatherObservable) {
WeatherObservable weatherObservable = (WeatherObservable) o;
if (weatherObservable.getTemperature() < 10) {
System.out.println("人穿羽绒服");
} else if (weatherObservable.getTemperature() > 24) {
System.out.println("人穿短袖");
} else {
System.out.println("人正常活动");
}
}
}
}
public class Test {
public static void main(String[] args) {
WeatherObservable weatherObservable = new WeatherObservable();
weatherObservable.addObserver(new PersonObserver());
weatherObservable.addObserver(new DogObserver());
for (int i = -8; i < 30; i = i + 3) {
System.out.println("当前温度: " + i + " 度");
weatherObservable.setTemperature(i);
System.out.println("--------------------------");
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果
当前温度: -8 度
狗不出窝
人穿羽绒服
--------------------------
当前温度: -3 度
狗不出窝
人穿羽绒服
--------------------------
当前温度: 2 度
狗正常活动
人穿羽绒服
--------------------------
当前温度: 7 度
狗正常活动
人穿羽绒服
--------------------------
当前温度: 12 度
狗正常活动
人正常活动
--------------------------
当前温度: 17 度
狗正常活动
人正常活动
--------------------------
当前温度: 22 度
狗正常活动
人正常活动
--------------------------
当前温度: 27 度
狗吐口水
人穿短袖
--------------------------
Spring中Event使用
通过继承ApplicationEvent即可完成一个事件的封装, 然后实现ApplicationListener对事件作出反馈
public class FinishEvent extends ApplicationEvent {
private String message;
public FinishEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}
@Component
public class FinishEventListener implements ApplicationListener<FinishEvent> {
@Override
public void onApplicationEvent(FinishEvent event) {
System.out.println("监听者收到信息: " + event.getMessage());
}
}
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
@ResponseBody
@GetMapping("/finish")
public String finish() {
applicationEventPublisher.publishEvent(new FinishEvent(applicationEventPublisher, "已完成"));
return null;
}
调用finish接口, 直接打印 监听者收到信息: 已完成
Spring中也有一些已经定义好的Event, 可以添加监听器, 在条件满足时, 触发listener执行相关操作
@Component
public class ContextRefreshEventListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("容器刷新完成....");
System.out.println(((ApplicationContext) event.getSource()).getBean(TestController.class));
}
}
运行结果
容器刷新完成....
com.cloud.demo.controller.TestController@46fb0c33
源码分析
Spring容器初始化
org.springframework.context.support.AbstractApplicationContext#refresh
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
// 初始化
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
...
}
finally {
...
}
}
}
ApplicationEventMulticaster监听器的持有和事件的发起都是靠通过此对象完成的
org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 判断容器内是有有对应的bean 名称 applicationEventMulticaster
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() + "]");
}
}
}
org.springframework.context.support.AbstractApplicationContext#registerListeners
protected void registerListeners() {
// Register statically specified listeners first.
// 首先从容器中获取直接存放各ApplicationListener 通过ac.addApplicationListener()方法存入
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!
// 通过类型从容器中获取ApplicationListener
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...
// 对earlyApplicationEvents发起事件通知
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
Spring在初始化前后都有对监听器的事件通知, 最后都会调用multicastEvent方法
org.springframework.context.event.SimpleApplicationEventMulticaster
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
// 获取通知类型
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 根据类型查找监听器 并循环调用
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
// 如果有线程池执行器 则放入到执行器中
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
// 同步调用
invokeListener(listener, event);
}
}
}
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);
}
}
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.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}