将多个CommandLineRunner/ApplicationRunner实现类放入Spring Boot可执行的jar中,并通过启动时的属性来切换执行的类

简要概述

我发现在需要创建一个简单的批处理程序时,使用Spring Boot实现CommandLineRunner/ApplicationRunner接口的类是简单且方便的。所以我尝试创建了几个批处理程序,

    • バッチをいくつも作りたい場合、バッチ1つに付き実行可能 jar ファイルを1つ作らないといけないのだろうか?

 

    一部のクラスや実行可能 jar に含まれる lib ディレクトリの下の外部ライブラリの jar ファイルを外に出して共通化しようと思ったが -jar オプションと -classpath オプションが共存できないらしく、jar ファイルからクラスや外部ライブラリの jar ファイルを外に出して共通化する方法が分からない。

在这方面我一直感到困扰。毕竟,我不想为每个批处理创建一个可执行的jar文件,所以我考虑了将实现了CommandLineRunner/ApplicationRunner接口的类都放入一个可执行的jar文件,并在启动时使用属性进行切换的方法。

如何切换执行的类?

    • Spring Boot では CommandLineRunner/ApplicationRunner インターフェースを実装したクラスの Bean が生成されていればその run メソッドが実行されるので、実行時に指定するプロパティの値で Bean を生成するのか否かを制御します。

 

    Bean 生成の制御は Spring Boot で提供されている @ConditionalOnProperty アノテーションを利用します。このアノテーションを @Bean アノテーションと一緒にメソッドに付けておくと、指定されたプロパティと値の組み合わせがある場合のみ Bean が生成されるようになります。

在尝试时的开发环境中,使用的是Spring Boot的版本。

我正在以下环境中进行测试。

    • JDK 8u102

 

    • IntelliJ IDEA Ultimate 2016.2

 

    Spring Boot 1.4

样品项目的规范

创建一个名为 multi-applicationrunner-sample-0.0.1-SNAPSHOT.jar 的可执行 jar 文件,并指定实现了 CommandLineRunner/ApplicationRunner 接口的类来运行它,可以使用 -Dbatch.execute=… 参数来执行它。

在实际中会以以下方式工作(还会输出Spring Boot的标志和INFO日志)。

> java -Dbatch.execute=Sample01 -jar multi-applicationrunner-sample-0.0.1-SNAPSHOT.jar
Sample01バッチが起動しました

> java -Dbatch.execute=Sample02 -jar multi-applicationrunner-sample-0.0.1-SNAPSHOT.jar
Sample02バッチです

样本项目的包文件结构

样例项目是在Spring Initializr中创建的Gradle项目。除了以下文件外,还有build.gradle文件。

src
└ main
  ├ java
  │ └ ksbysample
  │   └ batch
  │     ├ MultiApplicationRunnerSampleApplication
  │     ├ PrintService.java
  │     ├ Sample01BatchRunner.java
  │     └ Sample02BatchRunner.java
  └ resources

各个文件的内容

构建.gradle

这还是使用 Spring Initializr 生成的。

buildscript {
    ext {
        springBootVersion = '1.4.0.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'spring-boot'

jar {
    baseName = 'multi-applicationrunner-sample'
    version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
}


dependencies {
    compile('org.springframework.boot:spring-boot-starter')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}


eclipse {
    classpath {
         containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
         containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8'
    }
}

多应用运行器示例应用程序.java

这个也是保持了原始的 Spring Initializr 生成的状态。

package ksbysample.batch;

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

@SpringBootApplication
public class MultiApplicationRunnerSampleApplication {

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

PrintService.java 打印服务.java

为了验证即使在Sample01BatchRunner和Sample02BatchRunner类中没有添加@Component注解,PrintService类也可以使用@Autowired注解来进行描述,创建了这个类。

package ksbysample.batch;

import org.springframework.stereotype.Service;

@Service
public class PrintService {

    public void println(String msg) {
        System.out.println(msg);
    }

}

样例01BatchRunner.java

package ksbysample.batch;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

public class Sample01BatchRunner implements ApplicationRunner {

    @Autowired
    private PrintService printService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        printService.println("Sample01バッチが起動しました");
    }

    @Configuration
    public static class Sample01BatchConfig {
        @Bean
        @ConditionalOnProperty(value = { "batch.execute" }, havingValue = "Sample01")
        public Sample01BatchRunner sample01BatchRunner() {
            return new Sample01BatchRunner();
        }
    }

}

重要之处在于,

    • Sample01BatchRunner クラスは ApplicationRunner インターフェース(あるいは CommandLineRunner インターフェース)を実装し、run メソッドを override します。

 

    • Sample01BatchRunner クラス自体には @Component アノテーションを付加しません。

 

    • Sample01BatchRunner クラス内に @Autowired アノテーションを付加したフィールドは記述可能です。Bean として生成される時にインスタンスが DI されます。

@Configuration アノテーションを付加した Sample01BatchConfig クラスを記述します。@Configuration アノテーションを付加しているのはこのクラスの内部で @Bean アノテーションを付加したメソッドを定義するためです。
Sample01BatchConfig クラス内で Sample01BatchRunner Bean を生成するためのメソッドを定義します。このメソッドには @ConditionalOnProperty アノテーションを付加し、起動時のプロパティで Bean が生成されるか否かを制御されるようにします。

Sample02BatchRunner.java的中文本地化版本

package ksbysample.batch;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

public class Sample02BatchRunner implements ApplicationRunner {

    @Autowired
    private PrintService printService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        printService.println("Sample02バッチです");
    }

    @Configuration
    public static class Sample02BatchConfig {
        @Bean
        @ConditionalOnProperty(value = { "batch.execute" }, havingValue = "Sample02")
        public Sample02BatchRunner sample01BatchRunner() {
            return new Sample02BatchRunner();
        }
    }

}

广告
将在 10 秒后关闭
bannerAds