Spring Boot系列--启动方法解析监听器

参考版本:2.0.8.RELEASE

启动方法run中运行监听器的启动

查找 jar包中META-INF/spring.factories中SpringApplicationRunListener的定义,如果只引入了springbootstarter包的话,这里只定义了一个监听器EventPublishingRunListener 

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();

 SpringApplicationRunListeners:这个类是SpringApplicationRunListener的一个集合

public void starting() {
   for (SpringApplicationRunListener listener : this.listeners) {
      listener.starting();
   }
}

下面来看EventPublishingRunListener的starting方法

EventPublishingRunListener:继承了SpringApplicationRunListener,使用初始化好的事件广播器广播Application启动事件,这个类的接口实现主要有initialMulticaster来完成---装饰器模式

@Override
public void starting() {
   this.initialMulticaster.multicastEvent(
         new ApplicationStartingEvent(this.application, this.args));
}

 接下来看是如果广播事件的:spring中的事件监控--观察者模式

SimpleApplicationEventMulticaster:是接口ApplicationEventMulticaster的一个简单实现类,将所有的事件广播给所有的监听器,每个监听器只关心自己要监听的事件,不关心的就会忽略。默认在调用(当前)的线程中调用监听器,如果定义了线程池就会在新的线程中调用。
@Override
public void multicastEvent(ApplicationEvent event) {
   multicastEvent(event, resolveDefaultEventType(event));
}

@Override
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);
      }
   }
}

从代码getApplicationListeners(event, type)的结果来看,有以下四种监听器都监听了ApplicationStartingEvent,接下来每种监听器逐个执行

/**
 * 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);
   }
}
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())) {
         // 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;
      }
   }
}

接下来一个个看每个监听器在监听事件发生后都做了哪些事情 :

1、DelegatingApplicationListener:委派监听器,委派给那些在环境属性context.listener.classes指定的那些监听器。

@Override
public void onApplicationEvent(ApplicationEvent event) {
   if (event instanceof ApplicationEnvironmentPreparedEvent) {
      List<ApplicationListener<ApplicationEvent>> delegates = getListeners(
            ((ApplicationEnvironmentPreparedEvent) event).getEnvironment());
      if (delegates.isEmpty()) {
         return;
      }
      this.multicaster = new SimpleApplicationEventMulticaster();
      for (ApplicationListener<ApplicationEvent> listener : delegates) {
         this.multicaster.addApplicationListener(listener);
      }
   }
   if (this.multicaster != null) {
      this.multicaster.multicastEvent(event);
   }
}

2、LiquibaseServiceLocatorApplicationListener

3、BackgroundPreinitializer:对于一些耗时的任务使用一个后台线程尽早触发它们开始执行初始化,这是Springboot的缺省行为。这些初始化动作也可以叫做预初始化。 设置系统属性spring.backgroundpreinitializer.ignore为true可以禁用该机制。 该机制被禁用时,相应的初始化任务会发生在前台线程。

看看都做了哪些初始化任务:

// 记录预初始化任务是否已经在执行,初始值设置为false,表示未开始
    private static final AtomicBoolean preinitializationStarted = new AtomicBoolean(
            false);

    // 记录预初始化任务是否已经完成,1表示未完成,0表示完成
    private static final CountDownLatch preinitializationComplete = new CountDownLatch(1);

@Override
public void onApplicationEvent(SpringApplicationEvent event) {
   if (event instanceof ApplicationStartingEvent
         && preinitializationStarted.compareAndSet(false, true)) {
           //如果当前事件是ApplicationStartingEvent,并且预初始化任务尚未执行
            // 则 :将preinitializationStarted设置为预初始化任务开始执行;
            // 开始执行预初始化任务;

      performPreinitialization();
   }
   if ((event instanceof ApplicationReadyEvent
         || event instanceof ApplicationFailedEvent)
         && preinitializationStarted.get()) {
      try {
         preinitializationComplete.await();
      }
      catch (InterruptedException ex) {
         Thread.currentThread().interrupt();
      }
   }
}

private void performPreinitialization() {
   try {
      Thread thread = new Thread(new Runnable() {

         @Override
         public void run() {
            runSafely(new ConversionServiceInitializer());
            runSafely(new ValidationInitializer());
            runSafely(new MessageConverterInitializer());
            runSafely(new MBeanFactoryInitializer());
            runSafely(new JacksonInitializer());
            runSafely(new CharsetInitializer());
            preinitializationComplete.countDown();
         }

         public void runSafely(Runnable runnable) {
            try {
               runnable.run();
            }
            catch (Throwable ex) {
               // Ignore
            }
         }

      }, "background-preinit");
      thread.start();
   }
   catch (Exception ex) {
      // This will fail on GAE where creating threads is prohibited. We can safely
      // continue but startup will be slightly slower as the initialization will now
      // happen on the main thread.
      preinitializationComplete.countDown();
   }
}
4、LoggingApplicationListener:配置日志系统。如果有logging.config配置文件,就使用它启动日志系统,如果没有就使用默认配置。 
@Override
public void onApplicationEvent(ApplicationEvent event) {
   if (event instanceof ApplicationStartingEvent) {
      onApplicationStartingEvent((ApplicationStartingEvent) event);
   }
   else if (event instanceof ApplicationEnvironmentPreparedEvent) {
      onApplicationEnvironmentPreparedEvent(
            (ApplicationEnvironmentPreparedEvent) event);
   }
   else if (event instanceof ApplicationPreparedEvent) {
      onApplicationPreparedEvent((ApplicationPreparedEvent) event);
   }
   else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event)
         .getApplicationContext().getParent() == null) {
      onContextClosedEvent();
   }
   else if (event instanceof ApplicationFailedEvent) {
      onApplicationFailedEvent();
   }
}

本文通过查看监听器启动方法了解到springboot的一些内置监听器的作用,有一篇博客写的非常详细可参考:Springboot内置ApplicationListener

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用MySQL JDBC驱动解析MySQL binlog,可以使用下面的步骤: 1.添加MySQL JDBC驱动:在pom.xml文件中添加以下依赖项: ```xml <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.25</version> </dependency> ``` 2.编写代码:使用JDBC连接到MySQL数据库,并获取binlog事件流。可以使用以下示例代码: ```java import java.io.IOException; import java.sql.*; import com.github.shyiko.mysql.binlog.BinaryLogClient; import com.github.shyiko.mysql.binlog.event.*; public class BinlogParser { public static void main(String[] args) throws IOException { BinaryLogClient client = new BinaryLogClient("localhost", 3306, "username", "password"); client.registerEventListener(event -> { EventData data = event.getData(); if (data instanceof WriteRowsEventData) { WriteRowsEventData writeRowsEventData = (WriteRowsEventData) data; System.out.println(writeRowsEventData.getRows()); } else if (data instanceof UpdateRowsEventData) { UpdateRowsEventData updateRowsEventData = (UpdateRowsEventData) data; System.out.println(updateRowsEventData.getRows()); } else if (data instanceof DeleteRowsEventData) { DeleteRowsEventData deleteRowsEventData = (DeleteRowsEventData) data; System.out.println(deleteRowsEventData.getRows()); } }); client.connect(); } } ``` 3.运行代码:启动应用程序并运行binlog事件监听器。这将输出所有写入、更新和删除事件的行数据。 以上就是使用MySQL JDBC驱动解析MySQL binlog的基本步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值