iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >SpringBoot留给开发者的7个启动扩展点分别是怎样的
  • 321
分享到

SpringBoot留给开发者的7个启动扩展点分别是怎样的

2023-06-15 15:06:17 321人浏览 安东尼
摘要

这篇文章将为大家详细讲解有关SpringBoot留给开发者的7个启动扩展点分别是怎样的,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。我们经常需要在容器启动的时候做一些钩子动作,比如注册消息消

这篇文章将为大家详细讲解有关SpringBoot留给开发者的7个启动扩展点分别是怎样的,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

我们经常需要在容器启动的时候做一些钩子动作,比如注册消息消费者,监听配置等,今天就总结springBoot留给开发者的7个启动扩展点。

容器刷新完成扩展点

1、监听容器刷新完成扩展点ApplicationListener<ContextRefreshedEvent>

基本用法

熟悉Spring的同学一定知道,容器刷新成功意味着所有的Bean初始化已经完成,当容器刷新之后Spring将会调用容器内所有实现了ApplicationListener<ContextRefreshedEvent>的Bean的onApplicationEvent方法,应用程序可以以此达到监听容器初始化完成事件的目的。

@Component  public class StartupApplicationListenerExample implements     ApplicationListener<ContextRefreshedEvent> {      private static final Logger LOG         = Logger.getLogger(StartupApplicationListenerExample.class);      public static int counter;      @Override public void onApplicationEvent(ContextRefreshedEvent event) {          LOG.info("Increment counter");          counter++;      }  }

易错的点

这个扩展点用在WEB容器中的时候需要额外注意,在web 项目中(例如spring mvc),系统会存在两个容器,一个是root application context,另一个就是我们自己的context(作为root application context的子容器)。如果按照上面这种写法,就会造成onApplicationEvent方法被执行两次。解决此问题的方法如下:

@Component  public class StartupApplicationListenerExample implements     ApplicationListener<ContextRefreshedEvent> {      private static final Logger LOG         = Logger.getLogger(StartupApplicationListenerExample.class);      public static int counter;      @Override public void onApplicationEvent(ContextRefreshedEvent event) {          if (event.getApplicationContext().getParent() == null) {              // root application context 没有parent              LOG.info("Increment counter");              counter++;          }      }  }

高阶玩法

当然这个扩展还可以有更高阶的玩法:自定义事件,可以借助Spring以最小成本实现一个观察者模式:

  •  先自定义一个事件: 

public class NotifyEvent extends ApplicationEvent {      private String email;      private String content;      public NotifyEvent(Object source) {          super(source);      }      public NotifyEvent(Object source, String email, String content) {          super(source);          this.email = email;          this.content = content;      }      // 省略getter/setter方法  }
  •  注册一个事件监听器 

@Component  public class NotifyListener implements ApplicationListener<NotifyEvent> {      @Override      public void onApplicationEvent(NotifyEvent event) {          System.out.println("邮件地址:" + event.getEmail());          System.out.println("邮件内容:" + event.getContent());      }  }
  •  发布事件 

@RunWith(SpringRunner.class)  @SpringBootTest  public class ListenerTest {      @Autowired      private WebApplicationContext webApplicationContext;      @Test      public void testListener() {          NotifyEvent event = new NotifyEvent("object", "abc@qq.com", "This is the content");          webApplicationContext.publishEvent(event);      }  }
  •  执行单元测试可以看到邮件的地址和内容都被打印出来了

2、SpringBoot的CommandLineRunner接口

当容器上下文初始化完成之后,SpringBoot也会调用所有实现了CommandLineRunner接口的run方法,下面这段代码可起到和上文同样的作用:

@Component  public class CommandLineAppStartupRunner implements CommandLineRunner {      private static final Logger LOG =        LoggerFactory.getLogger(CommandLineAppStartupRunner.class);      public static int counter;      @Override      public void run(String...args) throws Exception {         LOG.info("Increment counter");          counter++;      }  }

对于这个扩展点的使用有额外两点需要注意:

  • 多个实现了CommandLineRunner的Bean的执行顺序可以根据Bean上的@Order注解调整

