spring remoting源码分析--Hessian分析
1. Caucho
1.1 概況
spring-remoting代碼的情況如下:
本節(jié)近分析caucho模塊。
1.2 分類
其中以hession為例,Hessian遠程服務(wù)調(diào)用過程:
?
Hessian遠程服務(wù)調(diào)用過程
1.2.1 客戶端
BurlapProxyFactoryBean,BurlapClientInterceptor;
HessianProxyFactoryBean,HessianClientInterceptor;
HessianProxyFactoryBean繼承自HessianClientInterceptor,間接封裝了HessianProxyFactory。HessianProxyFactory是hessian的client實現(xiàn)類,
示例:
public interface Basic {public String hello(); }import com.caucho.hessian.client.HessianProxyFactory;public class BasicClient {public static void main(String []args)throws Exception{String url = "http://www.caucho.com/hessian/test/basic";HessianProxyFactory factory = new HessianProxyFactory(); Basic basic = (Basic) factory.create(Basic.class, url);System.out.println("Hello: " + basic.hello());} }?create方法如下:
/*** Creates a new proxy with the specified URL. The returned object* is a proxy with the interface specified by api.** <pre>* String url = "http://localhost:8080/ejb/hello");* HelloHome hello = (HelloHome) factory.create(HelloHome.class, url);* </pre>** @param api the interface the proxy class needs to implement* @param url the URL where the client object is located.** @return a proxy to the object with the specified interface.*/public Object create(Class<?> api, URL url, ClassLoader loader){if (api == null)throw new NullPointerException("api must not be null for HessianProxyFactory.create()");InvocationHandler handler = null; handler = new HessianProxy(url, this, api);return Proxy.newProxyInstance(loader,new Class[] { api,HessianRemoteObject.class },handler);}其中HessianProxy實現(xiàn)了java的動態(tài)代理
/*** Proxy implementation for Hessian clients. Applications will generally* use HessianProxyFactory to create proxy clients.*/ public class HessianProxy implements InvocationHandler, Serializable {private static final Logger log= Logger.getLogger(HessianProxy.class.getName());protected HessianProxyFactory _factory;private WeakHashMap<Method,String> _mangleMap= new WeakHashMap<Method,String>();private Class<?> _type;private URL _url;/*** Protected constructor for subclassing*/protected HessianProxy(URL url, HessianProxyFactory factory){this(url, factory, null);}/*** Protected constructor for subclassing*/protected HessianProxy(URL url,HessianProxyFactory factory, Class<?> type){_factory = factory;_url = url;_type = type;} }?最重要的invoke方法如下:
/*** Handles the object invocation.** @param proxy the proxy object to invoke* @param method the method to call* @param args the arguments to the proxy object*/public Object invoke(Object proxy, Method method, Object []args)throws Throwable{String mangleName;synchronized (_mangleMap) {mangleName = _mangleMap.get(method);}if (mangleName == null) {String methodName = method.getName();Class<?> []params = method.getParameterTypes();// equals and hashCode are special casedif (methodName.equals("equals")&& params.length == 1 && params[0].equals(Object.class)) {Object value = args[0];if (value == null || ! Proxy.isProxyClass(value.getClass()))return Boolean.FALSE;Object proxyHandler = Proxy.getInvocationHandler(value);if (! (proxyHandler instanceof HessianProxy))return Boolean.FALSE;HessianProxy handler = (HessianProxy) proxyHandler;return new Boolean(_url.equals(handler.getURL()));}else if (methodName.equals("hashCode") && params.length == 0)return new Integer(_url.hashCode());else if (methodName.equals("getHessianType"))return proxy.getClass().getInterfaces()[0].getName();else if (methodName.equals("getHessianURL"))return _url.toString();else if (methodName.equals("toString") && params.length == 0)return "HessianProxy[" + _url + "]";if (! _factory.isOverloadEnabled())mangleName = method.getName();elsemangleName = mangleName(method);synchronized (_mangleMap) {_mangleMap.put(method, mangleName);}}InputStream is = null;HessianConnection conn = null;try {if (log.isLoggable(Level.FINER))log.finer("Hessian[" + _url + "] calling " + mangleName); conn = sendRequest(mangleName, args);is = getInputStream(conn);if (log.isLoggable(Level.FINEST)) {PrintWriter dbg = new PrintWriter(new LogWriter(log));HessianDebugInputStream dIs= new HessianDebugInputStream(is, dbg);dIs.startTop2();is = dIs;}AbstractHessianInput in;int code = is.read();if (code == 'H') {int major = is.read();int minor = is.read();in = _factory.getHessian2Input(is);Object value = in.readReply(method.getReturnType());return value;}else if (code == 'r') {int major = is.read();int minor = is.read();in = _factory.getHessianInput(is);in.startReplyBody();Object value = in.readObject(method.getReturnType());if (value instanceof InputStream) {value = new ResultInputStream(conn, is, in, (InputStream) value);is = null;conn = null;}elsein.completeReply();return value;}elsethrow new HessianProtocolException("'" + (char) code + "' is an unknown code");} catch (HessianProtocolException e) {throw new HessianRuntimeException(e);} finally {try {if (is != null)is.close();} catch (Exception e) {log.log(Level.FINE, e.toString(), e);}try {if (conn != null)conn.destroy();} catch (Exception e) {log.log(Level.FINE, e.toString(), e);}}}發(fā)送http請求
/*** Sends the HTTP request to the Hessian connection.*/protected HessianConnection sendRequest(String methodName, Object []args)throws IOException{HessianConnection conn = null;conn = _factory.getConnectionFactory().open(_url);boolean isValid = false;try {addRequestHeaders(conn);OutputStream os = null;try {os = conn.getOutputStream();} catch (Exception e) {throw new HessianRuntimeException(e);}if (log.isLoggable(Level.FINEST)) {PrintWriter dbg = new PrintWriter(new LogWriter(log));HessianDebugOutputStream dOs = new HessianDebugOutputStream(os, dbg);dOs.startTop2();os = dOs;}AbstractHessianOutput out = _factory.getHessianOutput(os);out.call(methodName, args);out.flush();conn.sendRequest();isValid = true;return conn;} finally {if (! isValid && conn != null)conn.destroy();}}創(chuàng)建http連接代碼
/*** Opens a new or recycled connection to the HTTP server.*/public HessianConnection open(URL url)throws IOException{if (log.isLoggable(Level.FINER))log.finer(this + " open(" + url + ")");URLConnection conn = url.openConnection();// HttpURLConnection httpConn = (HttpURLConnection) conn;// httpConn.setRequestMethod("POST");// conn.setDoInput(true);long connectTimeout = _proxyFactory.getConnectTimeout();if (connectTimeout >= 0)conn.setConnectTimeout((int) connectTimeout);conn.setDoOutput(true);long readTimeout = _proxyFactory.getReadTimeout();if (readTimeout > 0) {try {conn.setReadTimeout((int) readTimeout);} catch (Throwable e) {}}?
1.2.2 服務(wù)器端
HessianExporter及其實現(xiàn)類HessianServiceExporter,SimpleHessianServiceExporter.
?hessian服務(wù)端示例
package hessian.test;import com.caucho.hessian.server.HessianServlet;public class BasicService extends HessianServlet implements Basic {public String hello(){return "Hello, world";} }?我們來看一下:
HessianServiceExporter
/*** Servlet-API-based HTTP request handler that exports the specified service bean* as Hessian service endpoint, accessible via a Hessian proxy.** <p><b>Note:</b> Spring also provides an alternative version of this exporter,* for Sun's JRE 1.6 HTTP server: {@link SimpleHessianServiceExporter}.** <p>Hessian is a slim, binary RPC protocol.* For information on Hessian, see the* <a href="http://www.caucho.com/hessian">Hessian website</a>.* <b>Note: As of Spring 4.0, this exporter requires Hessian 4.0 or above.</b>** <p>Hessian services exported with this class can be accessed by* any Hessian client, as there isn't any special handling involved.** @author Juergen Hoeller* @since 13.05.2003* @see HessianClientInterceptor* @see HessianProxyFactoryBean* @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter* @see org.springframework.remoting.rmi.RmiServiceExporter*/處理客戶端請求的方法:
/*** Processes the incoming Hessian request and creates a Hessian response.*/@Overridepublic void handleRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {if (!"POST".equals(request.getMethod())) {throw new HttpRequestMethodNotSupportedException(request.getMethod(),new String[] {"POST"}, "HessianServiceExporter only supports POST requests"); } response.setContentType(CONTENT_TYPE_HESSIAN); try { invoke(request.getInputStream(), response.getOutputStream()); } catch (Throwable ex) { throw new NestedServletException("Hessian skeleton invocation failed", ex); } }invoke調(diào)用
/*** Actually invoke the skeleton with the given streams.* @param skeleton the skeleton to invoke* @param inputStream the request stream* @param outputStream the response stream* @throws Throwable if invocation failed*/protected void doInvoke(HessianSkeleton skeleton, InputStream inputStream, OutputStream outputStream)throws Throwable {ClassLoader originalClassLoader = overrideThreadContextClassLoader();try {InputStream isToUse = inputStream;OutputStream osToUse = outputStream; if (this.debugLogger != null && this.debugLogger.isDebugEnabled()) { PrintWriter debugWriter = new PrintWriter(new CommonsLogWriter(this.debugLogger)); @SuppressWarnings("resource") HessianDebugInputStream dis = new HessianDebugInputStream(inputStream, debugWriter); @SuppressWarnings("resource") HessianDebugOutputStream dos = new HessianDebugOutputStream(outputStream, debugWriter); dis.startTop2(); dos.startTop2(); isToUse = dis; osToUse = dos; } if (!isToUse.markSupported()) { isToUse = new BufferedInputStream(isToUse); isToUse.mark(1); } int code = isToUse.read(); int major; int minor; AbstractHessianInput in; AbstractHessianOutput out; if (code == 'H') { // Hessian 2.0 stream major = isToUse.read(); minor = isToUse.read(); if (major != 0x02) { throw new IOException("Version " + major + "." + minor + " is not understood"); } in = new Hessian2Input(isToUse); out = new Hessian2Output(osToUse); in.readCall(); } else if (code == 'C') { // Hessian 2.0 call... for some reason not handled in HessianServlet! isToUse.reset(); in = new Hessian2Input(isToUse); out = new Hessian2Output(osToUse); in.readCall(); } else if (code == 'c') { // Hessian 1.0 call major = isToUse.read(); minor = isToUse.read(); in = new HessianInput(isToUse); if (major >= 2) { out = new Hessian2Output(osToUse); } else { out = new HessianOutput(osToUse); } } else { throw new IOException("Expected 'H'/'C' (Hessian 2.0) or 'c' (Hessian 1.0) in hessian input at " + code); } if (this.serializerFactory != null) { in.setSerializerFactory(this.serializerFactory); out.setSerializerFactory(this.serializerFactory); } if (this.remoteResolver != null) { in.setRemoteResolver(this.remoteResolver); } try { skeleton.invoke(in, out); } finally { try { in.close(); isToUse.close(); } catch (IOException ex) { // ignore } try { out.close(); osToUse.close(); } catch (IOException ex) { // ignore } } } finally { resetThreadContextClassLoader(originalClassLoader); } }調(diào)用skeleton的invoke方法
/*** Invoke the object with the request from the input stream.** @param in the Hessian input stream* @param out the Hessian output stream*/public void invoke(Object service,AbstractHessianInput in,AbstractHessianOutput out)throws Exception{ServiceContext context = ServiceContext.getContext();// backward compatibility for some frameworks that don't read// the call type firstin.skipOptionalCall();// Hessian 1.0 backward compatibilityString header;while ((header = in.readHeader()) != null) { Object value = in.readObject(); context.addHeader(header, value); } String methodName = in.readMethod(); int argLength = in.readMethodArgLength(); Method method; method = getMethod(methodName + "__" + argLength); if (method == null) method = getMethod(methodName); if (method != null) { } else if ("_hessian_getAttribute".equals(methodName)) { String attrName = in.readString(); in.completeCall(); String value = null; if ("java.api.class".equals(attrName)) value = getAPIClassName(); else if ("java.home.class".equals(attrName)) value = getHomeClassName(); else if ("java.object.class".equals(attrName)) value = getObjectClassName(); out.writeReply(value); out.close(); return; } else if (method == null) { out.writeFault("NoSuchMethodException", escapeMessage("The service has no method named: " + in.getMethod()), null); out.close(); return; } Class<?> []args = method.getParameterTypes(); if (argLength != args.length && argLength >= 0) { out.writeFault("NoSuchMethod", escapeMessage("method " + method + " argument length mismatch, received length=" + argLength), null); out.close(); return; } Object []values = new Object[args.length]; for (int i = 0; i < args.length; i++) { // XXX: needs Marshal object values[i] = in.readObject(args[i]); } Object result = null; try { result = method.invoke(service, values); } catch (Exception e) { Throwable e1 = e; if (e1 instanceof InvocationTargetException) e1 = ((InvocationTargetException) e).getTargetException(); log.log(Level.FINE, this + " " + e1.toString(), e1); out.writeFault("ServiceException", escapeMessage(e1.getMessage()), e1); out.close(); return; } // The complete call needs to be after the invoke to handle a // trailing InputStream in.completeCall(); out.writeReply(result); out.close(); }反射觸發(fā)類的方法。
?
BurlapExporter及其實現(xiàn)類BurlapServiceExporter,SimpleBurlapServiceExporter,因已經(jīng)depressed,故略。
1.3 小結(jié)
Spring封裝了hessian客戶端和服務(wù)端的通用代碼,把實現(xiàn)者和調(diào)用者作為bean放到spring容器中管理,簡化了開發(fā)。分析源碼的過程中,發(fā)現(xiàn)在客戶端使用了動態(tài)代理,在服務(wù)端使用反射,讓我們加深了對java基礎(chǔ)知識的理解。
?
轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/p/5496933.html
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的spring remoting源码分析--Hessian分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 好技术领导和差技术领导区别在哪里--转
- 下一篇: Kubernetes系统架构简介--转