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


相关文章
|
2月前
|
安全 NoSQL Java
SpringBoot接口安全:限流、重放攻击、签名机制分析
本文介绍如何在Spring Boot中实现API安全机制,涵盖签名验证、防重放攻击和限流三大核心。通过自定义注解与拦截器,结合Redis,构建轻量级、可扩展的安全防护方案,适用于B2B接口与系统集成。
454 3
|
2月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
|
3月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
618 3
|
4月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
841 0
|
1月前
|
监控 Cloud Native Java
Spring Boot 3.x 微服务架构实战指南
🌟蒋星熠Jaxonic,技术宇宙中的星际旅人。深耕Spring Boot 3.x与微服务架构,探索云原生、性能优化与高可用系统设计。以代码为笔,在二进制星河中谱写极客诗篇。关注我,共赴技术星辰大海!(238字)
Spring Boot 3.x 微服务架构实战指南
|
1月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
237 3
|
1月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
315 2
|
2月前
|
消息中间件 Ubuntu Java
SpringBoot整合MQTT实战:基于EMQX实现双向设备通信
本教程指导在Ubuntu上部署EMQX 5.9.0并集成Spring Boot实现MQTT双向通信,涵盖服务器搭建、客户端配置及生产实践,助您快速构建企业级物联网消息系统。
940 1
|
4月前
|
前端开发 Java 数据库连接
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
|
3月前
|
JavaScript Java 应用服务中间件
基于springboot的学生成绩分析和弱项辅助系统
本系统旨在解决学生成绩分析与弱项辅助信息管理效率低下的问题,通过软件技术实现数据处理的高效化、流程化与规范化,提升管理质量与便捷性。