Reputation: 362
I have a main Spring Boot application in the top-level package that I launch, with different controllers in the children packages:
i.e.
ca.example.batch.MainBatchApplication
ca.example.batch.job1.Job1Controller (/batch/startJob1)
ca.example.batch.job2.Job2Controller (/batch/startJob2)
I am able to start the Spring Batches by going to the URL: http://localhost:8080/batch/startJob1 or http://localhost:8080/batch/startJob2.
However, in another package I have:
ca.example.batch.job3.Job3Controller
ca.example.batch.job3.Job3Application
... which is not a Spring Batch, but a Spring CommandLineRunner. I want to know if there is a way to launch MainBatchApplication without starting that CommandLineRunner automatically, but run it through the controller, i.e. http://localhost:8080/batch/startJob3.
The controller code I am looking at is:
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 is:
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);
}
}
}
The error I get in the log is:
""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)
... when I launch the controller request.
If this isn't the right way, please advise.
Basically, what I am trying to do is launch a main() from within a controller but use the MainBatchApplication runtime to run it (if that makes sense?). When the program is done, it send the return code back to the controller and shows in the browser.
Thank you, Joey
Upvotes: 1
Views: 2031
Reputation: 6936
ca.example.batch.MainBatchApplication
is the main appliction you start.
So it scans all Components in package ca.example.batch
. That means it should detect ca.example.batch.job3.Job3Application
so you should be able to @Autowire
it in the Job3Controller
this should work:
@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";
}
....
}
Upvotes: 1