I am trying to execute a method in a separate thread, when the server starts. Please find my main class below:
#SpringBootApplication
#EnableSwagger2
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public TaskExecutor taskExecutor() {
return new SimpleAsyncTaskExecutor();
}
#Bean
public CommandLineRunner schedulingRunner(TaskExecutor executor) {
return new CommandLineRunner() {
public void run(String... args) throws Exception {
executor.execute(new CsvReader());
}
};
}
}
#Component
public class CsvReader implements Runnable{
#Value("${file-url}")
private String appUrl;
#Override
public void run() {
System.out.println("run after Object created: "+ appUrl); // this is coming as null. Not able to read it from application.properties
}
}
You can use #PropertySource annotation.
Something like this
#SpringBootApplication
#PropertySource("application.properties")
#EnableSwagger2
public class Application {
// Your code
}
You can Autowire the value like this
#Component
public class CsvReader implements Runnable{
#Value("${property.name.from.application.properties.file}")
private String appUrl;
#Override
public void run() {
System.out.println("run after Object created: "+ appUrl); // this is coming as null. Not able to read it from application.properties
}
}
Got the issue,
As I am executing CsvReader in a separate thread, container is not taking care of the bean initialisation, and thus dependency injections are not working.
Fixed the issue by
#Configuration
public class CsvReader {
#Value("${file-url}")
private String appUrl;
#PostConstruct
private void runAfterObjectCreated() {
Thread thread = new Thread() {
public void run() {
System.out.println("run after Object created: "+ appUrl);
}
};
thread.start();
}
}
With the above code, I am delegating the bean instantiation to the container.
#PostConstruct, ensures execution, once the class is loaded, and because I have a Thread class instantiated, by method is running in a new thread.
Option 2
#SpringBootApplication
#EnableSwagger2
public class Application {
#Autowired
private CsvReader csvReader;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner schedulingRunner(TaskExecutor executor) {
return new CommandLineRunner() {
public void run(String... args) throws Exception {
executor.execute(csvReader);
}
};
}
}
Related
I am struggling to run a thread in background with autowired bean in spring boot. From all the internet source I found that if I create a new instance of the object it will throw null because it is not part of spring life cycle and I would instead need to use executorTask and inject it as bean. Here is what I have tried so far with no luck.
My Application.java file
#SpringBootApplication
#EnableAsync
public class Application {
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
SpringApplication.run(Application.class, args);
}
}
My ThreadConfig.java file [where I actually create the bean for task executor]
#Configuration
public class ThreadConfig {
#Bean
public TaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(4);
executor.setThreadNamePrefix("default_task_executor_thread");
executor.initialize();
return executor;
}
}
The AsyncService.java file
#Service
public class AsynchronousService {
#Autowired
private ApplicationContext applicationContext;
#Autowired
private TaskExecutor taskExecutor;
public void executeAsynchronously() {
NotificationThread myThread = applicationContext.getBean(NotificationThread.class);
taskExecutor.execute(myThread);
}
}
The actual thread that I want to run in background
#Component
#Scope("prototype")
public class NotificationThread implements Runnable {
#Autowired
private UserDao userDao;
public void run() {
while (true) {
System.out.println("thread is running...");
List<User> users = userDao.findAllByType("1"); //Used to get Error here when running directly from main
try {
Thread.sleep(1000 );
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Before when I directly create this thread in main I would get error as mentioned in the comment line. So i switched to taskexecutor.
NotificationThread is the thread i want to run in background. But its not working, not sure what changes to make. Would help guidance.
Need to call the service method executeAsynchronously() to start the flow.
You may auto-wire AsynchronousService to the ThreadAppRunner as follows and call service.executeAsynchronously().
#Component
public class ThreadAppRunner implements ApplicationRunner {
#Autowired
AsynchronousService service;
#Override
public void run(ApplicationArguments args) throws Exception {
service.executeAsynchronously()
}
}
During the startup process, my application creates bean which schedules some tasks in task executor, and then it fails after creating another bean.
This leaves my application in undead state where application looks like it's running but does not provide functionality.
I wonder how I could handle BeanCreationException globally to provide proper shutdown.
This is my example code
#SpringBootApplication
#EnableAutoConfiguration
public class Application {
ExecutorService executorService = Executors.newCachedThreadPool();
public Application(){
executorService.submit(()-> {while(true);});
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
#Service
public class FaultyService {
public FaultyService(){
throw new RuntimeException("error");
}
}
You can add a #PreDestroy to shut down the executor. However, it is still the responsibility of your threads to respond to Thread.interrupt() so your infinite while-loop would not be killed, but yours is just a contrived example so I've changed that too:
#SpringBootApplication
#EnableAutoConfiguration
public class Application {
ExecutorService executorService = Executors.newCachedThreadPool();
public Application() {
executorService.submit(() -> {
while (true)
{
if (Thread.interrupted()) break;
}
});
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#PreDestroy
public void tearDownExecutor() {
executorService.shutdownNow();
}
}
#Service
public class FaultyService {
public FaultyService(){
throw new RuntimeException("error");
}
}
I am tasked with making our database writes asynchronous. Sounds pretty simple on the surface, but the info I'm getting online isn't all that helpful and what I hear from co-workers is "asynch is tricky". So, I'm hoping to get something more helpful than "play with it bit until you get it to work". My code/call looks like this:`
#EnableAsync
#SpringCloudApplication
//To run as a FAT JAR:
//public class Application {
// Only extend when running as WAR
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}}
public class MyClass{
public void asyncCall(){
if(1==1){
DatabaseWriter.testAsync();
System.out.println("past DatabaseWriter.testAsync() method");
return;
}
}}
public class DatabaseWriter {
#Async
public static Future<Object> testAsync(){
Thread.sleep(10000);
println ("end of DatabaseWriter.testAsync() method");
return null;
}}
`
So, my output consistently comes out looking like this:
end of DatabaseWriter.testAsync() method
past DatabaseWriter.testAsync() method
Obviously, the original method call is waiting for the return from the testAsync() method. I'm looking for direction on what I'm doing wrong.
#Async annotation works only for beans from the spring context, because spring creates proxy around async method. So if you create bean with new keyword:
new DatabaseWriter();
or if you put #Async annotation on static method it will not work, because there will be original method instead of proxy.
That example works well. To start the application just run the main method
#SpringBootApplication
#EnableAsync
public class Application extends AsyncConfigurerSupport {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("GithubLookup-");
executor.initialize();
return executor;
}
}
#Component
class AppRunner implements CommandLineRunner {
public static final Logger logger = LoggerFactory.getLogger(AppRunner2.class);
#Autowired
private DatabaseWriter writer;
#Override
public void run(String... args) throws Exception {
logger.info("--- start ---");
writer.testAsync();
logger.info("--- stop ---");
}
}
#Component
class DatabaseWriter {
#Async
public Future<Object> testAsync() throws InterruptedException {
Thread.sleep(5000);
AppRunner.logger.info("end of DatabaseWriter.testAsync() method");
return null;
}
}
You can try to replace line
writer.testAsync();
with
new DatabaseWriter().testAsync();
and will see that the #Async doesn't work.
I am new to Apache Camel and trying to receive a simple SNMP trap.
I have the Maven project set up with camel-core and org.apache.servicemix.bundles.snmp4j.
I have not been able to find any SNMP examples, but based on other examples I have come up with this Main class:
public class Main {
public static Processor myProcessor = new Processor() {
public void process(Exchange arg0) throws Exception {
// save to database
}
};
public static void main(String[] args) {
CamelContext context = new DefaultCamelContext();
context.addComponent("snmp", new SnmpComponent());
RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("snmp:127.0.0.1:162?protocol=udp&type=TRAP").process(myProcessor);
}
};
try {
context.addRoutes(builder);
context.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
However when I run it in Eclipse as Java application it just exits after running for half a second. I was expecting it to keep running and listening to 127.0.0.1:162 ...
Any help is greatly appreciated
One way to at least pick up a trap and print to System.out is like so:
public class SNMPTrap {
private Main main;
public static void main(String[] args) throws Exception {
SNMPTrap snmpTrap = new SNMPTrap();
snmpTrap.boot();
}
#SuppressWarnings("deprecation")
public void boot() throws Exception {
main = new Main();
main.bind("snmp", new SnmpComponent());
main.addRouteBuilder(new MyRouteBuilder());
main.addMainListener(new Events());
System.out.println("Starting SNMPTrap. Use ctrl + c to terminate the JVM.\n");
main.run();
}
private static class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
from("snmp:127.0.0.1:162?protocol=udp&type=TRAP").process(myProcessor)
.bean("snmp");
}
}
public static Processor myProcessor = new Processor() {
public void process(Exchange trap) throws Exception {
System.out.println(trap.getIn().getBody(String.class));
// Save to DB or do other good stuff
}
};
public static class Events extends MainListenerSupport {
#Override
public void afterStart(MainSupport main) {
System.out.println("SNMPTrap is now started!");
}
#Override
public void beforeStop(MainSupport main) {
System.out.println("SNMPTrap is now being stopped!");
}
}
}
However, I get warning that Main which is part of Camel core is deprecated now.
I have an application built upon Spring Boot. There is simple controller with a method which creates new Thread and starts it. However a runnable executes unix command (nc) (used ProcessBuilder for that). Thus when I'm runnning it on the windows I get exceptions from started thread. Indeed it can not run unix program. Now I would like to write a test for this controller, but I'm wondering is it possible and reasonable. I was thinking about changing behaviour of runnable task just for testing, although I don't know how can it be done. Thanks for any help and other ideas/solutions for this case.
Controller:
#Controller
public class TaskController {
ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(task-%d").build();
#RequestMapping(value = "/startTask")
public #ResponseBody ResponseEntity<String> startTask() {
Runnable runnable= new Task();
threadFactory.newThread(runnable).start();
return new ResponseEntity<String>("Task started", HttpStatus.ACCEPTED);
}
}
Task:
public class Task implements Runnable {
#Override
public void run() {
// start unix process
}
}
Application class:
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Integration Test:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
#IntegrationTest("server.port=0")
#DirtiesContext
public class ApplicationTest {
#Value("${local.server.port}")
private int port;
#Test
public void shouldStartTask() throws Exception {
// when
ResponseEntity<String> entity = new TestRestTemplate().getForEntity("http://localhost:" + this.port + "/startTask", String.class);
// then
assertThat(entity.getStatusCode()).isSameAs(HttpStatus.ACCEPTED);
}
}
You might find it easier to test your program if you the extract the processing logic of your application (which does things using threads) from your controller logic, placing the processing logic in a separate service layer, which your controller delegates to. Design the service layer to have an API that is easy to unit test, by providing methods for accessing its current state, not just for performing actions. Use dependency injection to connect your controller to your service layer.
So, something like this:
public interface Service
{
// Sets this.wasTaskStarted() == true
void startTask();
boolean wasTaskStarted();
void awaitCompletionOfTask();
}
#Controller
public class TaskController {
private final Service service;
#Autowired
public TaskController(Service service) {
this.service = service;
}
#RequestMapping(value = "/startTask")
public #ResponseBody ResponseEntity<String> startTask() {
service.startTask();
return new ResponseEntity<String>("Task started", HttpStatus.ACCEPTED);
}
}
public ServiceImpl implements Service {
private final ThreadFactor threadFactory = new ....;
private Thread taskTread;
#Override
public synchronized void startTask() {
if (taskTread == null) {
taskTread = threadFactory.newThread(new Task());
taskTread.start();
notifyAll();
}
// else already started
}
#Override
public synchronized boolean wasTaskStarted() {
return taskTread != null;
}
#Override
public synchronized void awaitCompletionOfTask() {
while (taskTread == null) {
wait();
}
taskTread.join();
}
}
To test that your controller starts a task, you just need to test that Service.wasTaskStarted() is true after calling TaskController.startTask().
You also have to test your service layer:
public class ServiceImplTest
{
#Test
public void testStartTask() {
final ServiceImpl service = new ServiceImpl(....);
service.startTask();
assert(service.wasTastStarted());
}
#Test
public void testRunTask() {
final ServiceImpl service = new ServiceImpl(....);
service.startTask();
service.awaitCompletionOfTask();
// Add assertions here to test that the task did what it ought to do
}
}
Thanks for the suggestion. You just opened my mind and I changed the design a bit. I resigned from an integration test. From business point of view, I don't need to check whether task has been started or even completed. Now it looks as follows:
Controller:
#Controller
public class TaskController {
private ThreadService threadService;
#Autowired
public TaskController (ThreadService threadService) {
this.threadService= threadService;
}
#RequestMapping(value = "/startTask")
public #ResponseBody ResponseEntity<String> startTask() {
// some conditions here which I would like to test
threadService.startNewThread(new Task());
return new ResponseEntity<String>("Task started", HttpStatus.ACCEPTED);
}
}
Task:
public class Task implements Runnable {
#Override
public void run() {
// start unix process
}
}
Thread service:
#Component
public class ThreadService {
ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("task-%d").build();
public void startNewThread(Runnnable task) {
threadFactory.newThread(task).start();
}
}
And I decided to unit test my controller, stubbing ThreadService with mockito:
#RunWith(MockitoJUnitRunner.class)
public class TaskControllerTest {
#Mock
ThreadService threadService;
#InjectMocks
private TaskController objectUnderTest;
#Test
public void shouldStartTask() throws FileNotFoundException {
// when
ResponseEntity<String> response = objectUnderTest.startTask();
// then
assertThat(response.getStatusCode()).isSameAs(HttpStatus.ACCEPTED);
// more assertions
}