Servlet 3.0 practice: asynchronous Servlet and comet style applications

Source: Internet
Author: User

Overview
The JSR 315 specification, as an important member of the Java EE 6 system, upgraded the latest servlet API version from 2.5 to 3.0, which is the biggest upgrade of the servlet version in the past 10 years, this upgrade introduces several exciting features for developers, such:

    • Pluggable Web architecture (Web framework pluggability ).
    • Using annotations to replace the EOD of traditional web. xml configuration files is easy to develop ).
    • Serlvet supports asynchronous processing.
    • Improved security, such as HTTP only cookies and login/logout.
    • Other improvements, such as direct support for file upload.

In the open-source Community The most discussed is the support of servlet asynchronous processing, the so-called servlet asynchronous processing, it includes non-blocking input/output, asynchronous event notification, delayed request processing, and delayed response output. Most of these features were not first proposed by the JSR 315 specification. For example, the advanced NiO technology is provided in Tomcat 6.0 so that a servlet thread can process multiple HTTP requests, jetty and glassfish have also had similar support. However, when using the advanced features provided by these Web containers, because the existing servlet APIs do not support such applications, you must introduce some proprietary Web Container classes, interfaces, or annotations, as a result, these advanced features must be coupled with specific containers, which is unacceptable for many projects. Therefore, after JSR 315 writes these features into specifications and provides unified API support, such asynchronous processing features are truly practical in a broad sense, as long as they support servlet 3.0 web containers, you can run the web without modification. Program .
The servlet asynchronous processing series in JSR 315 are useful in many occasions, but what people see first is that they are "server-side push) method-value in the comet mode interaction model. List of JSR 315 standard targets proposed on the JCP (Java Community process) website, the title of the asynchronous Processing Section is set to "async and comet support" (asynchronous and comet support ).
This article will introduce in detail the implementation of comet style applications and the practical application of asynchronous Processing Features in servlet 3.0 in Comet style programs.

Breakthrough in the classic request-response interaction model
"Comet technology", "server-side push", and "reverse Ajax technology" refer to the same thing, you may have heard of one or more of these items. It doesn't matter if you have never heard of it. A single sentence is enough to express all of them: "If there is no client request, the server sends data to the client ".
This sentence sounds simple and easy to understand, but any program that has been engaged in B/S application development for a long time knows that this implementation is not simple, even for a long time, people think this is impossible. This method does not conform to the traditional HTTP-based interaction philosophy: Only socket-level applications can achieve peer-to-peer communication between the server and the client. In HTTP-based applications, server only responds to requests from the client. It does not care about the status of the client and does not actively request information from the client. Therefore, HTTP is called stateless and unidirectional protocol, this interaction mode is called the request-response interaction model.
The stateless and unidirectional classic request-response interaction model has many advantages, such as high efficiency and high scalability. For applications that passively respond to user requests, such as CMS, MIS, and ERP, It is very suitable. However, for other applications that require active sending by the server, like chat rooms (when users do not speak, they also need to send the speeches of other users back), log systems (the client does not have a request, when the server has a log output, the initiative is sent to the client) it is difficult to process, or such applications are not suitable for processing using the classic request-response interaction model. When "unsuitable" and "On Demand" exist at the same time, people are constantly looking for ways to break through these limits.

 

Back to Top

Comet Implementation Method

  • in simple round-robin of the earliest web applications, the server changes are detected by regularly refreshing pages by means of JavaScript or meta HTML tags. Apparently, the server still passively responds to client requests when the page is refreshed on a regular basis, but the client requests are continuous and frequent, which makes the user seem to have the illusion that the server automatically sends the information. This method is simple and easy, but the defects are also very obvious: Most requests may be meaningless, because the events that the server expects do not happen, and there is actually no information to send, but I have to repeatedly respond to all the content on the page to the browser. In addition, when the server changes, it cannot return "real-time". The interval between refreshing is too short, this results in a great waste of performance. If the interval is too long, event notifications may arrive later than the expected time.
    when most browsers provide support for xhr (XMLHttpRequest) objects, Ajax technology becomes increasingly popular, in this phase, you do not have to return all the content on the whole page every time you perform polling. If no event is generated on the server side, you only need to return a very small amount of content in the HTTP report style. AJAX can save a lot of bandwidth waste in polling transmission, but it cannot reduce the number of requests. Therefore, simple polling implemented by Ajax still has polling limitations, which can only be mitigated to some extent, but cannot achieve qualitative changes.
  • The maximum difference between long round robin (hybrid round robin) and simple round robin is the length of connection time: When simple round robin is performed, the page is closed after the output of the connection, long polling usually lasts for 30 seconds or longer. When an expected event occurs on the server, an event notification will be immediately output to the client, and the connection will be closed, at the same time, the next connection is established to start a new long polling.
    The advantage of long polling is that when the server expects an event, the data is immediately returned to the client. No data is returned during this period, and no new requests are generated within a long wait period, this can reduce the number of requests sent, while the sensitivity of Event Notifications is greatly increased to almost "real-time.
  • The comet stream (forever frame) comet stream is a product of further development based on the long polling implementation idea. In this case, the persistent polling will not close the connection after the event notification is sent back to the client. Instead, the connection is reestablished until the timeout event occurs. This variation is called the comet stream. The client can use the readystate attribute in the XMLHTTPRequest object to determine whether it is using loading or loaded. In theory, a comet stream can use a link to process several server Event Notifications, further reducing the number of requests sent to the server.

