springboot原理实战(11) -- springboot扩展分析CommandLineRunner

简介: springboot原理实战(11) -- springboot扩展分析CommandLineRunner

目录


本文章主要了解在spring容器执行refreshed之前的一个回调接口:ApplicationContextInitializer,

在容器启动成功后的最后一步回调(类似开机自启动)的接口:CommandLineRunner和ApplicationRunner。

脑图如下:

1dc618a0ed9580ce8bfa6facb208c08f.png


一、ApplicationContextInitializer


该接口是接口是在spring容器执行refreshed之前的一个回调。


①使用步骤:


1: 写一个类: 实现AApplicationContextInitializer接口

2: 注册ApplicationContextInitializer


②注册方法3种:


1.app.addInitializers

2:通过配置项context.initializer.classes指定

3.可以通过spring.factories机制(注册listener监听器也可以使用这种方式)


演示 1.app.addInitializers方式


写个实现类


public class MyAppliationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("bean count: " + applicationContext.getBeanDefinitionCount());
    }
}


在入口中注册和调用:


@SpringBootApplication
public class Demo8Application {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Demo8Application.class);
        app.addInitializers(new MyAppliationContextInitializer());
        ConfigurableApplicationContext context = app.run(args);
        context.close();
    }
}


测试

:5d4c6812c8535adbb050f4ddf2e1bce8.png

测试已经注入!


演示 2:通过配置项context.initializer.classes指定


public class MyAppliationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("bean count: " + applicationContext.getBeanDefinitionCount());
    }
}


public class MyAppliationContextInitializer2 implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println(applicationContext.getDisplayName());
   }
}


application.properties,写了2个实现类:


context.initializer.classes=com.springboot.demo8.MyAppliationContextInitializer,com.springboot.demo8.MyAppliationContextInitializer2

46a9d80a6e05e4e3b19d57a0ee70bcdf.png


@SpringBootApplication
public class Demo8Application {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Demo8Application.class);
        ConfigurableApplicationContext context = app.run(args);
        context.close();
    }


运行结果ok:

66ba272a0bfc97be54a5fa679e3d5482.png


3.spring.factories机制(注册listener监听器也可以使用这种方式)


新建一个项目intializer:

1dc618a0ed9580ce8bfa6facb208c08f.png


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.springboot</groupId>
    <artifactId>intializer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>intializer</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
</project>


public class EchoAppliationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("=========EchoAppliationContextInitializer==========");
    }
}
intializer\src\main\resources\META-INF\spring.factories:
org.springframework.context.ApplicationContextInitializer=com.springboot.intializer.EchoAppliationContextInitializer


将该项目引入原来的项目:


<dependency>
   <groupId>com.springboot</groupId>
     <artifactId>intializer</artifactId>
     <version>0.0.1-SNAPSHOT</version>
 </dependency>


测试:


@SpringBootApplication
public class Demo8Application {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Demo8Application.class);
        ConfigurableApplicationContext context = app.run(args);
        context.close();
    }
}


运行结果:

5d4c6812c8535adbb050f4ddf2e1bce8.png

结果显示已经注入!!


二、CommandLineRunner


该接口是在容器启动成功后的最后一步回调(类似开机自启动),可以在应用启动时打印一些东西之类的。


①使用步骤:


1.写一个类,实现CommandLineRunner 接口


2 把该类纳入到spring的容器管理中


注意:可以通过@Order注解或者Ordered接口来控制执行顺序。order值小的优先

演示一下

@Order(1)
@Component
public class ServerSuccessReport implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("=====应用已经成功的启动============" + Arrays.asList(args));
    }
}


@Order(2)
@Component
public class ServerStartedReport implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("=====应用启动后的时间是:============"+ LocalDateTime.now().toString());
    }
}


以上2个类都实现了CommandLineRunner 接口,并用@Compoent,并通过order控制优先级,值小的优先执行,注入spring:


测试下:


