Java Servlet 3.0有了异步特性,这使得服务器端可以推后处理某些请求。 Ajax可以使得客户端post部分请求,并接受异步回调。 websocket可以使得客户端与服务器进行全双工的通讯,客户端接受ServerPush信息很容易。 1. use servlet3.0 async feature 1.1 服务器端代码(异步Servlet) servletpath:/AsyncPath - in server side @WebServlet(urlPatterns={"/AsyncPath"},asyncSupported=true) public class AsyncServlet extends HttpServlet 1.2. access the async url on web browser chrome - in client side (在浏览器输�%Fspan> result.add(ServerEndpointConfig.Builder.create(EchoEndpoint.class, "/websocket/echoProgrammatic").build()); } if (scanned.contains(EchoEndpoint.class)) { result.add(ServerEndpointConfig.Builder.create(EchoEndpointAsync.class, "/websocket/echoProgrammaticAsync").build()); } return result; } @Override public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) { // Deploy all WebSocket endpoints defined by annotations in the examples // web application. Filter out all others to avoid issues when running // tests on Gump Set<Class<?>> results = new HashSet<Class<?>>(); for (Class<?> clazz : scanned) { if (clazz.getPackage().getName().startsWith("websocket.")) { results.add(clazz); } } return results; } } 2.2 EchoEndpointAsync package websocket.echo; import java.io.IOException; import java.nio.ByteBuffer; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import javax.websocket.Endpoint; import javax.websocket.EndpointConfig; import javax.websocket.MessageHandler; import javax.websocket.Rem5�http://localhost:8080/SMPUI/AsyncPath?name=tony&age=42&delay=4,然后敲回车) Async servlet starts:Mon Feb 29 14:20:01 CST 2016 </br> OK </br> Async servlet ends :Mon Feb 29 14:20:01 CST 2016 </br> </br> Event 1 started...Mon Feb 29 14:20:01 CST 2016</br> Event 2 started...Mon Feb 29 14:20:06 CST 2016</br> Event 3 started...Mon Feb 29 14:20:06 CST 2016</br> 浏览器的忙碌图标还是至少5秒以上。 2. use servlet traditional feature (sync) in server side 2.1 服务器端代码(同步Servlet) servletpath:/SyncPath -in server side @WebServlet("/SyncPath") 2.2 access the async url on web browser chrome - in client side (在浏览器输入http://localhost:8080/SMPUI/AsyncPath?name=tony&age=42&delay=4,然后敲回车) Sync servlet starts:Mon Feb 29 16:38:23 CST 2016 </br> Event 1 started...Mon Feb 29 16:38:23 CST 2016</br> Event 2 started...Mon Feb 29 16:38:27 CST 2016</br> Event 3 started...Mon Feb 29 16:38:27 CST 2016</br> OK </br> Sync servlet ends :Mon Feb 29 16:38:27 CST 2016 </br> </br> 浏览器的忙碌图标还是至少5秒以上。 由1,2可总结: 这种异步带来的好处是在服务器端的,对客户端纯浏览器(无Ajax)操作并无改善。 异步的好处是:服务器异步工作。可以先缓存大量请求,然后业务逻辑的处理可以延迟进行。 缺点是:客户端仍是阻塞式等待。 在同步环境下,service(HttpServletRequest request, HttpServletResponse response) 执行完成(出了这个方法)后,其request, response 不能再使用。 在异步环境下,service(HttpServletRequest request, HttpServletResponse response) 执行完成后,在另外的线程中仍可以使用asyncontext得到response来向客户端写。这就是本质区别。 3. Use Ajax in client (Web browser) (在浏览器输入http://localhost:8080/SMPUI/AsyncPath回车后,点击Submit按钮) var xhttp = new XMLHttpRequest(); var url="http://localhost:8080/SMPUI/AsyncPath"; xhttp.open("GET", url, true); //true = ajax xhttp.send(); 点击Submit按钮后看到的结果: Async servlet starts:Tue Mar 01 17:00:27 CST 2016 OK Async servlet ends :Tue Mar 01 17:00:27 CST 2016 Event 1 started...Tue Mar 01 17:00:27 CST 2016 Event 2 started...Tue Mar 01 17:00:37 CST 2016 Event 3 started...Tue Mar 01 17:00:37 CST 2016 浏览器图标不再忙碌 由3总结: 浏览器异步发送方和接收结果,导致浏览器忙碌图标不再是不停转动10秒后再显示,而是很平静的过一会(10秒)把服务器延迟产生的数据也显示出来。 服务器端仍然是异步工作。 好处是:客户端不再阻塞式等待结果,而是利用回调函数处理服务器发来的数据。 缺点是:还是靠拉的方式。 不是服务器主动推的方式。[客户端主动发一次请求服务器才有响应,客户端不发请求服务器没有响应,客户端发几次请求服务器有几次响应] 即使客户端做成轮询的方式[每隔几秒发一次请求],运行若干(10-20)分钟后浏览器页面会崩溃,显然不是可接受的方式。 4. Use WebSocket 实现全双工通信。每次客户端发的请求都有回应,同时客户端还可以接受服务器推的信息。 1.客户端:echoAsync.xhtml <?xml version="1.0" encoding="UTF-8"?> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <title>Tomcat WebSocket Async Examples: Echo</title> <style type="text/css"><![CDATA[ #connect-container { float: left; width: 400px } #connect-container div { padding: 5px; } #console-container { float: left; margin-left: 15px; width: 400px; } #console { border: 1px solid #CCCCCC; border-right-color: #999999; border-bottom-color: #999999; height: 170px; overflow-y: scroll; padding: 5px; width: 100%; } #console p { padding: 0; margin: 0; } ]]></style> <script type="application/javascript"><![CDATA[ var ws = null; function setConnected(connected) { document.getElementById('connect').disabled = connected; document.getElementById('disconnect').disabled = !connected; document.getElementById('echo').disabled = !connected; } function connect() { var target = document.getElementById('target').value; if (target == '') { alert('Please select server side connection implementation.'); return; } if ('WebSocket' in window) { ws = new WebSocket(target); } else if ('MozWebSocket' in window) { ws = new MozWebSocket(target); } else { alert('WebSocket is not supported by this browser.'); return; } ws.onopen = function () { setConnected(true); log('Info: WebSocket connection opened.'); }; ws.onmessage = function (event) { log('Received: ' + event.data); }; ws.onclose = function (event) { setConnected(false); log('Info: WebSocket connection closed, Code: ' + event.code + (event.reason == "" ? "" : ", Reason: " + event.reason)); }; } function disconnect() { if (ws != null) { ws.close(); ws = null; } setConnected(false); } function echo() { if (ws != null) { var message = document.getElementById('message').value; log('Sent: ' + message); ws.send(message); } else { alert('WebSocket connection not established, please connect.'); oteEndpoint; } function updateTarget(target) { if (window.location.protocol == 'http:') { document.getElementById('target').value = 'ws://' + window.location.host + target; } else { document.getElementById('target').value = 'wss://' + window.location.host + target; } } function log(message) { var console = document.getElementById('console'); var p = document.createElement('p'); p.style.wordWrap = 'break-word'; p.appendChild(document.createTextNode(message)); console.appendChild(p); while (console.childNodes.length > 25) { console.removeChild(console.firstChild); } console.scrollTop = console.scrollHeight; } document.addEventListener("DOMContentLoaded", function() { // Remove elements with "noscript" class - <noscript> is not allowed in XHTML var noscripts = document.getElementsByClassName("noscript"); for (var i = 0; i < noscripts.length; i++) { noscripts[i].parentNode.removeChild(noscripts[i]); } }, false); ]]></script> </head> <body> <div class="noscript"><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable Javascript and reload this page!</h2></div> <div> <div id="connect-container"> <div> <span>Connect to service implemented using:</span> <!-- echo example using new programmatic API on the server side --> <input id="radio1" type="radio" name="group1" value="/SMPUI/websocket/echoProgrammaticAsync" οnclick="updateTarget(this.value);"/> <label for="radio1">programmatic API</label> <!-- echo example using new annotation API on the server side --> <input id="radio2" type="radio" name="group1" value="/SMPUI/websocket/echoAnnotation" οnclick="updateTarget(this.value);"/> <label for="radio2">annotation API</label> </div> <div> <input id="target" type="text" size="40" style="width: 350px"/> </div> <div> <button id="connect" onclick="connect();">Connect</button> <button id="disconnect" disabled="disabled" onclick="disconnect();">Disconnect</button> </div> <div> <textarea id="message" style="width: 350px">Here is a message!</textarea> </div> <div> <button id="echo" onclick="echo();" disabled="disabled">Echo message</button> </div> </div> <div id="console-container"> <div id="console"/> </div> </div> </body> </html> 2.服务器端: 2.1 ExamplesConfig package websocket; import java.util.HashSet; import java.util.Set; import javax.websocket.Endpoint; import javax.websocket.server.ServerApplicationConfig; import javax.websocket.server.ServerEndpointConfig; import websocket.echo.EchoEndpoint; import websocket.echo.EchoEndpointAsync; public class ExamplesConfig implements ServerApplicationConfig { @Override public Set<ServerEndpointConfig> getEndpointConfigs( Set<Class<? extends Endpoint>> scanned) { Set<ServerEndpointConfig> result = new HashSet<ServerEndpointConfig>(); if (scanned.contains(EchoEndpoint.class)) {
Servlet3异步特性+Ajax+Websocket
最新推荐文章于 2023-06-16 14:07:14 发布