Skip to main content

Spring MVC 3.2 Preview: Introducing Servlet 3, Async Support


Continuing the Spring 3.0 "simplification series" started by Keith and Chris, I would like to provide a quick overview of simplifications in scheduling and task execution enabled by Spring 3.0.
I will be walking through a basic sample application that you can checkout from the spring-samples Subversion repository. It has been designed to be as simple as possible while showcasing both annotation-driven and XML-based approaches to scheduling tasks in Spring 3.0.
Let's begin with the annotation-driven approach. You can run it directly via the main() method in AnnotationDemo. If you take a look, you'll see that it's nothing more than a bootstrap for a Spring ApplicationContext:
public static void main(String[] args) {
    new ClassPathXmlApplicationContext("config.xml", AnnotationDemo.class);
}
The reason nothing else is necessary is that the ApplicationContext contains an "active" component, which we will see in just a moment. Because of that component, the main() method will not exit. The config.xml is also minimal, containing only two elements:
<context:component-scan base-package="org/springframework/samples/task/basic/annotation"/>
<task:annotation-driven/>
The "component-scan" element points to the package that contains our "beans". There are two of them: ScheduledProcessor and AsyncWorker. We'll look at those momentarily, but first take a look at the "annotation-driven" element. That's the one that is new in Spring 3.0, and it drives two annotations: @Scheduled and @Async. You could provide references to a Spring TaskScheduler and TaskExecutor with the "scheduler" and "executor" attributes respectively, but for this sample, we'll just rely on the defaults.
The ScheduledProcessor contains the @Scheduled annotation on a method and is therefore the "active" component I mentioned above. Since the 'annotation-driven' element exists in the configuration, this method will be registered with a Spring TaskScheduler instance that will execute the method periodically with a fixed delay of 30 seconds.
@Service
public class ScheduledProcessor implements Processor {
    private final AtomicInteger counter = new AtomicInteger();
    @Autowired
    private Worker worker;
    @Scheduled(fixedDelay = 30000)
    public void process() {
        System.out.println("processing next 10 at " + new Date());
        for (int i = 0; i < 10; i++) {
            worker.work(counter.incrementAndGet());
        }
    }
}
As you can see in the previous code excerpt, the Worker is invoked by the ScheduledProcessor within a loop. However, the AsyncWorker implementation contains the @Async annotation on its work(..) method, and due to the 'annotation-driven' element in the configuration, this will be wrapped in a proxy so that the method is actually invoked by a TaskExecutor instance. To verify that, the current thread name is displayed within that method. Likewise, to clarify that work is being performed concurrently, a sleep(..) call is made to simulate time-consuming work.
@Component
public class AsyncWorker implements Worker {
    @Async
    public void work(int i) {
        String threadName = Thread.currentThread().getName();
        System.out.println("   " + threadName + " beginning work on " + i);
        try {
            Thread.sleep(5000); // simulates work
        }
        catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("   " + threadName + " completed work on " + i);
    }
}
If you run the AnnotationDemo main() method, the output should look something like this:

processing next 10 at Mon Jan 04 18:20:52 EST 2010
SimpleAsyncTaskExecutor-1 beginning work on 1
SimpleAsyncTaskExecutor-2 beginning work on 2
SimpleAsyncTaskExecutor-3 beginning work on 3
SimpleAsyncTaskExecutor-5 beginning work on 5
SimpleAsyncTaskExecutor-4 beginning work on 4
SimpleAsyncTaskExecutor-6 beginning work on 6
SimpleAsyncTaskExecutor-7 beginning work on 7
SimpleAsyncTaskExecutor-8 beginning work on 8
SimpleAsyncTaskExecutor-9 beginning work on 9
SimpleAsyncTaskExecutor-10 beginning work on 10
SimpleAsyncTaskExecutor-1 completed work on 1
SimpleAsyncTaskExecutor-2 completed work on 2
SimpleAsyncTaskExecutor-3 completed work on 3
SimpleAsyncTaskExecutor-5 completed work on 5
SimpleAsyncTaskExecutor-6 completed work on 6
SimpleAsyncTaskExecutor-7 completed work on 7
SimpleAsyncTaskExecutor-8 completed work on 8
SimpleAsyncTaskExecutor-4 completed work on 4
SimpleAsyncTaskExecutor-10 completed work on 10
SimpleAsyncTaskExecutor-9 completed work on 9

There are a few things to notice about that output. First, the processing of 10 rows at a time will repeat every 30 seconds (due to @Scheduled). Second, the work items are being processed concurrently by different threads (due to @Async). There should be a pause of roughly 5 seconds between the last "beginning work" message and first "completed work" message. If the workers were all running in a single thread, we would instead see sequential beginning/completed pairs, and the entire process would take about 50 seconds. Of course, the temporal aspect cannot be captured here in the blog entry, so you really should download and run the sample yourself for the full effect (the project can be imported directly into SpringSource Tool Suite or another Eclipse-based environment with Maven support).
The last thing I want to show is the XML-based alternative for the @Scheduled annotation. The sample includes another class, SimpleProcessor, that does not contain @Scheduled on its process() method:
@Service
public class SimpleProcessor implements Processor {
    private final AtomicInteger counter = new AtomicInteger();
    public void process() {
        System.out.println("processing next 10 at " + new Date());
        for (int i = 0; i < 10; i++) {
            System.out.println("   processing " + counter.incrementAndGet());
        }
    }
}
The XML is only slightly more verbose than the annotation-driven version, because Spring 3.0 now provides a "task" namespace to keep the configuration concise.
<context:component-scan base-package="org/springframework/samples/task/basic/xml"/>
<task:scheduled-tasks>
    <task:scheduled ref="simpleProcessor" method="process" cron="3/10 * * * * ?"/>
