• 《Spring技术内幕》学习笔记17——Spring HTTP调用器实现远程调用


    1.Spring中,HTTPInvoker(HTTP调用器)是通过基于HTTP协议的分布式远程调用解决方案,和java RMI一样,HTTP调用器也需要使用java的对象序列化机制完成客户端和服务器端的通信。HTTP调用器的远程调用工作原理如下:

    (1).客户端:

    a.向服务器发送远程调用请求:

    远程调用信息——>封装为远程调用对象——>序列化写入到远程调用HTTP请求中——>向服务器端发送。

    b.接收服务器端返回的远程调用结果:

    服务器端返回的远程调用结果HTTP响应——>反序列化为远程调用结果对象。

    (2).服务器端:

    a.接收客户端发送的远程调用请求:

    客户端发送的远程调用HTTP请求——>反序列化为远程调用对象——>调用服务器端目标对象的目标方法处理。

    b.向客户端返回远程调用结果:

    服务器端目标对象方法的处理结果——>序列化写入远程调用结果HTTP响应中——>返回给客户端。

    接下来我们将从客户端和服务器端分别分析HTTP调用器远程调用的具体实现。

    2.HTTP调用器客户端配置:

    使用HTTP调用器之前,首先需要对客户端其进行如下的配置:

     

    [xhtml] view plain copy
     
    1. <!--客户端HTTP调用器代理-->  
    2. <bean id=”proxy” class=”org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean”>  
    3. <property name=”serviceUrl”>  
    4. <value>http://yourhost:8080/远程调用URL</value>  
    5. </property>  
    6. <property name=”serviceInterface”>  
    7. <value>远程调用服务接口全路径</value>  
    8. </property>  
    9. </bean>  
    10. <bean id=”客户端bean” class=”客户端Bean全路径”>  
    11.         <property name=”remoteService”>  
    12.                 <ref bean=”proxy”/>  
    13.         </property>  
    14. </bean>  

     

    在HTTP调用器客户端代理HttpInvokerProxyFactoryBean中封装远程调用服务URL和服务接口,客户端程序通过HTTP调用代理可以调用实现了指定接口的目标服务端对象。

    3.HttpInvokerProxyFactoryBean创建远程调用代理对象:

    HTTP调用器客户端代理HttpInvokerProxyFactoryBean是一个实现了Spring FactoryBean接口的IoC容器,其作用是对远程服务客户端封装,源码如下:

     

    [java] view plain copy
     
    1. public class HttpInvokerProxyFactoryBean extends HttpInvokerClientInterceptor implements FactoryBean<Object> {  
    2.     //远程对象的代理  
    3.     private Object serviceProxy;  
    4.     //在IoC容器注入完成之后调用  
    5.     public void afterPropertiesSet() {  
    6.         //调用父类容器的回调方法  
    7.         super.afterPropertiesSet();  
    8. //getServiceInterface()方法用于获取配置的远程调用接口  
    9.         if (getServiceInterface() == null) {  
    10.             throw new IllegalArgumentException("Property 'serviceInterface' is required");  
    11.         }  
    12.         //使用ProxyFactory代理工厂生成远程代理对象,注意第二个参数this,因为  
    13.     //HttpInvokerProxyFactoryBean继承了HttpInvokerClientInterceptor,  
    14.         //所以代理对象的拦截器设置为HttpInvokerClientInterceptor  
    15.         this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader());  
    16.     }  
    17.     //向IoC容器索取被管理对象的方法,获取产生的远程调用代理对象  
    18.     public Object getObject() {  
    19.         return this.serviceProxy;  
    20.     }  
    21.     //获取对象类型,返回配置的远程调用接口  
    22.     public Class<?> getObjectType() {  
    23.         return getServiceInterface();  
    24.     }  
    25.     //是否是单态类型,默认Spring IoC容器产生的都是单态类型  
    26.     public boolean isSingleton() {  
    27.         return true;  
    28.     }  
    29. }  

     

    通过上面对HttpInvokerProxyFactoryBean源码的分析我们看到,当通过getObject方法向Spring IoC容器索取远程调用对象时,触发afterPropertiesSet回调方法,创建远程调用的代理对象,最后将该远程调用代理对象返回。在创建远程调用代理对象时,使用其父类HttpInvokerClientInterceptor作为远程调用代理对象的拦截器,该拦截器将拦截对代理对象的方法调用。下面我们分析HttpInvokerClientInterceptor代理拦截器对代理对象的方法拦截处理。

    4.HttpInvokerClientInterceptor拦截对远程调用代理的方法调用:

    当客户端通过HTTP请求调用远程调用代理的方法时,将会触发HttpInvokerClientInterceptor拦截器的invoke方法对当前的请求进行封装处理,将客户端的java对象序列化传输到服务器端,在远程服务器端执行完请求之后,又将处理结果java对象序列化返回给客户端。其源码如下:

     

    [java] view plain copy
     
    1. public class HttpInvokerClientInterceptor extends RemoteInvocationBasedAccessor  
    2.         implements MethodInterceptor, HttpInvokerClientConfiguration {  
    3.     private String codebaseUrl;  
    4.     //HTTP调用请求执行器  
    5.     private HttpInvokerRequestExecutor httpInvokerRequestExecutor;  
    6.     public void setCodebaseUrl(String codebaseUrl) {  
    7.         this.codebaseUrl = codebaseUrl;  
    8.     }  
    9.     public String getCodebaseUrl() {  
    10.         return this.codebaseUrl;  
    11.     }  
    12.     public void setHttpInvokerRequestExecutor(HttpInvokerRequestExecutor httpInvokerRequestExecutor) {  
    13.         this.httpInvokerRequestExecutor = httpInvokerRequestExecutor;  
    14.     }  
    15.     //获取HTTP调用请求执行器,如果HTTP调用请求执行器没有设置,则使用  
    16.     //SimpleHttpInvokerRequestExecutor作为HTTP调用请求执行器  
    17.     public HttpInvokerRequestExecutor getHttpInvokerRequestExecutor() {  
    18.         if (this.httpInvokerRequestExecutor == null) {  
    19.             SimpleHttpInvokerRequestExecutor executor = new SimpleHttpInvokerRequestExecutor();  
    20.             executor.setBeanClassLoader(getBeanClassLoader());  
    21.             this.httpInvokerRequestExecutor = executor;  
    22.         }  
    23.         return this.httpInvokerRequestExecutor;  
    24.     }  
    25.     //IoC容器初始化完成回调方法  
    26.     public void afterPropertiesSet() {  
    27.         //调用父类的初始化回调方法  
    28.         super.afterPropertiesSet();  
    29.         //获取HTTP调用请求执行器  
    30.         getHttpInvokerRequestExecutor();  
    31.     }  
    32. //拦截器代理对象方法调用入口,拦截器将客户端对远程调用代理的调用封装为  
    33. //MethodInvocation对象。  
    34.     public Object invoke(MethodInvocation methodInvocation) throws Throwable {  
    35.         if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {  
    36.             return "HTTP invoker proxy for service URL [" + getServiceUrl() + "]";  
    37.         }  
    38.         //创建远程调用对象,封装了远程调用  
    39.         RemoteInvocation invocation = createRemoteInvocation(methodInvocation);  
    40.         //远程调用结果  
    41.         RemoteInvocationResult result = null;  
    42.         try {  
    43.             //远程调用入口  
    44.             result = executeRequest(invocation, methodInvocation);  
    45.         }  
    46.         catch (Throwable ex) {  
    47.             throw convertHttpInvokerAccessException(ex);  
    48.         }  
    49.         try {  
    50.             //返回远程调用结果  
    51.             return recreateRemoteInvocationResult(result);  
    52.         }  
    53.         catch (Throwable ex) {  
    54.             if (result.hasInvocationTargetException()) {  
    55.                 throw ex;  
    56.             }  
    57.             else {  
    58.                 throw new RemoteInvocationFailureException("Invocation of method [" + methodInvocation.getMethod() +  
    59.                         "] failed in HTTP invoker remote service at [" + getServiceUrl() + "]", ex);  
    60.             }  
    61.         }  
    62.     }  
    63.     //执行远程调用入口  
    64.     protected RemoteInvocationResult executeRequest(  
    65.             RemoteInvocation invocation, MethodInvocation originalInvocation) throws Exception {  
    66.         return executeRequest(invocation);  
    67.     }  
    68.     //通过HTTP调用请求执行器执行远程调用  
    69.     protected RemoteInvocationResult executeRequest(RemoteInvocation invocation) throws Exception {  
    70.         return getHttpInvokerRequestExecutor().executeRequest(this, invocation);  
    71.     }  
    72.     //将远程调用异常转换成Spring异常  
    73.     protected RemoteAccessException convertHttpInvokerAccessException(Throwable ex) {  
    74.         if (ex instanceof ConnectException) {  
    75.             throw new RemoteConnectFailureException(  
    76.                     "Could not connect to HTTP invoker remote service at [" + getServiceUrl() + "]", ex);  
    77.         }  
    78.         else if (ex instanceof ClassNotFoundException || ex instanceof NoClassDefFoundError ||  
    79.                 ex instanceof InvalidClassException) {  
    80.             throw new RemoteAccessException(  
    81.                     "Could not deserialize result from HTTP invoker remote service [" + getServiceUrl() + "]", ex);  
    82.         }  
    83.         else {  
    84.             throw new RemoteAccessException(  
    85.                 "Could not access HTTP invoker remote service at [" + getServiceUrl() + "]", ex);  
    86.         }  
    87.     }  
    88. }  

     

    通过上面对HttpInvokerClientInterceptor拦截器的源码分析,我们可以看出,拦截器将客户端对远程调用的HTTP请求封装成了MethodInvocation对象,拦截器的在调用远程调用的代理对象时,又将方法调用封装成了RemoteInvocation远程调用,RemoteInvocation数据对象中封装了调用的具体信息,如方法名、方法参数以及参数类型等。

    真正执行远程调用的是HTTP调用请求执行器SimpleHttpInvokerRequestExecutor,下面我们继续分析SimpleHttpInvokerRequestExecutor远程调用的具体过程。

    5.SimpleHttpInvokerRequestExecutor远程调用:

    SimpleHttpInvokerRequestExecutor封装了基于HTTP协议的远程调用过程,具体源码如下:

     

    [java] view plain copy
     
    1. public class SimpleHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {  
    2. //HTTP调用请求执行器真正进行远程调用的方法,该方法有其父类//AbstractHttpInvokerRequestExecutor的executeRequest方法调用  
    3.     protected RemoteInvocationResult doExecuteRequest(  
    4.             HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)  
    5.             throws IOException, ClassNotFoundException {  
    6.         //打开一个标准的J2SE HttpURLConnection  
    7.         HttpURLConnection con = openConnection(config);  
    8.         //准备连接  
    9.         prepareConnection(con, baos.size());  
    10. //远程调用被封装成了RemoteInvocation对象,它通过序列化被写到对应的//HttpURLConnection中  
    11.         writeRequestBody(config, con, baos);  
    12.         //获取远程调用的结果,校验返回的结果  
    13.         validateResponse(config, con);  
    14.         InputStream responseBody = readResponseBody(config, con);  
    15.         //将远程调用结果转换成RemoteInvocationResult返回  
    16.         return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());  
    17.     }  
    18. //打开一个HttpURLConnection  
    19.     protected HttpURLConnection openConnection(HttpInvokerClientConfiguration config) throws IOException {  
    20.         //getServiceUrl()方法获取配置的远程调用URL,打开一个URL连接  
    21.         URLConnection con = new URL(config.getServiceUrl()).openConnection();  
    22.         if (!(con instanceof HttpURLConnection)) {  
    23.             throw new IOException("Service URL [" + config.getServiceUrl() + "] is not an HTTP URL");  
    24.         }  
    25.         return (HttpURLConnection) con;  
    26.     }  
    27.     //准备HTTP请求连接  
    28.     protected void prepareConnection(HttpURLConnection con, int contentLength) throws IOException {  
    29.         con.setDoOutput(true);  
    30.         //HTTP调用器只支持POST请求方法  
    31.         con.setRequestMethod(HTTP_METHOD_POST);  
    32.     //设置HTTP请求头内容类型,设置为:application/x-java-serialized-object  
    33.         con.setRequestProperty(HTTP_HEADER_CONTENT_TYPE, getContentType());  
    34.         //设置HTTP请求头内容长度  
    35.         con.setRequestProperty(HTTP_HEADER_CONTENT_LENGTH, Integer.toString(contentLength));  
    36.         LocaleContext locale = LocaleContextHolder.getLocaleContext();  
    37.         //设置HTTP请求的Locale  
    38.         if (locale != null) {  
    39.             con.setRequestProperty(HTTP_HEADER_ACCEPT_LANGUAGE, StringUtils.toLanguageTag(locale.getLocale()));  
    40.         }  
    41.         //设置HTTP请求压缩方式  
    42.         if (isAcceptGzipEncoding()) {  
    43.             con.setRequestProperty(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);  
    44.         }  
    45.     }  
    46. //把序列化对象输出到HTTP请求体中  
    47.     protected void writeRequestBody(  
    48.             HttpInvokerClientConfiguration config, HttpURLConnection con, ByteArrayOutputStream baos)  
    49.             throws IOException {  
    50.         baos.writeTo(con.getOutputStream());  
    51.     }  
    52. //校验远程调用的HTTP响应  
    53.     protected void validateResponse(HttpInvokerClientConfiguration config, HttpURLConnection con)  
    54.             throws IOException {  
    55.         //如果HTTP响应状态码大于等于300,则证明调用发生错误  
    56.         if (con.getResponseCode() >= 300) {  
    57.             throw new IOException(  
    58.                     "Did not receive successful HTTP response: status code = " + con.getResponseCode() +  
    59.                     ", status message = [" + con.getResponseMessage() + "]");  
    60.         }  
    61.     }  
    62.     //提取远程调用结果的HTTP响应信息  
    63.     protected InputStream readResponseBody(HttpInvokerClientConfiguration config, HttpURLConnection con)  
    64.             throws IOException {  
    65.         //如果响应信息是Gzip压缩的,则需要先解压  
    66.         if (isGzipResponse(con)) {  
    67.             return new GZIPInputStream(con.getInputStream());  
    68.         }  
    69.         //正常的HTTP响应  
    70.         else {  
    71.             return con.getInputStream();  
    72.         }  
    73.     }  
    74.     //是否是Gzip格式压缩  
    75.     protected boolean isGzipResponse(HttpURLConnection con) {  
    76.         //获取HTTP响应头信息中的压缩方式  
    77.         String encodingHeader = con.getHeaderField(HTTP_HEADER_CONTENT_ENCODING);  
    78.         return (encodingHeader != null && encodingHeader.toLowerCase().indexOf(ENCODING_GZIP) != -1);  
    79.     }  
    80. }  

     

    通过对SimpleHttpInvokerRequestExecutor的分析,我们看到,HTTP调用请求执行器的处理逻辑是:首先,打开指定URL的HTTP连接,设置连接属性。其次,将封装请求的RemoteInvocation对象序列化到请求体中,请HTTP请求发送到服务器端。最后,从服务器端的HTTP响应中读取输入流,并将响应结果转换成RemoteInvocationResult。

    将远程调用的HTTP响应转换为RemoteInvocationResult是由AbstractHttpInvokerRequestExecutor的readRemoteInvocationResult方法实现,下面我们将分析其将HTTP响应结果转换成RemoteInvocationResult的实现。

    6.AbstractHttpInvokerRequestExecutor其将HTTP响应结果转换成RemoteInvocationResult:

    AbstractHttpInvokerRequestExecutor中处理远程调用结果,并HTTP响应转换为RemoteInvocationResult的主要方法如下:

     

    [java] view plain copy
     
    1. //从HTTP响应中读取远程调用结果入口方法  
    2. protected RemoteInvocationResult readRemoteInvocationResult(InputStream is, String codebaseUrl)  
    3.             throws IOException, ClassNotFoundException {  
    4.         //根据给定的输入流和类创建对象输入流  
    5.         ObjectInputStream ois = createObjectInputStream(decorateInputStream(is), codebaseUrl);  
    6.         try {  
    7.             //从对象输入流中读取远程调用结果  
    8.             return doReadRemoteInvocationResult(ois);  
    9.         }  
    10.         finally {  
    11.             ois.close();  
    12.         }  
    13.     }  
    14. //从对象输入流中读取远程调用结果  
    15. protected RemoteInvocationResult doReadRemoteInvocationResult(ObjectInputStream ois)  
    16.             throws IOException, ClassNotFoundException {  
    17.         //获取对象输入流中的对象  
    18.         Object obj = ois.readObject();  
    19.         if (!(obj instanceof RemoteInvocationResult)) {  
    20.             throw new RemoteException("Deserialized object needs to be assignable to type [" +  
    21.                     RemoteInvocationResult.class.getName() + "]: " + obj);  
    22.         }  
    23.         //将获取到的对象封装为RemoteInvocationResult  
    24.         return (RemoteInvocationResult) obj;  
    25.     }  

     

    7.HTTP调用器的服务器端配置:

    和HTTP调用器客户端类似,服务器端也需要进行如下的配置:

     

    [xhtml] view plain copy
     
    1. <bean name=”/客户端配置的远程调用URL” class=”org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter”>  
    2. <property name=”service”>  
    3. <ref bean=”服务器端实现bean”/>  
    4. </property>  
    5. <property name=”serviceInterface”>  
    6. <value>远程调用服务接口全路径</value>  
    7. </property>  
    8. </property>  

     

    通过对服务器端配置的例子,我们可以看出,真正处理远程调用的服务器端实现是由service属性中指定的服务器端bean提供的,HttpInvokerServiceExporter将远程调用服务接口和服务实现类进行封装,主要提HTTP协议封装和java对象序列化功能。

    Spring的HttpInvokerServiceExporter是与Spring的MVC结合在一起的,它本质上是Spring MVC的一个Controller,客户端发来的远程调用HTTP请求有Spring MVC的中央控制器DispatcherServlet转发到指定URL的HttpInvokerServiceExporter上。

    8.HttpInvokerServiceExporter导出和执行远程调用服务:

    HttpInvokerServiceExporter响应客户端发送的远程调用HTTP请求,它从HTTP请求中读取远程调用并将其反序列化为RemoteInvocation对象,然后调用目标服务对象的目标方法完成远程调用服务,当服务执行完成之后,通过HTTP响应把执行结果对象序列化输出到客户端。器源码如下:

     

    [java] view plain copy
     
    1. public class HttpInvokerServiceExporter extends RemoteInvocationSerializingExporter implements HttpRequestHandler {  
    2.     //处理客户端发来的远程调用HTTP请求  
    3.     public void handleRequest(HttpServletRequest request, HttpServletResponse response)  
    4.             throws ServletException, IOException {  
    5.         try {  
    6.             //从HTTP请求中反序列化出RemoteInvocation远程调用对象  
    7.             RemoteInvocation invocation = readRemoteInvocation(request);  
    8.             //调用目标服务对象,完成远程调用请求,并创建调用结果  
    9.             RemoteInvocationResult result = invokeAndCreateResult(invocation, getProxy());  
    10.             //将调用结果写到HTTP响应中  
    11.             writeRemoteInvocationResult(request, response, result);  
    12.         }  
    13.         catch (ClassNotFoundException ex) {  
    14.             throw new NestedServletException("Class not found during deserialization", ex);  
    15.         }  
    16.     }  
    17.     //从HTTP请求中读取RemoteInvocation远程调用对象入口方法  
    18.     protected RemoteInvocation readRemoteInvocation(HttpServletRequest request) throws IOException, ClassNotFoundException {  
    19.         //将从HTTP请求中读取远程调用对象  
    20.         return readRemoteInvocation(request, request.getInputStream());  
    21.     }  
    22. //从HTTP请求中读取远程调用对象  
    23.     protected RemoteInvocation readRemoteInvocation(HttpServletRequest request, InputStream is) throws IOException, ClassNotFoundException {  
    24.         //根据HTTP请求输入流创建对象输入流  
    25.         ObjectInputStream ois = createObjectInputStream(decorateInputStream(request, is));  
    26.         try {  
    27.             //从对象输入流中读取远程调用对象  
    28.             return doReadRemoteInvocation(ois);  
    29.         }  
    30.         finally {  
    31.             ois.close();  
    32.         }  
    33.     }  
    34.     //获取HTTP请求输入流  
    35.     protected InputStream decorateInputStream(HttpServletRequest request, InputStream is) throws IOException {  
    36.         return is;  
    37.     }  
    38.     //将远程调用执行结果写到HTTP响应中  
    39.     protected void writeRemoteInvocationResult(  
    40.             HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result) throws IOException {  
    41.         //设置HTTP响应的内容类型为:application/x-java-serialized-object  
    42.         response.setContentType(getContentType());  
    43.         //将远程调用结果写到HTTP响应中  
    44.         writeRemoteInvocationResult(request, response, result, response.getOutputStream());  
    45.     }  
    46. //将远程调用执行结果写入HTTP响应中  
    47.     protected void writeRemoteInvocationResult(  
    48.             HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result, OutputStream os)  
    49.             throws IOException {  
    50.         //获取HTTP响应对象输出流  
    51.         ObjectOutputStream oos = createObjectOutputStream(decorateOutputStream(request, response, os));  
    52.         try {  
    53.             //将远程调用执行结果写到HTTP响应对象输出流中  
    54.             doWriteRemoteInvocationResult(result, oos);  
    55.         }  
    56.         finally {  
    57.             oos.close();  
    58.         }  
    59.     }  
    60.     //获取HTTP响应对象输入流  
    61.     protected OutputStream decorateOutputStream(  
    62.             HttpServletRequest request, HttpServletResponse response, OutputStream os) throws IOException {  
    63.         return os;  
    64.     }  
    65. }  

     

    通过对HttpInvokerServiceExporter的源码分析,我们可以看出,真正执行远程对象调用的是RemoteInvocationResultresult = invokeAndCreateResult(invocation, getProxy());它调用了RemoteInvocationBasedExporter的invokeAndCreateResult方法调用远程目标对象方法,并创建远程调用执行结果,下面我们继续分析执行服务器端远程调用目标对象方法的实现。

    9.RemoteInvocationBasedExporter调用服务器目标对象:

    RemoteInvocationBasedExporter的invokeAndCreateResult方法调用服务器目标对象方法,RemoteInvocationBasedExporter源码如下:

     

    [java] view plain copy
     
    1. public abstract class RemoteInvocationBasedExporter extends RemoteExporter {  
    2.     //远程调用执行器  
    3. private RemoteInvocationExecutor remoteInvocationExecutor = new DefaultRemoteInvocationExecutor();  
    4. public RemoteInvocationExecutor getRemoteInvocationExecutor() {  
    5.         return this.remoteInvocationExecutor;  
    6.     }  
    7. protected RemoteInvocationResult invokeAndCreateResult(RemoteInvocation invocation, Object targetObject) {  
    8.         try {  
    9.             //调用服务器端目标对象的方法  
    10.             Object value = invoke(invocation, targetObject);  
    11.             //根据执行结果创建RemoteInvocationResult  
    12.             return new RemoteInvocationResult(value);  
    13.         }  
    14.         catch (Throwable ex) {  
    15.             return new RemoteInvocationResult(ex);  
    16.         }  
    17.     }  
    18. //调用目标对象的方法  
    19. protected Object invoke(RemoteInvocation invocation, Object targetObject)  
    20. throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {  
    21.         if (logger.isTraceEnabled()) {  
    22.             logger.trace("Executing " + invocation);  
    23.         }  
    24.         try {  
    25.             //获取远程调用执行器,由远程调用执行器调用目标对象的方法,即通过  
    26.             //DefaultRemoteInvocationExecutor了调用目标对象的方法  
    27.             return getRemoteInvocationExecutor().invoke(invocation, targetObject);  
    28.         }  
    29.         catch (NoSuchMethodException ex) {  
    30.             if (logger.isDebugEnabled()) {  
    31.                 logger.warn("Could not find target method for " + invocation, ex);  
    32.             }  
    33.             throw ex;  
    34.         }  
    35.         catch (IllegalAccessException ex) {  
    36.             if (logger.isDebugEnabled()) {  
    37.                 logger.warn("Could not access target method for " + invocation, ex);  
    38.             }  
    39.             throw ex;  
    40.         }  
    41.         catch (InvocationTargetException ex) {  
    42.             if (logger.isDebugEnabled()) {  
    43.                 logger.debug("Target method failed for " + invocation, ex.getTargetException());  
    44.             }  
    45.             throw ex;  
    46.         }  
    47.     }   
    48. }  

     

    通过上面对RemoteInvocationBasedExporter源码分析我们看到,真正调用目标对象的是DefaultRemoteInvocationExecutor的invoke方法,下面我们继续分析DefaultRemoteInvocationExecutor调用目标对象方法的实现。

    10.DefaultRemoteInvocationExecutor调用目标对象的方法实现远程调用:

    DefaultRemoteInvocationExecutor用于调用目标对象的指定方法实现远程对象调用服务,其源码如下:

     

    [java] view plain copy
     
    1. public class DefaultRemoteInvocationExecutor implements RemoteInvocationExecutor {  
    2.     //调用目标对象的方法  
    3.     public Object invoke(RemoteInvocation invocation, Object targetObject)  
    4.             throws NoSuchMethodException, IllegalAccessException, InvocationTargetException{  
    5.         Assert.notNull(invocation, "RemoteInvocation must not be null");  
    6.         Assert.notNull(targetObject, "Target object must not be null");  
    7.         //调用RemoteInvocation的invoke方法  
    8.         return invocation.invoke(targetObject);  
    9.     }  
    10. }  
    11. RemoteInvocation的invoke方法源码如下:  
    12.     public Object invoke(Object targetObject)  
    13.             throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {  
    14.         //获取远程调用对象的方法名称和参数类型  
    15.         Method method = targetObject.getClass().getMethod(this.methodName, this.parameterTypes);  
    16.         //利用JDK反射机制,调用目标对象指定参数的方法  
    17.         return method.invoke(targetObject, this.arguments);  
    18.     }   
  • 相关阅读:
    node-red 使用 创建第一个流程
    node-red 安装
    docker postgres 导出导入数据
    6大设计模式(转)
    常见的算法
    @Autowired与@Resource的区别
    Elasticsearch
    redis搭建主从复用-读写分离
    转载redis持久化的几种方式
    后台启动mysql
  • 原文地址:https://www.cnblogs.com/exmyth/p/5156053.html
Copyright © 2020-2023  润新知