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


相关文章
|
27天前
|
XML Java 数据库连接
spring boot 参数的过滤注解与实战
在Spring Boot应用中,对于入参的过滤,通常会涉及到对Web层的数据验证和处理。Spring Boot借助Spring框架提供了强大的验证框架支持,主要基于JSR-303/JSR-380(Bean Validation API)规范,以及Spring自身的@Valid或@Validated注解来实现请求参数的验证。以下是一些常见的使用案例来展示如何对参数进行过滤和验证。
24 1
|
1月前
|
安全 Java 数据安全/隐私保护
SpringBoot实现二维码扫码登录的原理与详细步骤
SpringBoot实现二维码扫码登录的原理与详细步骤
79 1
|
1月前
|
XML Java 开发者
Spring Boot中的bean注入方式和原理
Spring Boot中的bean注入方式和原理
39 0
|
1月前
|
Java Spring 容器
【二十二】springboot整合拦截器实战并对比过滤器
【二十二】springboot整合拦截器实战并对比过滤器
30 0
|
1月前
|
前端开发 搜索推荐 Java
【Spring底层原理高级进阶】基于Spring Boot和Spring WebFlux的实时推荐系统的核心:响应式编程与 WebFlux 的颠覆性变革
【Spring底层原理高级进阶】基于Spring Boot和Spring WebFlux的实时推荐系统的核心:响应式编程与 WebFlux 的颠覆性变革
|
9天前
|
前端开发 Java 应用服务中间件
Springboot对MVC、tomcat扩展配置
Springboot对MVC、tomcat扩展配置
|
9天前
|
Java 容器 Spring
Springboot自动配置原理
Springboot自动配置原理
|
25天前
|
Java API 开发者
springboot 多线程的使用原理与实战
在Spring Boot中实现多线程,主要依赖于Spring框架的@Async注解以及底层Java的并发框架。这里将深入剖析Spring Boot多线程的原理,包括@Async注解的工作方式、任务执行器的角色以及如何通过配置来调整线程行为。
33 5
|
26天前
|
存储 缓存 安全
Spring Boot从入门到实战
本课程从SpringBoot的最基础的安装、配置开始到SpringBoot的日志管理、Web业务开发、数据存储、数据缓存,安全控制及相关企业级应用,全程案例贯穿,案例每一步的都会讲解实现思路,全程手敲代码实现。让你不仅能够掌SpringBoot的应用,还能了解背后的原理,学习完本课程后,能够让你动手独立完成一个中小型的SpringBoot Web应用开发。
18 1
Spring Boot从入门到实战
|
30天前
|
XML 设计模式 Java
springboot创建并配置环境3 - 配置扩展属性(下)
springboot创建并配置环境3 - 配置扩展属性(下)
springboot创建并配置环境3 - 配置扩展属性(下)