ZetCode

Spring Boot CommandLineRunner

最后修改于 2023 年 8 月 2 日

在本文中,我们将展示如何使用 CommandLineRunner 接口运行 beans。

Spring 是一个流行的 Java 应用程序框架,而 Spring Boot 是 Spring 的一个演进,它有助于轻松创建独立的、生产级的基于 Spring 的应用程序。

CommandLineRunner

CommandLineRunner 是一个接口,用于指示当 bean 包含在 SpringApplication 中时应该运行。一个 Spring Boot 应用程序可以有多个实现 CommandLineRunner 的 beans。这些可以使用 @Order 进行排序。

Spring Boot CommandLineRunner 示例

以下应用程序演示了 CommandLineRunner 的用法。它在 H2 内存数据库中创建城市,然后列出它们。

build.gradle
...
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           │   MyRunner.java
│   │           ├───model
│   │           │       City.java
│   │           └───repository
│   │                   CityRepository.java
│   └───resources
│           application.properties
└───test
    ├── java
    └── resources

这是项目结构。

build.gradle
plugins {
    id 'org.springframework.boot' version '3.1.1'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'com.zetcode'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'com.h2database:h2'
}

这是 Gradle 构建文件。我们使用 H2 数据库和 Spring Data JPA。

resources/application.properties
spring.main.banner-mode=off

application.properties 是 Spring Boot 中的主要配置文件。使用 spring.main.banner-mode=off 我们关闭 Spring 横幅。

com/zetcode/model/City.java
package com.zetcode.model;

import java.util.Objects;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "cities")
public class City {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;
    private int population;

    public City() {
    }

    public City(String name, int population) {
        this.name = name;
        this.population = population;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 79 * hash + Objects.hashCode(this.id);
        hash = 79 * hash + Objects.hashCode(this.name);
        hash = 79 * hash + this.population;
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final City other = (City) obj;
        if (this.population != other.population) {
            return false;
        }
        if (!Objects.equals(this.name, other.name)) {
            return false;
        }
        return Objects.equals(this.id, other.id);
    }

    @Override
    public String toString() {

        var builder = new StringBuilder();
        builder.append("City{id=").append(id).append(", name=")
                .append(name).append(", population=")
                .append(population).append("}");

        return builder.toString();
    }
}

这是 City 模型,它具有以下属性:id, namepopulation

com/zetcode/repository/CityRepository.java
package com.zetcode.repository;

import com.zetcode.model.City;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CityRepository extends CrudRepository<City, Long> {
}

CityRepository 对 City 存储库具有一些通用的 CRUD 操作。

com/zetcode/MyRunner.java
package com.zetcode;

import com.zetcode.model.City;
import com.zetcode.repository.CityRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class MyRunner implements CommandLineRunner {

    private static final Logger logger = LoggerFactory.getLogger(MyRunner.class);

    private final CityRepository repository;

    public MyRunner(CityRepository repository) {
        this.repository = repository;
    }

    @Override
    public void run(String... args) throws Exception {
        repository.deleteAll();

        repository.save(new City("Bratislava", 432000));
        repository.save(new City("Budapest", 1759000));
        repository.save(new City("Prague", 1280000));

        repository.findAll().forEach((city) -> {
            logger.info("{}", city);
        });
    }
}

通过实现 CommandLineRunnerMyRunner 类的 run 方法将在应用程序启动后执行。

@Component
public class MyRunner implements CommandLineRunner {

MyRunner 也用 @Component 修饰,因此它也会被自动检测并注册。

private final CityRepository repository;

public MyRunner(CityRepository repository) {
    this.repository = repository;
}

我们将 CityRepository bean 注入到 repository 字段中。

@Override
public void run(String... args) throws Exception {

    repository.save(new City("Bratislava", 432000));
    repository.save(new City("Budapest", 1759000));
    repository.save(new City("Prague", 1280000));

    repository.findAll().forEach((city) -> {
        logger.info("{}", city);
    });

run 方法中,我们创建三个城市,然后找到所有城市并将它们打印到控制台。

com/zetcode/Application.java
package com.zetcode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application  {
    
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Application 是设置 Spring Boot 应用程序的入口点。

$ ./gradlew bootRun

我们运行应用程序。

在本文中,我们已经展示了如何使用 CommandLineRunner 接口来创建一个在应用程序启动时运行的 bean。

作者

我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。迄今为止,我撰写了 1,400 多篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出 所有 Spring Boot 教程