首页 > 解决方案 > Spring Boot 在作为 Servlet 但不能作为命令行运行时可以连接到 Cassandra

问题描述

背景:我正在尝试为我们的 Cassandra 数据库建立一个基于代码的数据迁移系统。我没有大量的 Java 经验,但如果这是一个 .NET 项目,我会在同一个解决方案下将迁移设置为不同的项目。但是,根据其他更有经验的团队成员的指导,建议我将迁移包含在与应用程序的其余部分相同的包中(我可以接受)。还建议最简单的方法是通过 Web API 端点运行迁移(我对此持怀疑态度)。为了避免打开潜在的安全漏洞,我想我会尝试制作一个命令行实用程序来执行迁移。


我有一个 Spring Boot Web 应用程序,其入口点类如下所示:

@Configuration
@SpringBootApplication
@EnableAutoConfiguration
@EnableCaching
@EnableScheduling
public class MyApplication extends SpringBootServletInitializer {

  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(MyApplication.class);
  }

  public static void main(String[] args) {
    new MyApplication().configure(new SpringApplicationBuilder(MyApplication.class)).run(args);
  }
}

但是,我正在尝试添加功能以通过命令行(例如java -jar MyApplication.jar migrate)运行与此应用程序一起打包的几个迁移脚本,因此我添加了以下类:

@Configuration
@SpringBootApplication
@EnableAutoConfiguration
public class MigrationRunner implements CommandLineRunner {

  @Autowired
  Session session;

  @Override
  public void run(String[] args)
  {
    MigrationResources mr = new MigrationResources();
    mr.addMigration(...);
    mr.addMigration(...);

    MigrationEngine.withSession(session).migrate(mr);
  }
}

然后像这样更新我的入口点类:

// annotations
public class MyApplication extends SpringBootServletInitializer {

  private final static String MIGRATE_COMMAND = "migrate";

  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(MyApplication.class);
  }

  public static void main(String[] args) {
    if (args.length > 0 && args[0].equalsIgnoreCase(MIGRATE_COMMAND)) {
      new SpringApplicationBuilder()
          .sources(MigrationRunner.class)
          .run(Arrays.copyOfRange(args, 1, args.length));
    } else {
      new MyApplication().configure(new SpringApplicationBuilder(MyApplication.class)).run(args);
    }
  }
}

问题是,当我使用migratearg 执行此操作时,Spring 会抛出此错误:

创建名称为“migrationRunner”的 bean 时出错:通过字段“会话”表达的不满足的依赖关系

在类路径资源 [org/springframework/boot/autoconfigure/data/cassandra/Cas​​sandraDataAutoConfiguration.class] 中定义名称为“会话”的 bean 创建错误:调用 init 方法失败

尝试查询的所有主机都失败(尝试:server022/XX.YY.ZZ.022:9042 (com.datastax.driver.core.exceptions.TransportException: [server022/XX.YY.ZZ.022:9042] 连接已关闭), server022/XX.YY.ZZ.020:9042 (com.datastax.driver.core.exceptions.TransportException: [server020/XX.YY.ZZ.020:9042] 连接已关闭), server020/ XX.YY.ZZ.021:9042(com.datastax.driver.core.exceptions.TransportException: [server020/XX.YY.ZZ.021:9042] 连接已关闭))

migrate在没有arg的情况下运行它仍然可以正常工作。我怀疑Spring 根本没有为这个 Cassandra 服务器获取正确的证书,即使它似乎正在获取所有其他配置属性(服务器名称、密钥空间等)

问题:如何制作一个同时具有命令行模式并且可以在两种模式下连接到配置的 Cassandra 服务器的 Spring Boot servlet?

标签: javaspringspring-bootcassandradata-migration

解决方案


你需要做的就是,

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

您的应用程序过于复杂。如果您运行,默认情况下MyApplication.main将在端口中运行。8080

奖金,如果您需要两者都从相同的class.

@SpringBootApplication
public class MigrationRunner implements CommandLineRunner {

  @Autowired
  Session session;


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

  @Override
  public void run(String[] args)
  {
    MigrationResources mr = new MigrationResources();
    mr.addMigration(...);
    mr.addMigration(...);

    MigrationEngine.withSession(session).migrate(mr);
  }
}

推荐阅读