类路径上有多个ApplicationRunners,如何使SpringApplication.run()只运行一个

时间:2016-02-18 10:19:54

标签: spring spring-boot

上下文:我有一个带有一些实用程序的项目来执行数据修复等操作。每个实用程序都是Java应用程序,即具有main()方法的类。我想将它们定义为Spring Boot应用程序,因此我可以使用ApplicationRunnerApplicationArguments工具。 Spring配置是通过共享配置类中的注释定义的。我在下面给出了这个设置的最小例子。

期望:如果我致电SpringApplication.run(SomeClass.class, args),其中SomeClassApplicationRunner,则会在该类上运行run(),而不会在应用中的任何其他类上运行上下文。

实际发生的事情:它调用上下文中的所有ApplicationRunners

为什么呢?我理解SpringApplication.run(Class, String[])表示“运行此类”,而它似乎意味着“从此类加载应用程序上下文并运行您可以在其中找到的任何内容”。我应该如何解决它只运行一个类?我不介意我的其他应用程序类是否不在应用程序上下文中,因为我需要的所有配置都在共享配置类中。但我不想根据我需要运行的类来编辑代码(例如添加或删除注释)。

最小例子:

Spring配置类(共享):

package com.stackoverflow.example;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ExampleSpringConfig {
  /** Some bean - just here to check that beans from this config are injected */
  @Bean public FooService fooService () {
    return new FooService();
  }
}

两个应用程序类

package com.stackoverflow.example;

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

import javax.annotation.Resource;

@SpringBootApplication
public class SomethingJob implements ApplicationRunner {
  @Resource private FooService fooService;

  public void run(ApplicationArguments args) throws Exception {
    System.out.println("Doing something"); // do things with FooService here
  }

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

和另一个相同的,除了它打印“做其他事情”。

输出:

[Spring Boot startup logs...]
Doing something else
Doing something
[Spring Boot shutdown logs...]

2 个答案:

答案 0 :(得分:2)

首先,只应使用@SpringBootApplication注释一个类。正如您在答案中注意到的那样,这定义了外部" main"入口点。为了清晰度和概念分离,我建议这是与ApplicationRunner类不同的类。

为了只运行一些但不是所有的跑步者,我通过解析参数完成了这一操作,并迅速退出了不应该被调用的跑步者。 e.g。

package com.stackoverflow.example;

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

import javax.annotation.Resource;

@Component
public class SomethingJob implements ApplicationRunner {
  @Resource private FooService fooService;

  public void run(ApplicationArguments args) throws Exception {
    if (!args.containsOption("something")) return

    System.out.println("Doing something"); // do things with FooService here
  }

}

通过这种方式,您可以执行java -jar myjar.jar --somethingjava -jar myjar.jar --something-else,具体取决于您要运行哪一个。

答案 1 :(得分:0)

我在尝试使用我的最小示例时找到了解决方法。

<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 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.demo.mongo.example</groupId> <artifactId>demomongo</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>demomongo Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-mongodb</artifactId> <version>1.2.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.7.1</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.9.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.7.1-1</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>3.0-alpha-1</version> </dependency> </dependencies> <build> <finalName>demomongo</finalName> </build> </project>只是div/(declare-const a01 Int) (declare-const a02 Int) (assert(or (= (div a01 a02) 2) (= (div a02 a01) 2))) (assert( > a01 0)) (assert( > a02 0)) (check-sat) 的别名。通过单独应用它们,我发现导致此行为的List<String> results= em.createQuery( "SELECT myclass FROM myClass ") .setMaxResults(10) .getResultList(); 注释。如果我只申请其他2,我就不会解决问题。

我想这是因为image: java:openjdk-8-jdk before_script: - export GRADLE_USER_HOME=`pwd`/.gradle cache: paths: - .gradle/wrapper - .gradle/caches build: stage: build script: - ./gradlew assemble test: stage: test script: - ./gradlew check 意味着&#34;我是一个配置类,我定义的任何bean应该在组件扫描期间被拉入上下文&#34;虽然这个类没有定义一个 preg_match('/\d{4}/', $value, $match); ,但一个,它具有相同的效果。因此,如果类路径中有2个这样的bean,它们都会进入应用程序上下文。

如果没有@SpringBootApplication,您要运行的bean仍然会被注册,因为它被@ComponentScan调用引用,但类路径上的其他@EnableAutoConfiguration不会被注册;吨

通过确保我的应用上下文中只有一个@Configuration,这可以解决我的问题。但它并没有回答更广泛的问题,&#34;如果我有几个@Configuration,我怎么告诉Spring Boot运行哪一个?&#34;所以我仍然感谢任何更完整的答案或建议采用不同的方法。