读书人

Spring技术黑幕深入解析Spring架构

发布时间: 2012-11-10 10:48:50 作者: rapoo

Spring技术内幕——深入解析Spring架构与设计原理(五)Spring与远端调用
?Spring技术黑幕——深入解析Spring架构与设计原理(五)Spring与远端调用Spring技术黑幕——深入解析Spring架构与设计原理(五)Spring与远端调用

    public class HttpInvokerProxyFactoryBean extends HttpInvokerClientInterceptorimplements FactoryBean<Object> {//这是远端对象的代理private Object serviceProxy;@Override//在注入完成之后,设置远端对象代理public void afterPropertiesSet() {super.afterPropertiesSet();//需要配置远端调用的接口if (getServiceInterface() == null) {throw new IllegalArgumentException("Property 'serviceInterface' is required");}//这里使用ProxyFactory来生成远端代理对象,注意这个this,因为HttpInvokerProxyFactoryBean的基类是HttpInvokerClientInterceptor,所以代理类的拦截器被设置为HttpInvokerClientInterceptorthis.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader());}//FactoryBean生产对象的入口。返回的是serviceProxy对象,这是一个代理对象public Object getObject() {return this.serviceProxy;}public Class<?> getObjectType() {return getServiceInterface();}public boolean isSingleton() {return true;}?Spring技术黑幕——深入解析Spring架构与设计原理(五)Spring与远端调用Spring技术黑幕——深入解析Spring架构与设计原理(五)Spring与远端调用
      //对代理对象的方法调用入口public Object invoke(MethodInvocation methodInvocation) throws Throwable {if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {return "HTTP invoker proxy for service URL [" + getServiceUrl() + "]";}//创建RemoteInvocation对象,这个对象封装了对远端的调用,这些远端调用通过序列化的机制完成RemoteInvocation invocation = createRemoteInvocation(methodInvocation);RemoteInvocationResult result = null;try {//这里是对远端调用的入口result = executeRequest(invocation, methodInvocation);}catch (Throwable ex) {throw convertHttpInvokerAccessException(ex);}try {//返回远端调用的结果return recreateRemoteInvocationResult(result);}catch (Throwable ex) {if (result.hasInvocationTargetException()) {throw ex;}else {throw new RemoteInvocationFailureException("Invocation of method [" + methodInvocation.getMethod() +"] failed in HTTP invoker remote service at [" + getServiceUrl() + "]", ex);}}}?Spring技术黑幕——深入解析Spring架构与设计原理(五)Spring与远端调用Spring技术黑幕——深入解析Spring架构与设计原理(五)Spring与远端调用
        //这是HTTP调用器实现的基本过程,通过HTTP的request和reponse来完成通信,在通信的过程中传输的数据是序列化的对象protected RemoteInvocationResult doExecuteRequest(HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)throws IOException, ClassNotFoundException {//打开一个标准J2SE HttpURLConnectionHttpURLConnection con = openConnection(config);prepareConnection(con, baos.size());//远端调用封装成RemoteInvocation对象,这个对象通过序列化被写到对应的HttpURLConnection中去writeRequestBody(config, con, baos);//这里取得远端服务返回的结果,然后把结果转换成RemoteInvocationResult返回validateResponse(config, con);InputStream responseBody = readResponseBody(config, con);return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());}//把序列化对象输出到HttpURLConnection去protected void writeRequestBody(HttpInvokerClientConfiguration config, HttpURLConnection con, ByteArrayOutputStream baos)throws IOException {baos.writeTo(con.getOutputStream());}//为使用HttpURLConnection完成对象序列化,需要进行一系列的配置//比如配置请求方式为post,请求属性等等protected void prepareConnection(HttpURLConnection con, int contentLength) throws IOException {con.setDoOutput(true);con.setRequestMethod(HTTP_METHOD_POST);con.setRequestProperty(HTTP_HEADER_CONTENT_TYPE, getContentType());con.setRequestProperty(HTTP_HEADER_CONTENT_LENGTH, Integer.toString(contentLength));LocaleContext locale = LocaleContextHolder.getLocaleContext();if (locale != null) {con.setRequestProperty(HTTP_HEADER_ACCEPT_LANGUAGE, StringUtils.toLanguageTag(locale.getLocale()));}if (isAcceptGzipEncoding()) {con.setRequestProperty(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);}}//获得HTTP响应的IO流protected InputStream readResponseBody(HttpInvokerClientConfiguration config, HttpURLConnection con)throws IOException {//如果是通过gzip压缩,那么需要先解压if (isGzipResponse(con)) {// GZIP response found - need to unzip.return new GZIPInputStream(con.getInputStream());}else {// Plain response found.// 正常的HTTP响应输出return con.getInputStream();}}?Spring技术黑幕——深入解析Spring架构与设计原理(五)Spring与远端调用Spring技术黑幕——深入解析Spring架构与设计原理(五)Spring与远端调用
          protected Object invoke(RemoteInvocation invocation, Object targetObject)throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {if (logger.isTraceEnabled()) {logger.trace("Executing " + invocation);}try {//调用RemoteInvocationExecutor,这个执行器是DefaultRemoteInvocationExecutorreturn getRemoteInvocationExecutor().invoke(invocation, targetObject);}catch (NoSuchMethodException ex) {if (logger.isDebugEnabled()) {logger.warn("Could not find target method for " + invocation, ex);}throw ex;}catch (IllegalAccessException ex) {if (logger.isDebugEnabled()) {logger.warn("Could not access target method for " + invocation, ex);}throw ex;}catch (InvocationTargetException ex) {if (logger.isDebugEnabled()) {logger.debug("Target method failed for " + invocation, ex.getTargetException());}throw ex;}}?Spring技术黑幕——深入解析Spring架构与设计原理(五)Spring与远端调用Spring技术黑幕——深入解析Spring架构与设计原理(五)Spring与远端调用
            protected void writeRemoteInvocationResult(HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result)throws IOException {//设置Response的ContentType属性,设置为application/x-java-serialized-objectresponse.setContentType(getContentType());writeRemoteInvocationResult(request, response, result, response.getOutputStream());}//输出到HTTP的Response,然后把Response关闭protected void writeRemoteInvocationResult(HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result, OutputStream os)throws IOException {ObjectOutputStream oos = createObjectOutputStream(decorateOutputStream(request, response, os));try {doWriteRemoteInvocationResult(result, oos);oos.flush();}finally {oos.close();}}
            经过这一系列的处理过程,服务执行结果对象又回到了HTTP的远端调用客户端。在客户端从HTTP响应读取对象之后,它把这个看起来像是在本地实现,其实是由远端服务对象完成的调用结果,交给发起远端调用的客户端调用方法,从而最终完成整个远端调用的过程。这个过程很有特点,它使用了HTTP的请求和响应作为通信通道,在这个通信通道里面,并没有再做进一步的附加的通信协议的封装,而且,在这个处理过程中,使用的都是Java和Spring框架已有的特性,比如,通过IoC的配置,以及代理对象拦截器的封装处理,再加Java的序列化和反序列化,以及在服务器端的Spring MVC框架的使用,通过这些已有的技术实现,让使用者感觉,它的实现风格非常的简洁轻快,整个代码实现,阅读起来,也让人感到非常的赏心悦目。

读书人网 >编程

热点推荐