@SpringBootApplication
public class Demo8Application {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Demo8Application.class);
        ConfigurableApplicationContext context = app.run(args);
        context.close();
    }
 }


运行结果:

46a9d80a6e05e4e3b19d57a0ee70bcdf.png


三、ApplicationRunner


CommandLineRunner,ApplicationRunner 区别


区别在于方法的参数不一样


CommandLineRunner的参数是最原始的参数,没有做任务处理


ApplicationRunner的参数是ApplicationArguments,是对原始参数做了进一步的封装


举例说明:


看下CommandLineRunner的获取参数代码:


@Component
public class ServerSuccessReport implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("=====应用已经成功的启动============" + Arrays.asList(args));
    }
}


看戏ApplicationRunner的获取参数代码:


import java.util.Arrays;
@Component
public class StartedApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("应用已经启动,参数为:" + Arrays.asList(args.getSourceArgs()));
    }
}


运行结果:

66ba272a0bfc97be54a5fa679e3d5482.png

都获取了程序的参数,这里我们看不出来区别,继续改造:


先设置启动参数:

1dc618a0ed9580ce8bfa6facb208c08f.png

ApplicationRunner 获取的是一个ApplicationArguments对象,我们来通过参数对象打印看下:

 

public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Demo8Application.class);
        ConfigurableApplicationContext context = app.run(args);
        ApplicationArguments arg = context.getBean(ApplicationArguments.class);
        System.out.println(arg.getSourceArgs().length);
        System.out.println(arg.getOptionNames());
        System.out.println(arg.getOptionValues("myname"));
        context.close();
    }


运行结果:

5d4c6812c8535adbb050f4ddf2e1bce8.png

可以看到通过ApplicationArguments可以使用其提供的getOptionNames,getOptionValues方法很方便的获取参数值,而CommandLineRunner 只能获取到--myname=admin这样的字符串,我们获取key或者value需要使用split切割很麻烦,而且ApplicationArguments还有好多实用的方法:

46a9d80a6e05e4e3b19d57a0ee70bcdf.png

这就是CommandLineRunner,ApplicationRunner 区别 : 方法的参数类型不一样.


本文讲了主要是springboot容器2个常用接口:在spring容器执行refreshed之前的一个回调接口:ApplicationContextInitializer,

在容器启动成功后的最后一步回调(类似开机自启动)的接口:CommandLineRunner和ApplicationRunner,和这2个接口的区别.


