Как запустить CommandLineRunner из Spring Controller

У меня есть основное приложение Spring Boot в пакете верхнего уровня, который я запускаю, с разными контроллерами в дочерних пакетах:

т.е.

ca.example.batch.MainBatchApplication
ca.example.batch.job1.Job1Controller (/batch/startJob1)
ca.example.batch.job2.Job2Controller (/batch/startJob2)

Я могу запустить пакеты Spring, перейдя по URL-адресу: http: // локальный: 8080 / партия / startJob1 или http: // локальный: 8080 / партия / startJob2.

Однако в другом пакете у меня есть:

ca.example.batch.job3.Job3Controller
ca.example.batch.job3.Job3Application

... это не Spring Batch, а Spring CommandLineRunner. Я хочу знать, есть ли способ запустить MainBatchApplication без автоматического запуска этого CommandLineRunner, но запустить его через контроллер, то есть http: // локальный: 8080 / партия / startJob3.

Код контроллера, на который я смотрю:

package ca.example.batch.job3;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class Job3Controller {

    @RequestMapping("/batch/startJob3")
    public String handle() throws Exception {

        Job3Application app = new Job3Application();

        Logger logger = LoggerFactory.getLogger(this.getClass());

        logger.info("app: " + app);

        String args = "";
        app.run(args);

        return "COMPLETE";
    }
}

Job3Application:

package ca.example.batch.job3;

import static java.lang.System.exit;
import java.util.List;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.Banner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Import;
import ca.example.batch.common.CommonLibraryReference;
import ca.example.batch.common.domain.WasHost;
import ca.example.batch.common.svc.WasHostService;

@SpringBootApplication
@Import(CommonLibraryReference.class)
public class Job3Application implements CommandLineRunner {

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

    @Autowired
    public DataSource dataSource;

    @Autowired
    public WasHostService wasHostService;

    public Job3Application() {
    }

    public static void main(String[] args) throws Exception {
        new SpringApplicationBuilder(Job3Application.class)
        .web(WebApplicationType.NONE)
        .bannerMode(Banner.Mode.OFF)
        .run(args);
    }

    @Override
    public void run(String... strings) throws Exception {
        logger.info("Loading data...");

        logger.info("wasHostService: " + wasHostService);
        List<WasHost> hostList = wasHostService.findAll();
        if (!hostList.isEmpty()) {
            for (WasHost host : hostList) {
                logger.info("hostname: " + host.getHostname());
            }
        } else {
            logger.info("No hosts found in database. Aborting data collection.");
            exit(0);
        }
    }
}

Ошибка, которую я получаю в журнале:

""2018-07-07 12:56:09 [http-nio-9191-exec-1] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring FrameworkServlet 'dispatcherServlet'
""2018-07-07 12:56:09 [http-nio-9191-exec-1] INFO  c.e.b.job3.Job3Controller - app: ca.example.batch.job3.Job3Application@472d7ac
""2018-07-07 12:56:09 [http-nio-9191-exec-1] INFO  c.e.b.job3.Job3Application - Loading data...
""2018-07-07 12:56:09 [http-nio-9191-exec-1] INFO  c.e.b.job3.Job3Application - wasHostService: null
""2018-07-07 12:56:09 [http-nio-9191-exec-1] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
"java.lang.NullPointerException: null
    at ca.example.batch.job3.Job3Application.run(Job3Application.java:47)
    at ca.example.batch.job3.Job3Controller.handle(Job3Controller.java:21)

... когда я запускаю запрос контроллера.

Если это неправильный способ, сообщите об этом.

По сути, я пытаюсь запустить main () из контроллера, но использую среду выполнения MainBatchApplication для его запуска (если это имеет смысл?). Когда программа завершена, она отправляет код возврата обратно в контроллер и отображается в браузере.

Спасибо, Джоуи

удалил ответ, так как вопрос изменился. Job3Application run(...) только ведет журнал или завершает работу приложения !? Так что я не думаю, что это очень полезно.

Dirk Deyne 07.07.2018 18:24

