Wednesday, January 13, 2010

Asynchronous Code with Spring 3 – Simple as an annotation

After reviewing some of the features of Spring 3, i decided to test out the asychronous features via annotation. And below is all the code i needed in order to have a function executed asynchronously in my application:



   1: public class Asyncher {



   2:     @Async



   3:     public void myMethod(int i) {



   4:         try {



   5:             Thread.sleep(2000);



   6:         } catch (InterruptedException e) {



   7:             e.printStackTrace();



   8:         }



   9:         System.out.println("Running for " + i);



  10:     }



  11:  



  12:     public static void main(String[] args) throws InterruptedException {



  13:         ApplicationContext ctx = new ClassPathXmlApplicationContext("appContext.xml");



  14:         Asyncher a = ctx.getBean("asyncher", Asyncher.class);



  15:         for (int i=0; i<10;i++) {



  16:                 a.myMethod(i);



  17:         }      



  18:  



  19:         ThreadPoolTaskExecutor t = ctx.getBean("myExecutor",ThreadPoolTaskExecutor.class);



  20:         while (t.getActiveCount() > 0) {



  21:             System.out.println("Number of tasks left: " + t.getActiveCount());



  22:             Thread.sleep(2000);



  23:         }



  24:         t.shutdown();



  25:     }



  26: }



Hard to believe, but all i needed to do was add the Async annotation on line 2 to my function and it works. of course we need a few lines in our application Context to make this work, but here they are:


   1: <?xml version="1.0" encoding="UTF-8"?>



   2: <beans xmlns="http://www.springframework.org/schema/beans"



   3:        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"



   4:        xmlns:context="http://www.springframework.org/schema/context"



   5:        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">



   6:  



   7:     <task:annotation-driven executor="myExecutor" />



   8:     <task:executor id="myExecutor" pool-size="2"/>



   9:     <bean id="asyncher" class="Asyncher"/>



  10:  



  11: </beans>


This same method can be used to create scheduled jobs as well, by changing or adding on line 7 the scheduler attribute and then adding in a scheduler bean

<task:scheduler id="myScheduler" pool-size="10"/>

You can read about it in the docs here

3 comments:

  1. Important note is that all calls need to be from the highest level so that Spring can intercept. If you invoke one method and then that method invokes the asynchronous annotated one, it will not work. I ran into this problem but solved it by making the code to run asynchronously an inner class. This inner class then needs to be declared in your application context

    ReplyDelete
  2. David R, you just saved my day man...
    I was calling @Async methods from within class and wondering why it is still in same thread... :(

    ReplyDelete
  3. Hi David,

    i am facing problem while using the @Async annotation. i am using a file which is been invoked from the web.xml as a contextListener. i am getting error in that file as

    Multiple annotations found at this line:
    - schema_reference.4: Failed to read schema document 'http://www.springframework.org/schema/task/spring-task-3.0.xsd', because 1) could not find the document;
    2) the document could not be read; 3) the root element of the document is not .
    - cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'task:annotation-driven'.


    Can you please help me on this.

    ReplyDelete