相关文章
|
12天前
|
Java 应用服务中间件 API
Vertx高并发理论原理以及对比SpringBoot
Vertx 是一个基于 Netty 的响应式工具包,不同于传统框架如 Spring,它的侵入性较小,甚至可在 Spring Boot 中使用。响应式编程(Reactive Programming)基于事件模式,通过事件流触发任务执行,其核心在于事件流 Stream。相比多线程异步,响应式编程能以更少线程完成更多任务,减少内存消耗与上下文切换开销,提高 CPU 利用率。Vertx 适用于高并发系统,如 IM 系统、高性能中间件及需要较少服务器支持大规模 WEB 应用的场景。随着 JDK 21 引入协程,未来 Tomcat 也将优化支持更高并发,降低响应式框架的必要性。
Vertx高并发理论原理以及对比SpringBoot
|
7天前
|
缓存 NoSQL Java
Springboot实战——黑马点评之秒杀优化
【9月更文挑战第27天】在黑马点评项目中,秒杀功能的优化对提升系统性能和用户体验至关重要。本文提出了多项Spring Boot项目的秒杀优化策略,包括数据库优化(如索引和分库分表)、缓存优化(如Redis缓存和缓存预热)、并发控制(如乐观锁、悲观锁和分布式锁)以及异步处理(如消息队列和异步任务执行)。这些策略能有效提高秒杀功能的性能和稳定性,为用户提供更佳体验。
|
22天前
|
Java 开发者 数据格式
【Java笔记+踩坑】SpringBoot基础4——原理篇
bean的8种加载方式,自动配置原理、自定义starter开发、SpringBoot程序启动流程解析
【Java笔记+踩坑】SpringBoot基础4——原理篇
|
2月前
|
NoSQL Java Redis
Redis6入门到实战------ 八、Redis与Spring Boot整合
这篇文章详细介绍了如何在Spring Boot项目中整合Redis,包括在`pom.xml`中添加依赖、配置`application.properties`文件、创建配置类以及编写测试类来验证Redis的连接和基本操作。
Redis6入门到实战------ 八、Redis与Spring Boot整合
|
2月前
|
Java API UED
【实战秘籍】Spring Boot开发者的福音:掌握网络防抖动,告别无效请求,提升用户体验!
【8月更文挑战第29天】网络防抖动技术能有效处理频繁触发的事件或请求,避免资源浪费,提升系统响应速度与用户体验。本文介绍如何在Spring Boot中实现防抖动,并提供代码示例。通过使用ScheduledExecutorService,可轻松实现延迟执行功能,确保仅在用户停止输入后才触发操作,大幅减少服务器负载。此外,还可利用`@Async`注解简化异步处理逻辑。防抖动是优化应用性能的关键策略,有助于打造高效稳定的软件系统。
42 2
|
2月前
|
Java 开发者 Spring
"揭秘SpringBoot魔法SPI机制:一键解锁服务扩展新姿势,让你的应用灵活飞天!"
【8月更文挑战第11天】SPI(Service Provider Interface)是Java的服务提供发现机制,用于运行时动态查找和加载服务实现。SpringBoot在其基础上进行了封装和优化,通过`spring.factories`文件提供更集中的配置方式,便于框架扩展和组件替换。本文通过定义接口`HelloService`及其实现类`HelloServiceImpl`,并在`spring.factories`中配置,结合`SpringFactoriesLoader`加载服务,展示了SpringBoot SPI机制的工作流程和优势。
42 5
|
3月前
|
Java Spring 容器
Spring Boot 启动源码解析结合Spring Bean生命周期分析
Spring Boot 启动源码解析结合Spring Bean生命周期分析
87 11
|
2月前
|
JSON Java API
解码Spring Boot与JSON的完美融合:提升你的Web开发效率,实战技巧大公开!
【8月更文挑战第29天】Spring Boot作为Java开发的轻量级框架,通过`jackson`库提供了强大的JSON处理功能,简化了Web服务和数据交互的实现。本文通过代码示例介绍如何在Spring Boot中进行JSON序列化和反序列化操作,并展示了处理复杂JSON数据及创建RESTful API的方法,帮助开发者提高效率和应用性能。
69 0
|
2月前
|
SQL Java 数据库连接
Spring Boot联手MyBatis,打造开发利器:从入门到精通,实战教程带你飞越编程高峰!
【8月更文挑战第29天】Spring Boot与MyBatis分别是Java快速开发和持久层框架的优秀代表。本文通过整合Spring Boot与MyBatis,展示了如何在项目中添加相关依赖、配置数据源及MyBatis,并通过实战示例介绍了实体类、Mapper接口及Controller的创建过程。通过本文,你将学会如何利用这两款工具提高开发效率,实现数据的增删查改等复杂操作,为实际项目开发提供有力支持。
61 0
|
2月前
|
Java 开发者 Spring
Spring Boot实战宝典:揭秘定时任务的幕后英雄,让业务处理如流水般顺畅,轻松驾驭时间管理艺术!
【8月更文挑战第29天】在现代应用开发中,定时任务如数据备份、报告生成等至关重要。Spring Boot作为流行的Java框架,凭借其强大的集成能力和简洁的配置方式,为开发者提供了高效的定时任务解决方案。本文详细介绍了如何在Spring Boot项目中启用定时任务支持、编写定时任务方法,并通过实战案例展示了其在业务场景中的应用,同时提供了注意事项以确保任务的正确执行。
37 0
下一篇
无影云桌面