1.观察者模式
观察者模式是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。
1.为什么用观察者模式?
解耦。聚焦在自己的业务逻辑,不用管其他后续的逻辑。后续有新的业务逻辑直接添加即可,不用修改之前的代码。例如,停电不用挨家挨户告诉停电了,需要买蜡烛。只要把停电的消息发送出去,后续别人是买蜡烛还是手电筒就不用管了。
2.主题与观察者的关系
主题:存储观察者,调用观察者的行为
观察者:实现自己的行为
3.自己实现观察者模式
//抽象的主题
public interface ISubject {
//添加观察者
void addObserver(IObserver iObserver);
//删除观察者
void deleteObserver(IObserver iObserver);
//发布事件
void publish(Object o);
}
//具体的主题
public class ConcertSubject implements ISubject{
List<IObserver> list = new ArrayList<>();
@Override
public void addObserver(IObserver iObserver) {
list.add(iObserver);
}
@Override
public void deleteObserver(IObserver iObserver) {
list.remove(iObserver);
}
@Override
public void publish(Object event) {
for (IObserver iObserver : list) {
iObserver.update(event);
}
}
}
//抽象的观察者
public interface IObserver {
//观察者的行为
void update(Object tip);
}
//具体的观察者
public class ConcertObserver implements IObserver{
private String name;
public ConcertObserver(String name) {
this.name = name;
}
@Override
public void update(Object tip) {
System.out.println(name + tip.toString());
}
}
//被观察者发送的事件
public class Article {
private String author;
private String title;
public Article(String author, String title) {
this.author = author;
this.title = title;
}
public String getAuthor() {
return author;
}
public String getTitle() {
return title;
}
@Override
public String toString() {
return "收到了" + author + "发送的标题为‘" + title + "’的文章";
}
}
//主类运行
public class Test {
public static void main(String[] args) {
ISubject iSubject = new ConcertSubject();
IObserver reader1 = new ConcertObserver("张三");
IObserver reader2 = new ConcertObserver("李四");
iSubject.addObserver(reader1);
iSubject.addObserver(reader2);
iSubject.publish(new Article("bluesky","观察者模式"));
}
}
4.Java中内置类可以直接使用(Observer和Observable),将以上形式的代码进行了封装
//被观察者
public class Uploader extends Observable {
private String name;
public Uploader(String name) {
this.name = name;
}
public String getName() {
return name;
}
//object是向观察者发送的参数对象
public void publish(Object object) {
//changed变量置为true
setChanged();
//changed变量为true时,通知观察者
notifyObservers(object);
}
}
//观察者
public class Subscriber implements Observer {
private String name;
public Subscriber(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
//o是被观察对象,arg是被观察者发送的参数对象
public void update(Observable o, Object arg) {
Uploader up = (Uploader) o;
Vlog vlog = (Vlog) arg;
System.out.println(name + "关注的up:" + up.getName() + "更新了vlog'" + vlog.getName() + "'");
}
}
//被观察者发送的事件
public class Vlog {
private String name;
public Vlog(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
//主类
public class Test {
public static void main(String[] args) {
Uploader uploader = new Uploader("bluesky");
Subscriber fan1 = new Subscriber("fan1");
Subscriber fan2 = new Subscriber("fan2");
uploader.addObserver(fan1);
uploader.addObserver(fan2);
Vlog vlog = new Vlog("观察者模式");
uploader.publish(vlog);
}
}
5.SpringBoot中的观察者模式
//要发送的事件继承ApplicationEvent
public class MessageEvent extends ApplicationEvent {
private String name;
public MessageEvent(Object source, String name) {
super(source);
this.name = name;
}
public String getName() {
return name;
}
}
@Slf4j
@Component
public class MessagePublisher {
@Autowired
//使用该类发送消息
ApplicationEventPublisher publisher;
public void publishListener(MessageEvent messageEvent){
log.info("发送消息");
publisher.publishEvent(messageEvent);
}
}
@Slf4j
@Component
//监听消息的类实现ApplicationListener<T>,T为消息实体
public class MessageListener implements ApplicationListener<MessageEvent> {
@Override
public void onApplicationEvent(MessageEvent event) {
log.info("监听到的名字:"+event.getName());
}
}
SpringBoot中的观察者形式体现在哪?
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
Executor executor = this.getTaskExecutor();
//获取listener方法
Iterator var5 = this.getApplicationListeners(event, type).iterator();
while(var5.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var5.next();
if (executor != null) {
executor.execute(() -> {
//线程池中异步执行
this.invokeListener(listener, event);
});
} else {
this.invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
//监听出现异常处理
ErrorHandler errorHandler = this.getErrorHandler();
if (errorHandler != null) {
try {
this.doInvokeListener(listener, event);
} catch (Throwable var5) {
errorHandler.handleError(var5);
}
} else {
this.doInvokeListener(listener, event);
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
//执行listener.onApplicationEvent()方法
listener.onApplicationEvent(event);
} catch (ClassCastException var6) {
String msg = var6.getMessage();
if (msg != null && !this.matchesClassCastMessage(msg, event.getClass()) && (!(event instanceof PayloadApplicationEvent) || !this.matchesClassCastMessage(msg, ((PayloadApplicationEvent)event).getPayload().getClass()))) {
throw var6;
}
Log loggerToUse = this.lazyLogger;
if (loggerToUse == null) {
loggerToUse = LogFactory.getLog(this.getClass());
this.lazyLogger = loggerToUse;
}
if (loggerToUse.isTraceEnabled()) {
loggerToUse.trace("Non-matching event type for listener: " + listener, var6);
}
}
}
}
上述代码只是做到了同步解耦,大多数时候我们想要做异步解耦。对SpringBoot形式代码改造成异步解耦方式。
@Configuration
@Slf4j
public class EventConfig {
@Bean("applicationEventMulticaster")
public SimpleApplicationEventMulticaster customApplicationEventMulticaster(ConfigurableListableBeanFactory beanFactory, TaskExecutor taskExecutor) {
SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();
simpleApplicationEventMulticaster.setBeanFactory(beanFactory);
simpleApplicationEventMulticaster.setTaskExecutor(taskExecutor);
ErrorHandler errorHandler = new ErrorHandler() {
@Override
public void handleError(Throwable t) {
log.info("监听方法中出现了异常");
}
};
simpleApplicationEventMulticaster.setErrorHandler(errorHandler);
return simpleApplicationEventMulticaster;
}
}
- 配置了线程池,出现错误其他监听器正常执行
- 未配置线程池,配置ErrorHandler,出现错误打印日志,其他监听器正常执行。相当于进行了try cache
- 未配置线程池,未配置ErrorHandler,出现错误日志,直接崩,其他监听器不会正常执行
类加上@Async注解并配置线程池即可,可以实现发送消息的异步,不配置线程池,执行任务仍然是同步执行。
线程池中执行任务出现异常不会影响其他任务。
@Slf4j
@Component
public class MessageListener implements ApplicationListener<MessageEvent> {
@Async
@Override
public void onApplicationEvent(MessageEvent event) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("MessageListener监听到的名字:"+event.getName());
}
}
@Component
@Slf4j
public class MessageListener1 implements ApplicationListener<MessageEvent> {
@Async
@Override
public void onApplicationEvent(MessageEvent event) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("MessageListener1监听到的名字:"+event.getName());
}
}
使用@EventListener实现上述的内容
]()``` public class MessageEvent { private String name;
public MessageEvent(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
@Slf4j @Component public class MessagePublisher { @Autowired //使用该类发送消息 ApplicationEventPublisher publisher;
public void publishListener(MessageEvent messageEvent){
log.info("发送消息");
publisher.publishEvent(messageEvent);
}
}
@Slf4j @Component public class MessageListener {
@Async
@EventListener(value = MessageEvent.class)
public void listener(MessageEvent event){
log.info("MessageListener监听到的名字:"+event.getName());
}
}
@Slf4j @Component public class MessageListener1 { @Async @EventListener(value = MessageEvent.class) public void listener(MessageEvent event){ log.info("MessageListener1监听到的名字:"+event.getName()); } }
![图片转存失败,建议将图片保存下来直接上传
image.png(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a21ba4a49d3c4f7a99eafc05a5a856f7~tplv-k3u1fbpfcp-watermark.image?)
# 3.使用@EventListener可能会存在的问题,即无法读取到刚刚插入的数据
问题复现过程:业务逻辑实现需要,在一个有事务的方法中,插入一条数据,需要使用异步监听的方式查询这条数据
]()```
@Slf4j
@Service
public class MessageProblemImpl {
@Autowired
private ApplicationEventPublisher publisher;
@Autowired
private UserMapper userMapper;
@Transactional
public void insertThenQuery(){
userMapper.insert(new User(1L, "小明", 18));
publisher.publishEvent(new MessageEvent("测试插入数据后进行查询"));
log.info("数据插入成功");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
@Slf4j
@Component
public class MessageListener2 {
@Autowired
UserMapper userMapper;
@Async
@EventListener(value = MessageEvent.class,condition = "#event.name == '测试插入数据后进行查询'")
public void listener(MessageEvent event){
log.info("MessageListener1监听到的名字:"+event.getName());
Integer count = userMapper.selectCount(new LambdaQueryWrapper<>());
log.info("查询user表中数据的数量:" + count);
}
}
![图片转存失败,建议将图片保存下来直接上传
image.png(p6-juejin.byteimg.com/tos-cn-i-k3…?)
异步查询的时机在事务之前无法查询到插入的数据。
解决上述问题的方法
@TransactionalEventListener可以通过phase来保证事务提交之后在进行异步的查询 fallbackExecution 决定无事务是否执行,默认为false,即无事务不执行
]()``` //phase取值范围 public enum TransactionPhase { BEFORE_COMMIT, //事务提交之前 AFTER_COMMIT, //事务提交之后 AFTER_ROLLBACK, //回滚之后 AFTER_COMPLETION; //无论事务提交还是回滚之后进行
private TransactionPhase() {
}
}
@Slf4j @Component public class MessageListener2 { @Autowired UserMapper userMapper; @Async //@EventListener(value = MessageEvent.class,condition = "#event.name == '测试插入数据后进行查询'") @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, value = MessageEvent.class,condition = "#event.name == '测试插入数据后进行查询'") public void listener(MessageEvent event){ log.info("MessageListener1监听到的名字:"+event.getName()); Integer count = userMapper.selectCount(new LambdaQueryWrapper<>()); log.info("查询user表中数据的数量:" + count); } }
![图片转存失败,建议将图片保存下来直接上传
成功查询出了刚刚放进去的内容
image.png(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/94c0cdddcd7843b6bd10178551035fa3~tplv-k3u1fbpfcp-watermark.image?)
]()```
监听类执行的逻辑
public void onApplicationEvent(ApplicationEvent event) {
if (TransactionSynchronizationManager.isSynchronizationActive() && TransactionSynchronizationManager.isActualTransactionActive()) {
//有事务执行该逻辑
TransactionSynchronizationManager.registerSynchronization(new TransactionalApplicationListenerSynchronization(event, this, this.callbacks));
} else if (this.annotation.fallbackExecution()) {
//没有事务,判断fallbackExecution的值
if (this.annotation.phase() == TransactionPhase.AFTER_ROLLBACK && this.logger.isWarnEnabled()) {
this.logger.warn("Processing " + event + " as a fallback execution on AFTER_ROLLBACK phase");
}
this.processEvent(event);
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("No transaction is active - skipping " + event);
}
}