Whether it is a long polling or comet stream, you must maintain a long connection status on the server and the client. This is not a great burden on the client, however, the server must serve multiple clients at the same time. According to the classic request-response interaction model, if each request occupies one web thread and is not released, web Container threads will soon run out, and these threads are mostly idle. This is why comet services are very eager for asynchronous processing. It is hoped that the Web thread does not need to process client requests synchronously and one-to-one, so that one web thread can process multiple client requests.

actual servlet asynchronous processing
currently, many web containers support servlet API 3.0, such as glassfish V3, Tomcat 7.0, and jetty 8.0. At the time of writing this article, tomcat 7 and jetty 8 are still in the test phase, although servlet 3.0 is supported, however, the provided Code is still the NIO implementation coupled with the container. The example provided by glassfish V3 (glass fish Chat Room) this is a fully standard servlet 3.0 implementation. If you need to find a reference example, you may first check the glassfish example directory. In the later part of this article, we will provide another more practical example "Web Log System" as a practical demonstration of servlet API 3.0.
Web Log System practice
Apache log4j is currently the most popular log processor. It has many different appender that can output logs to the console, files, databases, and emails. In most applications, it is impossible for users to view the console or log files of the server. If they can directly view logs in real time on the browser, it will be convenient for development and maintenance, in this example, a log is output to the browser appender.
List 1. log4j asynchronous web appender


/**
* Appender supported by asynccontext
* @ Author zzm
*/
Public class weblogappender extends writerappender {
/**
* Asynchronous servlet context queue
*/
Public static final queue <asynccontext> async_context_queue
= New concurrentincluqueue <asynccontext> ();

/**
* Asynccontextqueue writer
*/
Private writer = new asynccontextqueuewriter (async_context_queue );

Public weblogappender (){
Setwriter (writer );
}

Public weblogappender (layout ){
This ();
Super. layout = layout;
}
}

The above is the code template of the appender class, derived from Org. apache. log4j. writerappender, all the appender provided by log4j by default are inherited from this class. The logic executed by the subclass Code only tells writerappender how to obtain writer. What we are most concerned about is how to asynchronously output the log information to the browser, which is completed in asynccontextqueuewriter.

List 2: asynchronous context queue writer


/**
* Output data to the writer of each context in a queue <asynccontext>
* @ Author zzm
*/
Public class asynccontextqueuewriter extends writer {

/**
* Asynccontext queue
*/
Private queue <asynccontext> queue;

/**
* Message Queue
*/
Private Static final blockingqueue <string> message_queue
= New linkedblockingqueue <string> ();

/**
* Send a message to an asynchronous thread and finally output it to the HTTP Response stream.
* @ Param cbuf
* @ Param off
* @ Param Len
* @ Throws ioexception
*/
Private void sendmessage (char [] cbuf, int off, int Len) throws ioexception {
Try {
Message_queue.put (new string (cbuf, off, Len ));
} Catch (exception ex ){
Ioexception T = new ioexception ();
T. initcause (Ex );
Throw T;
}
}

/**
* Asynchronous threads, when data is put into the message queue, will release the blocking of the take method and send the data to the HTTP Response stream
*/
Private runnable notifierrunnable = new runnable (){
Public void run (){
Boolean done = false;
While (! Done ){
String message = NULL;
Try {
Message = message_queue.take ();
For (asynccontext AC: Queue ){
Try {
Printwriter acwriter = ac. getresponse (). getwriter ();
Acwriter. println (htmlescape (Message ));
Acwriter. Flush ();
} Catch (ioexception ex ){
System. Out. println (Ex );
Queue. Remove (AC );
}
}
} Catch (interruptedexception iex ){
Done = true;
System. Out. println (iex );
}
}
}
};

/**
* @ Param message
* @ Return
*/
Private string htmlescape (string message ){
Return "<SCRIPT type = 'text/JavaScript '> \ nwindow. Parent. Update (\""
+ Message. replaceall ("\ n", ""). replaceall ("\ r", "") + "\"); </SCRIPT> \ n ";
}

/**
* Keep a default writer and output it to the console.
* This writer is the synchronous output, and the writer that outputs other data to the response stream is the asynchronous output.
*/
Private Static final writer default_writer = new outputstreamwriter (system. Out );

/**
* Construct asynccontextqueuewriter
* @ Param queue
*/
Asynccontextqueuewriter (queue <asynccontext> Queue ){
This. Queue = queue;
Thread notifierthread = new thread (notifierrunnable );
Notifierthread. Start ();
}

@ Override
Public void write (char [] cbuf, int off, int Len) throws ioexception {
Default_writer.write (cbuf, off, Len );
Sendmessage (cbuf, off, Len );
}

@ Override
Public void flush () throws ioexception {
Default_writer.flush ();
}

@ Override
Public void close () throws ioexception {
Default_writer.close ();
For (asynccontext AC: Queue ){
AC. getresponse (). getwriter (). Close ();
}
}
}

