0

I'm toying with asynchronous calls to reduce some waiting time on client side when calling a page.

As a experiement i have a controller that calls a pojo with a method annotated with @Async. In that menthod i sleep for 10000 ms to simulation operation to test whether my theory works, and it seems not to. Code below and further information can be found after it:

Test Controller

@Conroller
public class TestController {
@RequestMapping("/test")
public String testAsyncCall() {

new AsyncTestClass().asyncOpOne();

return "secondpage";
}
}

Asynchronous Class containing the @Async annotated method

public class AsyncTestClass {
@Async
public void asyncOpOne() {
try {
        Thread.sleep(10000);
        System.out.println("done working");
    } catch (InterruptedException e) {
        //
    }
}
}

Now from my understanding when the client makes the call to "/test" in their browser the controller should return call the asynchronous method and instantly return "secondpage" to be rendered.

What is happening is that the controller doesn't return the second page until the 10000 ms in the asynchronous call has finished, only then it returns the secondpage.

FYI @EnableAsync is added to one of my config files (using Java Configuration).

What am i doing wrong here that is causing the controller to wait for the async to finish its sleep before continuing?

Aeseir
  • 7,754
  • 10
  • 58
  • 107
  • 2
    You aren't using the Spring configured instance but are constructing a new one yourself... Use the one configured by spring. – M. Deinum Apr 16 '15 at 13:18
  • @M.Deinum can you clarify, i don't understand what you mean by that – Aeseir Apr 16 '15 at 13:19
  • 1
    You are doing `new AsyncTestClass` which means you are constructing an instance yourself, outside the control of spring so basically your `@Async` is useless. Add a bean for the `AsyncTestClass` and inject that into your controller. – M. Deinum Apr 16 '15 at 13:20
  • So does that mean all methods i annotate @Async should be in a bean and injected? – Aeseir Apr 16 '15 at 13:22
  • @Aeseir Correct, otherwise you don't get the AOP-enabled proxy. – beerbajay Apr 16 '15 at 13:25
  • correct... It is no different as an `@Transactional` method, spring uses AOP to accomplish that behavior. – M. Deinum Apr 16 '15 at 13:25
  • Brilliant thanks guys. @M.Deinum please add answer so i can accept it as token of appreciation – Aeseir Apr 16 '15 at 13:29
  • possible duplicate of [Why is my Spring @Autowired field null?](http://stackoverflow.com/questions/19896870/why-is-my-spring-autowired-field-null) – chrylis -cautiouslyoptimistic- Apr 16 '15 at 13:41

1 Answers1

4

Spring uses AOP to apply @Async behavior to your beans (the same goes for @Transactional for instance).

Spring will only apply AOP to beans it knows, as you are constructing a new instance outside of the scope of Spring the @Async does nothing. Simply add it as a bean to your configuration and inject it into your controller.

@Bean
public AsyncTestClass asyncTestClass() {
    return new AsyncTestClass():
}

Then in your calling class.

@Conroller
public class TestController {

    @Autowired
    private AsyncTestClass asyncTestClass;

    @RequestMapping("/test")
    public String testAsyncCall() {

        asyncTestClass.asyncOpOne();
        return "secondpage";
    }
}
M. Deinum
  • 115,695
  • 22
  • 220
  • 224