</task:scheduled-tasks>
If you run the main() method in XmlDemo, you will see that process execute every 10 seconds. For variety, this one uses a cron expression instead of the simple fixed-delay. As a result, you will notice that the timing is based on a 3 second offset (:13, :23, etc), but of course cron expressions can be much more powerful than that (I just didn't want to create a sample that would only run on certain days or times of day). It's worth pointing out that the support for cron-based scheduling is included directly within Spring 3.0 itself.
Be sure to check out the Task Execution and Scheduling chapter of the Spring 3.0 Reference Manual to learn more about the new TaskScheduler abstraction and Trigger strategies that provide the foundation for what you've seen here. The reference manual also discusses additional elements provided by the "task" namespace for configuring TaskScheduler and TaskExecutor instances with specific thread pool settings.
I hope this post has provided a useful overview of these new features. Stay tuned to the SpringSource team blog for more Spring 3.0 related content.


from http://blog.springsource.org/2012/05/06/spring-mvc-3-2-preview-introducing-servlet-3-async-support/

Comments

Popular posts from this blog

How to install JSVC on Linux WidenHome Log | WidenHome Log

How to install JSVC on Linux WidenHome Log | WidenHome Log In our team, we have a lot of Java standalone applications which should be run as daemon on Unix/Linux system, and we found JSVC is the best choice for us to wrap Java programs to daemons. This article records the steps on how to install JSVC executable on Linux, which is our stage/prod environment. Download JSVC source package First of all, we need to download JSVC source package from this URL: http://commons.apache.org/daemon/download_daemon.cgi , for example, I downloaded commons-daemon-1.0.5-src.tar.gz file. Or, download it via wget: wget -c http://apache.etoak.com/commons/daemon/source/commons-daemon-1.0.5-src.tar.gz Build JSVC executable Unzip the source package and build JSVC executable. chmod 755 commons-daemon-1.0.5-src.tar.gz tar zxvf commons-daemon-1.0.5-src.tar.gz cd commons-daemon-1.0.5-src/src/native/unix Before building the JSVC executable, please make sure you have set JAVA_HOME variable correctly. And make sur...

Java中的Serializable浅谈

from  http://www.cnblogs.com/vicenteforever/articles/1471775.html 对象的串行化(Serialization) 一、串行化的概念和目的 1.什么是串行化             对象的寿命通常随着生成该对象的程序的终止而终止。有时候,可能需要将对象的状态保存下来,在需要时再将对象恢复。我们把对象的这种能记录自己的状态以便将来再生的能力。叫作对象的持续性(persistence)。对象通过写出描述自己状态的数值来记录自己 ,这个过程叫对象的串行化(Serialization) 。串行化的主要任务是写出对象实例变量的数值。如果交量是另一对象的引用,则引用的对象也要串行化。这个过程是递归的,串行化可能要涉及一个复杂树结构的单行化,包括原有对象、对象的对象、对象的对象的对象等等。对象所有权的层次结构称为图表(graph)。 2.串行化的目的             Java对象的单行化的目标是为Java的运行环境提供一组特性,如下所示: 1)       尽量保持对象串行化的简单扼要 ,但要提供一种途径使其可根据开发者的要求进行扩展或定制。 2)       串行化机制应严格遵守Java的对象模型 。对象的串行化状态中应该存有所有的关于种类的安全特性的信息。 3)       对象的串行化机制应支持Java的对象持续性。 4)       对象的串行化机制应有足够的 可扩展能力以支持对象的远程方法调用(RMI)。 5)       对象串行化应允许对象定义自身 的格式即其自身的数据流表示形式,可外部化接口来完成这项功能。 什么情况下需要序列化 a)当...

Log4j Configuration

First, include  Log4j   jar file in your project (e.g. log4j-1.2.8.jar) From  http://www.javabeat.net/tips/82-baisc-steps-to-configure-log4j-using-xml-and.html Configure Log4j This example demonstrated how to configure  Log4j  setup using the Proerties file and  XML file . These are the two most widely used techniques for configuring the  Log4j  for your application. But, in the recent days configuring with  properties files  are considered to be old technique and recommended using  XML . This example program uses simple satndalone java program for running the example. But, in most of the  project  scenarios it will be used in the web application. However the configuration file will be the same. log4j.properties # Set root logger level to DEBUG and its only appender to Appender1. log4j.rootLogger=INFO, Appender1,Appender2 # Appender1 is set to be a ConsoleAppender. log4j.appender.Appender1=org.apache...