草庐IT

SpringBoot的多种事件监听机制

梦中残影如月 2023-04-16 原文

前置配置

# META-INF/spring.factories文件配置
# ApplicationContextInitializer
org.springframework.context.ApplicationContextInitializer=com.test.springbootdemo.eventListeners.MyApplicationContextInitializer
# ApplicationListener
org.springframework.context.ApplicationListener=com.test.springbootdemo.eventListeners.MyApplicationListener
# SpringApplicationRunListener
org.springframework.boot.SpringApplicationRunListener=com.test.springbootdemo.eventListeners.MySpringApplicationRunListener

 

ApplicationContextInitializer接口

代码示例

public class MyApplicationContextInitializer implements ApplicationContextInitializer {
    //run方法this.prepareContext触发
    //进一步则是this.applyInitializers
    //在进一步则是initializer.initialize(context);
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("ApplicationContextInitializer.....initialize");
    }
}

说明

  1.由于触发阶段在于准备容器的时候,所以添加@Component注解是不会起作用的,应为@Component注解需要在容器刷新时候才会起到作用。

 

ApplicationListener接口

代码示例

public class MyApplicationListener implements ApplicationListener {
    //run方法listeners.starting,触发第一次
    //run方法this.prepareEnvironment,触发第二次
    //即进一步,listeners.environmentPrepared
    //run方法this.prepareContext,触发第三次与触发第四次
    //进一步则是listeners.contextPrepared(context);触发第三次
    // listeners.contextLoaded(context);触发第四次
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextStartedEvent){
            System.out.println("ContextStartedEvent1.....run()");
        }

        System.out.println("Event1.....run()");

    }
}

@Component
public class MyApplicationListener2 implements ApplicationListener {
    //容器refresh()的时候触发
    //进一步finishRefresh();
    //再进一步getLifecycleProcessor().onRefresh();
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextStartedEvent){
            System.out.println("ContextStartedEvent2.....run()");
        }

        System.out.println("Event2.....run()");
    }
}

说明

  1.存在两种注册方式:

    1)@Component注解注册,这种需要在容器刷新后的finishRefresh()方法里面触发,然后监听到全部事件

    2)配置文件注册,这种会在SpringBoot中开启listeners,让listeners准备环境,准备容器等都会触发。包括容器刷新后的finishRefresh()方法里面都会触发【包括了注解修饰的部分】

 

ApplicationRunner接口

代码示例

@Component
public class MyApplicationRunner implements ApplicationRunner {
    //run方法this.callRunners,第一次触发
    //进一步,this.callRunner
    //在进一步,runner.run(args);
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner.....run()");
    }
}

说明

  1.这种只能在容器启动后进行触发

  2.与CommandLineRunner接口其实并没有很大差别,都在同一个方法内被调用,调用同一个触发方法。但是会优于CommandLineRunner被调用。

 

CommandLineRunner接口

代码示例

@Component
public class MyCommandLineRunner implements CommandLineRunner {
    //run方法this.callRunners,第一次触发
    //进一步,this.callRunner
    //在进一步,runner.run(args);
    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner.....run()");
    }
}

说明

  1.这种只能在容器启动后进行触发

  2.与ApplicationRunner接口其实并没有很大差别,都在同一个方法内被调用,调用同一个触发方法。但是会晚于ApplicationRunner被调用。

 

SpringApplicationRunListener接口

代码示例

public class MySpringApplicationRunListener implements SpringApplicationRunListener {
    public MySpringApplicationRunListener(SpringApplication springApplication, String[] arg) {
    }

    //run方法listeners.starting触发
    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        System.out.println("SpringApplicationRunListener.....starting()");
    }

    //run方法this.prepareEnvironment触发
    //进一步listeners.environmentPrepared
    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        System.out.println("SpringApplicationRunListener.....environmentPrepared()");
    }

    //run方法this.prepareContext触发
    //进一步listeners.contextPrepared(context);
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("SpringApplicationRunListener.....contextPrepared()");
    }

    //run方法this.prepareContext触发
    //进一步listeners.contextLoaded(context);
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("SpringApplicationRunListener.....contextLoaded()");
    }

    //run方法listeners.started(context, timeTakenToStartup);触发
    @Override
    public void started(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("SpringApplicationRunListener.....started()");
    }

    @Override
    public void started(ConfigurableApplicationContext context) {
        System.out.println("SpringApplicationRunListener.....started()");
    }

    //run方法listeners.ready(context, timeTakenToReady);触发
    @Override
    public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("SpringApplicationRunListener.....ready()");
    }

    @Override
    public void running(ConfigurableApplicationContext context) {
        System.out.println("SpringApplicationRunListener.....running()");
    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("SpringApplicationRunListener.....failed()");
    }
}

说明

  1.这个比较有意思在容器Refresh()前后都会触发,包括各种处理环境,准备容器等步骤。