  • 其run方法可以接受从控制台输入的参数,跟ApplicationListener<ContextRefreshedEvent>这种扩展相比,更加灵活 

// 从控制台输入参数示例  java -jar CommandLineAppStartupRunner.jar abc abcd

3、SpringBoot的ApplicationRunner接口

这个扩展和SpringBoot的CommandLineRunner接口的扩展类似,只不过接受的参数是一个ApplicationArguments类,对控制台输入的参数提供了更好的封装,以--开头的被视为带选项的参数,否则是普通的参数

@Component  public class AppStartupRunner implements ApplicationRunner {      private static final Logger LOG =        LoggerFactory.getLogger(AppStartupRunner.class);      public static int counter;      @Override      public void run(ApplicationArguments args) throws Exception {          LOG.info("Application started with option names : {}",             args.getOptionNames());          LOG.info("Increment counter");          counter++;      }  }

比如:

java -jar CommandLineAppStartupRunner.jar abc abcd --autho=mark verbose

Bean初始化完成扩展点

前面的内容总结了针对容器初始化的扩展点,在有些场景,比如监听消息的时候,我们希望Bean初始化完成之后立刻注册监听器,而不是等到整个容器刷新完成,Spring针对这种场景同样留足了扩展点:

1、@PostConstruct注解 

@PostConstruct注解一般放在Bean的方法上,被@PostConstruct修饰的方法会在Bean初始化后马上调用:  @Component  public class PostConstructExampleBean {      private static final Logger LOG         = Logger.getLogger(PostConstructExampleBean.class);      @Autowired      private Environment environment;      @PostConstruct      public void init() {          LOG.info(Arrays.asList(environment.getDefaultProfiles()));      }  }

2、 InitializingBean接口

InitializingBean的用法基本上与@PostConstruct一致,只不过相应的Bean需要实现afterPropertiesSet方法

@Component  public class InitializingBeanExampleBean implements InitializingBean {      private static final Logger LOG         = Logger.getLogger(InitializingBeanExampleBean.class);      @Autowired      private Environment environment;      @Override     public void afterPropertiesSet() throws Exception {          LOG.info(Arrays.asList(environment.getDefaultProfiles()));      }  }

3、@Bean注解的初始化方法

通过@Bean注入Bean的时候可以指定初始化方法:

Bean的定义

public class InitMethodExampleBean {      private static final Logger LOG = Logger.getLogger(InitMethodExampleBean.class);      @Autowired      private Environment environment;      public void init() {          LOG.info(Arrays.asList(environment.getDefaultProfiles()));      }  }

Bean注入

@Bean(initMethod="init")  public InitMethodExampleBean initMethodExampleBean() {      return new InitMethodExampleBean();  }

4、通过构造函数注入

Spring也支持通过构造函数注入,我们可以把搞事情的代码写在构造函数中,同样能达到目的

@Component   public class LogicInConstructorExampleBean {      private static final Logger LOG         = Logger.getLogger(LogicInConstructorExampleBean.class);      private final Environment environment;      @Autowired      public LogicInConstructorExampleBean(Environment environment) {          this.environment = environment;          LOG.info(Arrays.asList(environment.getDefaultProfiles()));      }  }

Bean初始化完成扩展点执行顺序?

可以用一个简单的测试:

@Component  @Scope(value = "prototype")  public class AllStrategiesExampleBean implements InitializingBean {      private static final Logger LOG         = Logger.getLogger(AllStrategiesExampleBean.class);      public AllStrategiesExampleBean() {          LOG.info("Constructor");      }      @Override      public void afterPropertiesSet() throws Exception {          LOG.info("InitializingBean");      }      @PostConstruct      public void postConstruct() {         LOG.info("PostConstruct");      }      public void init() {          LOG.info("init-method");      }  }

实例化这个Bean后输出:

[main] INFO o.b.startup.AllStrategiesExampleBean - Constructor  [main] INFO o.b.startup.AllStrategiesExampleBean - PostConstruct  [main] INFO o.b.startup.AllStrategiesExampleBean - InitializingBean  [main] INFO o.b.startup.AllStrategiesExampleBean - init-method

关于SpringBoot留给开发者的7个启动扩展点分别是怎样的就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

--结束END--

本文标题: SpringBoot留给开发者的7个启动扩展点分别是怎样的

本文链接: https://www.lsjlt.com/news/280729.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • SpringBoot留给开发者的7个启动扩展点分别是怎样的
    这篇文章将为大家详细讲解有关SpringBoot留给开发者的7个启动扩展点分别是怎样的,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。我们经常需要在容器启动的时候做一些钩子动作,比如注册消息消...
    99+
    2023-06-15
  • Python开发者应该知道的7个开发库分别是什么
    Python开发者应该知道的7个开发库分别是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。请注意我特别排除了像SQLAlchemy和Flask这样的库,因为其实在太优秀了,...
    99+
    2023-06-17
  • 10个加速CSS开发的框架分别是怎样的
    10个加速CSS开发的框架分别是怎样的,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。CSS可以做很多事情,但开发者更习惯的是变量、常量和一般的...
    99+
    2024-04-02
  • HTML开发中.html和.htm和.shtml 以及 .shtm四种扩展名的文件区别是怎样的
    本篇文章为大家展示了HTML开发中.html和.htm和.shtml 以及 .shtm四种扩展名的文件区别是怎样的,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。很多朋友刚开始接触网页制作,发现这么多...
    99+
    2023-06-08
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作