this class is one of the key classes for Web Log implementation. It inherits from writer and is actually a set of writer, including at least one default writer that outputs data to the console, it also contains zero to several response writer determined by queue to output data to the client. In the process of output, writer on the console is synchronous and direct output, and the output to the HTTP client is asynchronous output by the thread notifierrunnable. The specific implementation method is that information is placed in the message_queue of the blocking queue, and the take () method of the queue is used in the subthread loop, when the queue has no data, this method will block the thread until new data is put into the queue.
we have logged on to log4j. modify the configuration in XML and change the appender to weblogappender. The extension of log4j is completed:
listing 3: log4j. xml configuration








Next, create a servlet that supports Asynchronization. Each client accessing this servlet registers an asynchronous context object in async_context_queue. In this way, when logger information occurs, it will be output to these clients. At the same time, a listener for this asynchronous context object will be created. When an event such as timeout or error occurs, the context will be removed from the queue.

List 4: Web Log registration Servlet


/**
* Servlet implementation class weblogservlet
*/
@ Webservlet (urlpatterns = {"/weblogservlet"}, asyncsupported = true)
Public class weblogservlet extends httpservlet {

/**
* Serialversionuid
*/
Private Static final long serialversionuid =-260157400324419618l;

/**
* Register the client to the Message Queue that listens to logger.
*/
@ Override
Protected void doget (httpservletrequest req, httpservletresponse res)
Throws servletexception, ioexception {
Res. setcontenttype ("text/html; charset = UTF-8 ");
Res. setheader ("cache-control", "private ");
Res. setheader ("Pragma", "No-Cache ");
Req. setcharacterencoding ("UTF-8 ");
Printwriter writer = res. getwriter ();
// For IE
Writer. println ("<! -- Comet is a programming technique that enables Web
Servers to send data to the client without having any need for the client
To request it. --> \ n ");
Writer. Flush ();

Final asynccontext AC = Req. startasync ();
AC. setTimeout (10*60*1000 );
AC. addlistener (New asynclistener (){
Public void oncomplete (asyncevent event) throws ioexception {
Weblogappender. async_context_queue.remove (AC );
}

Public void ontimeout (asyncevent event) throws ioexception {
Weblogappender. async_context_queue.remove (AC );
}

Public void onerror (asyncevent event) throws ioexception {
Weblogappender. async_context_queue.remove (AC );
}

Public void onstartasync (asyncevent event) throws ioexception {
}
});
Weblogappender. async_context_queue.add (AC );
}
}

The processing on the server end is almost over now. Let's look at the implementation of the client. In fact, when the client directly accesses this servlet, we can see that the browser continuously has log output, and the scroll bar on this page will continue, showing that the HTTP connection is not closed. In order to display, we also wrapped the client and read the information sent by weblogservlet through a hidden frame, which is implemented in both comet stream mode.

Listing 5: client page


<HTML>
<Head> <SCRIPT type = "text/JavaScript" src = "JS/jquery-1.4.min.js"> </SCRIPT>
<SCRIPT type = "text/JavaScript" src = "JS/application. js"> </SCRIPT>
<Style>
. Lelefont {font-size: 9; color: # dddddd; font-family: fixedsys}
. Inputstyle {font-size: 9; color :# dddddd; font-family: fixedsys; width: 100%;
Height: 100%; Border: 0; Background-color: #000000 ;}
</Style>
<Body style = "margin: 0; overflow: hidden">
<Table width = "100%" Height = "100%" border = "0" cellpadding = "0"
Cellspacing = "0" bgcolor = "#000000">
<Tr>
<TD colspan = "2"> <textarea name = "result" id = "result" readonly = "true" Wrap = "off"
Style = "padding: 10; overflow: Auto" class = "inputstyle"> </textarea> </TD>
</Tr>
</Table>
<IFRAME id = "Comet-frame" style = "display: none;"> </iframe>
</Body>
</Html>


Listing 6: application. js referenced by the client


$ (document ). ready (function () {
var url = '/asyncservlet/weblogservlet';
$ ('# comet-framework') [0]. src = URL;
});

function Update (data) {
var resultarea = $ ('# result ') [0];
resultarea. value = resultarea. value + Data + '\ n';
}

To simulate log output, we read an existing Log File and call logger to output the content to the browser. When debugging, the reader can directly run testservlet in the source package, the overall effect after running is as follows:

Figure 1. Running Effect

Conclusion
The emergence of comet brings a brand new experience to web interaction, while servlet 3.0 and asynchronous Io provide a standard solution for the problems occupied by web threads on the server side during the implementation of comet. With the emergence of various servlet 3.0 containers, comet applications will become more and more frequent. Currently, developing comet applications is still challenging. However, with the development of technology, I believe that the application of comet will become as popular as Ajax.

This article is transferred from www.35java.com 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.