Я удалил большую часть кода для простоты. Однако, глядя на код, который у меня есть, Job3Application должен получить список из базы данных и зарегистрировать их. Этого не происходит, потому что «wasHostService» имеет значение null. Если я запускаю Job3Application отдельно, он работает нормально. Ошибка при запросе с контроллером ...

Joey Cote 07.07.2018 18:27

угадайте, вы забыли добавить @Import(CommonLibraryReference.class) в MainBatchApplication?

Dirk Deyne 07.07.2018 18:36

Нет, это его часть. Я добавил его в Job3Application, чтобы посмотреть, поможет ли это, но не помогло.

Joey Cote 07.07.2018 18:38

Есть что-то в создании экземпляра «приложения» внутри Job3Controller, которое не инициализирует @Autowired WasHostService в Job3Application.

Joey Cote 07.07.2018 18:41

еще раз: Job3Application run (...) только ведет журнал или завершает работу приложения !? Так что и new Job3Application() делать не стоит! Просто создайте component, где вы выполняете импортированные вещи, которые вам нужно сделать, и используйте (конструктор) инъекцию, чтобы получить этот компонент в вашем контроллере и запустить метод для выполнения задания.

Dirk Deyne 07.07.2018 18:53

обратите внимание, что вы должны иметь возможность автоматически подключать Job3Application в своем контроллере ... и вы должны увидеть строки журнала в консоли Загрузка данных..., wasHostService: ..

Dirk Deyne 07.07.2018 19:15
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
7
1 240
1

Ответы 1

ca.example.batch.MainBatchApplication - это главное приложение, которое вы запускаете. Таким образом, он сканирует все компоненты в пакете ca.example.batch. Это означает, что он должен обнаружить ca.example.batch.job3.Job3Application, поэтому вы сможете найти @Autowireit в Job3Controller.

это должно работать:

@Controller
public class Job3Controller {
  private final Job3Application job3Application;      

  public Job3Controller (Job3Application job3Application){
     this.job3Application = job3Application;
  }

  @RequestMapping("/batch/startJob3")
  public String handle() throws Exception {
    String[] args = ...
    this.job3Application.run(args);
    return "COMPLETE";
  }

  ....
}

почему бы просто не создать общую службу между бегуном и контроллером, чтобы вам не пришлось смешивать реализации?

Darren Forsythe 07.07.2018 20:04

@DarrenForsy правильно, это был бы лучший подход (и я предложил это в комментариях) ... но это не отвечает на вопрос `` Как запустить CommandLineRunner из Spring Controller ''

Dirk Deyne 07.07.2018 20:18

Дирк, с вашим кодом я получаю это при запуске MainBatchApplication: Consider defining a bean of type 'ca.example.batch.job3.Job3Application' in your configuration.

Joey Cote 08.07.2018 21:05

если вы не исключили Job3Application в своем MainBatchApplication, он должен присутствовать. Каждый @SpringBootApplication сам по себе является @Configuration, так что это компонент ... Можете ли вы показать использование MainBatchApplication?

Dirk Deyne 08.07.2018 21:49

Ах! Я исключил классы типа CommandLineRunner, потому что не хотел, чтобы он запускался с MainBatchApplication, а только тогда, когда вызывается Job3Controller. Если я удалю исключение из MainBatchApplication, что мне делать в Job3Application, чтобы предотвратить автоматический запуск?

Joey Cote 09.07.2018 02:20

разве это не очевидно? удалите commandlinerunner, переименуйте метод run () и вызовите его со своего контроллера ...

Dirk Deyne 09.07.2018 08:25

Я начал читать CommandLineRunner, и его намерение (которое запускается после запуска приложения) противоречило тому, чего я пытался достичь. Я сделал то, что вы сказали, и теперь могу вызвать код метода run () (в Job3Application) с моего контроллера. Для новичка нет ничего очевидного. Спасибо за помощь. Я приму твой ответ.

Joey Cote 09.07.2018 15:45

Другие вопросы по теме