日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringHttpInvoker解析2-服务端实现

發布時間:2025/3/15 javascript 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringHttpInvoker解析2-服务端实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

主要的配置文件

<!-- 在Spring的httpInvoker服務 --> <bean id="httpInvokerUserService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter"> <!--需要發布的實現類 --> <property name="service" ref="userServiceHttpInvoker" /> <property name="serviceInterface" value="com.gosun.jws.httpinvoker.UserService" /> </bean> <bean id="userServiceHttpInvoker" class="com.gosun.jws.httpinvoker.UserServiceImpl" />

我們分析入口類應該為HttpInvokerServiceExporter,RemoteInvocationSerializingExporter類實現了接口InitializingBean接口,本類實現了HttpRequestHandler接口。當某個bean繼承自InitializingBean接口的時候,Spring會確保這個bean在初始化時調用其afterPropertiesSet方法,而對于HttpRequestHandler接口,因為我們在配置中已經將此接口配置成Web服務,那么當有相應請求的時候,Spring的Web服務就會將程序引導至HttpRequestHandler的handlerRequest方法中。首先我們從afterPropertiesSet方法開始分析,看看在bean的初始化過程中做了那些邏輯。

public class HttpInvokerServiceExporter extends RemoteInvocationSerializingExporter implements HttpRequestHandler

創建代理

public void afterPropertiesSet() { prepare(); } public void prepare() { proxy = getProxyForService(); } protected Object getProxyForService() { //驗證service checkService(); //驗證serviceInterface checkServiceInterface(); //使用JDK的方式創建代理 ProxyFactory proxyFactory = new ProxyFactory(); //添加代理接口 proxyFactory.addInterface(getServiceInterface()); if(registerTraceInterceptor == null ? interceptors == null : registerTraceInterceptor.booleanValue()) proxyFactory.addAdvice(new RemoteInvocationTraceInterceptor(getExporterName())); if(interceptors != null) { AdvisorAdapterRegistry adapterRegistry = GlobalAdvisorAdapterRegistry.getInstance(); for(int i = 0; i < interceptors.length; i++) //加入代理的橫切面RemoteInvocationTraceInterceptor并記錄Exporter名稱 proxyFactory.addAdvisor(adapterRegistry.wrap(interceptors[i])); } //設置要代理的目標類 proxyFactory.setTarget(getService()); proxyFactory.setOpaque(true); //創建代理 return proxyFactory.getProxy(getBeanClassLoader()); }

可以看到,初始化過程中實現的邏輯主要是創建了一個代理,代理中封裝了對于特定請求的處理方法以及接口等信息,而這個代理的最關鍵目的是加入了RemoteInvocationTraceInterceptor增強器,當然創建代理還有些其他好處,比如代碼優雅,方便擴展等。RemoteInvocationTraceInterceptor中的增強主要是對增強的目標方法進行一些相關信息的日志打印,并沒有在此基礎上進行任何功能性的增強

處理來自客戶端的request

當有web請求時,根據配置中的規則會把路徑匹配的訪問直接引入對應的HttpRequestHandler中。

public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { //從request中讀取序列化對象 RemoteInvocation invocation = readRemoteInvocation(request); //執行調用 RemoteInvocationResult result = invokeAndCreateResult(invocation, getProxy()); //將結果的序列化對象寫入輸出流 writeRemoteInvocationResult(request, response, result); } catch(ClassNotFoundException ex) { throw new NestedServletException("Class not found during deserialization", ex); } }

在handlerRequest函數中,很清楚地看到了HttpInvoker處理的大致框架,HttpInvoker服務簡單點說就是將請求的方法,也就是RemoteInvocation對象,從客戶端序列化并通過Web請求出入服務端,服務端在對傳過來的序列化對象進行反序列化還原RemoteInvocation實例,然后通過實例中的相關信息進行相關方法的調用,并將執行結果再次的返回給客戶端。從handlerRequest函數中我們也可以清晰地看到程序執行的框架結構。

從request中讀取序列化對象

主要是從HttpServletRequest提取相關的信息,也就是提取HttpServletRequest中的RemoteInvocation對象的序列化信息以及反序列化的過程。

  protected RemoteInvocation readRemoteInvocation(HttpServletRequest request) throws IOException, ClassNotFoundException { return readRemoteInvocation(request, ((InputStream) (request.getInputStream()))); } protected RemoteInvocation readRemoteInvocation(HttpServletRequest request, InputStream is)throws IOException, ClassNotFoundException {ObjectInputStream ois = createObjectInputStream(decorateInputStream(request, is));try {return doReadRemoteInvocation(ois);}finally {ois.close();}}protected RemoteInvocation doReadRemoteInvocation(ObjectInputStream ois)throws IOException, ClassNotFoundException {Object obj = ois.readObject();if (!(obj instanceof RemoteInvocation)) {throw new RemoteException("Deserialized object needs to be assignable to type [" +RemoteInvocation.class.getName() + "]: " + obj);}return (RemoteInvocation) obj;}

這里完全是按照標準的方式進行操作,包括創建ObjectInputStream以及從ObjectInputStream中提取對象實例。

執行調用

根據反序列化方式得到的RemoteInvocation對象中的信息進行方法調用。注意,此時調用的實體并不是服務接口或者服務類,而是之前在初始化的時候構造的封裝了服務接口以及服務類的代理。完成了RemoteInvocation實例的提取,也就意味著可以通過RemoteInvocation實例中提供的信息進行方法調用了。

protected RemoteInvocationResult invokeAndCreateResult(RemoteInvocation invocation, Object targetObject) { try { //激活代理類中對應invacation中的方法 Object value = invoke(invocation, targetObject); //封裝結果以便于序列化 return new RemoteInvocationResult(value); } catch(Throwable ex) { return new RemoteInvocationResult(ex); } }

對應方法的激活也就是invoke方法的調用,雖然經過層層環繞,但是最終還是實現了一個我們熟知的調用invocation.invoke(targetObject),也就是執行RemoteInvocation類中的invoke方法,大致的邏輯還是通過RemoteInvocation中對應的方法信息在targetObject上去執行,此方法在分析RMI功能的時候已經分析過。但是在對于當前方法的targetObject參數,此targetObject是代理類,調用代理類的時候需要考慮增強方法的調用

對于返回結果需要使用RemoteInvocationResult進行封裝,之所以需要通過使用RemoteInvocationResult類進行封裝,是因為無法保證對于所有操作的返回結果都繼承Serializable接口,也就是說無法保證所有返回結果都可以直接進行序列化。那么,就必須使用RemoteInvocationResult類進行統一封裝。

將結果的序列化對象寫入輸出流

protected void writeRemoteInvocationResult(HttpServletRequest request, HttpServletResponse response,
         RemoteInvocationResult result)
throws IOException { response.setContentType(getContentType()); writeRemoteInvocationResult(request, response, result, ((OutputStream) (response.getOutputStream()))); } protected void writeRemoteInvocationResult(HttpServletRequest request, HttpServletResponse response,
         RemoteInvocationResult result, OutputStream os)
throws IOException { //獲取輸出流 ObjectOutputStream oos = createObjectOutputStream(decorateOutputStream(request, response, os)); try{ //將序列化對象寫入輸出流 doWriteRemoteInvocationResult(result, oos); }finally{ oos.close(); } } protected void doWriteRemoteInvocationResult(RemoteInvocationResult result, ObjectOutputStream oos) throws IOException { oos.writeObject(result); }

?

總結

以上是生活随笔為你收集整理的SpringHttpInvoker解析2-服务端实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。