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个接口的区别.


相关文章
|
29天前
|
XML Java 开发者
Spring Boot开箱即用可插拔实现过程演练与原理剖析
【11月更文挑战第20天】Spring Boot是一个基于Spring框架的项目,其设计目的是简化Spring应用的初始搭建以及开发过程。Spring Boot通过提供约定优于配置的理念,减少了大量的XML配置和手动设置,使得开发者能够更专注于业务逻辑的实现。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,为开发者提供一个全面的理解。
29 0
|
19小时前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
26 14
|
1月前
|
Java Spring
SpringBoot自动装配的原理
在Spring Boot项目中,启动引导类通常使用`@SpringBootApplication`注解。该注解集成了`@SpringBootConfiguration`、`@ComponentScan`和`@EnableAutoConfiguration`三个注解,分别用于标记配置类、开启组件扫描和启用自动配置。
56 17
|
22天前
|
Java 容器
springboot自动配置原理
启动类@SpringbootApplication注解下,有三个关键注解 (1)@springbootConfiguration:表示启动类是一个自动配置类 (2)@CompontScan:扫描启动类所在包外的组件到容器中 (3)@EnableConfigutarion:最关键的一个注解,他拥有两个子注解,其中@AutoConfigurationpackageu会将启动类所在包下的所有组件到容器中,@Import会导入一个自动配置文件选择器,他会去加载META_INF目录下的spring.factories文件,这个文件中存放很大自动配置类的全类名,这些类会根据元注解的装配条件生效,生效
|
1月前
|
Java 开发者 Spring
精通SpringBoot:16个扩展接口精讲
【10月更文挑战第16天】 SpringBoot以其简化的配置和强大的扩展性,成为了Java开发者的首选框架之一。SpringBoot提供了一系列的扩展接口,使得开发者能够灵活地定制和扩展应用的行为。掌握这些扩展接口,能够帮助我们写出更加优雅和高效的代码。本文将详细介绍16个SpringBoot的扩展接口,并探讨它们在实际开发中的应用。
48 1
|
2月前
|
自然语言处理 Java API
Spring Boot 接入大模型实战:通义千问赋能智能应用快速构建
【10月更文挑战第23天】在人工智能(AI)技术飞速发展的今天,大模型如通义千问(阿里云推出的生成式对话引擎)等已成为推动智能应用创新的重要力量。然而,对于许多开发者而言,如何高效、便捷地接入这些大模型并构建出功能丰富的智能应用仍是一个挑战。
206 6
|
2月前
|
Java Spring 容器
springboot @RequiredArgsConstructor @Lazy解决循环依赖的原理
【10月更文挑战第15天】在Spring Boot应用中,循环依赖是一个常见问题,当两个或多个Bean相互依赖时,会导致Spring容器陷入死循环。本文通过比较@RequiredArgsConstructor和@Lazy注解,探讨它们解决循环依赖的原理和优缺点。@RequiredArgsConstructor通过构造函数注入依赖,使代码更简洁;@Lazy则通过延迟Bean的初始化,打破创建顺序依赖。两者各有优势,需根据具体场景选择合适的方法。
96 4
|
3月前
|
Java 应用服务中间件 API
Vertx高并发理论原理以及对比SpringBoot
Vertx 是一个基于 Netty 的响应式工具包,不同于传统框架如 Spring,它的侵入性较小,甚至可在 Spring Boot 中使用。响应式编程(Reactive Programming)基于事件模式,通过事件流触发任务执行,其核心在于事件流 Stream。相比多线程异步,响应式编程能以更少线程完成更多任务,减少内存消耗与上下文切换开销,提高 CPU 利用率。Vertx 适用于高并发系统,如 IM 系统、高性能中间件及需要较少服务器支持大规模 WEB 应用的场景。随着 JDK 21 引入协程,未来 Tomcat 也将优化支持更高并发,降低响应式框架的必要性。
Vertx高并发理论原理以及对比SpringBoot
|
2月前
|
Java BI API
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
这篇文章介绍了如何在Spring Boot项目中整合iTextPDF库来导出PDF文件,包括写入大文本和HTML代码,并分析了几种常用的Java PDF导出工具。
558 0
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
|
2月前
|
XML Java 应用服务中间件
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
212 2