有关SpringBoot的多种事件监听机制的更多相关文章

  1. ruby - nanoc 和多种布局 - 2

    是否可以为特定(或所有)项目使用多个布局?例如,我有几个项目,我想对其应用两种不同的布局。一个是绿色的,一个是蓝色的(但是)。我想将它们编译到我的输出目录中的两个不同文件夹中(例如v1和v2)。我一直在玩弄规则和编译block,但我不知道这是怎么回事。因为,每个项目在编译过程中只编译一次,我不能告诉nanoc第一次用layout1编译,第二次用layout2编译。我试过这样的东西,但它导致输出文件损坏。compile'*'doifitem.binary?#don’tfilterbinaryitemselsefilter:erblayout'layout1'layout'layout2'

  2. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

  3. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

  4. ruby-on-rails - 事件管理员和自定义方法 - 2

    这是我在ActiveAdmin中的自定义页面ActiveAdmin.register_page"Settings"doaction_itemdolink_to('Importprojects','settings/importprojects')endcontentdopara"Text"endcontrollerdodefimportprojectssystem"rakedataspider:import_projects_ninja"para"OK"endendend我想做的是,当我单击“导入项目”按钮时,我想在Controller中执行rake任务。但是我无法访问该方法。可能是什

  5. ruby-on-rails - 在不重新查询数据库的情况下重新排序 Rails 中的事件记录? - 2

    例如,假设我有一个名为Products的模型,并且在ProductsController中,我有以下代码用于product_listView以显示已排序的产品。@products=Product.order(params[:order_by])让我们想象一下,在product_listView中,用户可以使用下拉菜单按价格、评级、重量等进行排序。数据库中的产品不会经常更改。我很难理解的是,每次用户选择新的order_by过滤器时,rails是否必须查询,或者rails是否能够以某种方式缓存事件记录以在服务器端重新排序?有没有一种方法可以编写它,以便在用户排序时rails不会重新查询结果

  6. ruby-on-rails - Ruby 长时间运行的进程对队列事件使用react - 2

    我有一个将某些事件写入队列的Rails3应用。现在我想在服务器上创建一个服务,每x秒轮询一次队列,并按计划执行其他任务。除了创建ruby​​脚本并通过cron作业运行它之外,还有其他稳定的替代方案吗? 最佳答案 尽管启动基于Rails的持久任务是一种选择,但您可能希望查看更有序的系统,例如delayed_job或Starling管理您的工作量。我建议不要在cron中运行某些东西,因为启动整个Rails堆栈的开销可能很大。每隔几秒运行一次它是不切实际的,因为Rails上的启动时间通常为5-15秒,具体取决于您的硬件。不过,每天这样做几

  7. 多种方法期间的 Ruby 救援异常 - 2

    我构建了一个简单的银行应用程序,它能够执行通常的操作;充值、提现等我的Controller方法执行这些操作并拯救由帐户或其他实体引发的异常。以下是Controller代码中使用的一些方法:defopen(type,with:)account=createtype,(holders.findwith)addaccountinit_yearly_interest_foraccountboundary.renderAccountSuccessMessage.new(account)rescueItemExistError=>messageboundary.rendermessageendde

  8. ruby-on-rails - 使用 Rails 事件记录获取二级模型 - 2

    我有一个帖子属于城市的关系,城市又属于一个州,例如:classPost现在我想找到所有帖子及其所属的城市和州。我编写了以下查询来获取带有城市的帖子,但不知道如何在同一查找器中获取带有城市的相应州:@post=Post.find:all,:include=>[:city]感谢任何帮助。谢谢。 最佳答案 Post.all(:include=>{:city=>:state}) 关于ruby-on-rails-使用Rails事件记录获取二级模型,我们在StackOverflow上找到一个类似的问

  9. ruby - 在没有数据库的情况下伪造一个事件记录模型 - 2

    我觉得我错过了什么。我正在编写一个ruby​​gem,它允许与事件记录进行交互,作为其主要功能的附加功能。在为其编写测试用例时,我需要能够指定虚拟事件记录模型来测试此功能。如果我可以获得一个事件记录模型的实例,它不需要与数据库的任何连接,可以有关系,所有这些东西,但不需要我在数据库中设置表,那就太棒了。我对测试还很陌生,在Rails测试之外我也很陌生,但似乎我应该能够相当轻松地完成类似的事情,但我什么也没找到。谁能告诉我我错过了什么?我看过工厂、制造商、固定装置,所有这些似乎都想达到目标。人们如何在您只需要AR对象进行测试的地方测试gem? 最佳答案

  10. ruby-on-rails - 在事件记录库中添加某些方法的首选方法是什么? - 2

    我想创建一个模块,为从事件记录库继承的类提供一些通用方法。以下是我们可以实现的两种方式。1)moduleCommentabledefself.extended(base)base.class_evaldoincludeInstanceMethodsextendClassMethodsendendmoduleClassMethodsdeftest_commentable_classmethodputs'testclassmethod'endendmoduleInstanceMethodsdeftest_commentable_instance_methodputs'testinstanc

随机推荐