HttpInvoker远程调用原理解析

前言

服务端在开发一般大致分为:

  • controller
  • service
  • dao/mapper(ROM框架处理)

开发完成后用nginx进行部署,nginx支持多服务的负载均衡,在和tomcat进行反向代理后可以完美实现部署

负载

graph LR
客户端-->服务端1
客户端-->服务端2
客户端-->...

服务端暴露的服务实在@Controller实现
通过dispaterServlet拦截请求后找到对应HttpRequestHandler找到对应的controller
通过上面的模式即可实现简单的分布式
到目前为止好像说的跟远程调用没关系


远程调用的场景

  • 服务和客户端不在一个机器上
  • 为了实现客户端和服务端分布式
  • rpc框架:dubbo , spring-cloud 其中dubbo算是一个spring-cloud的一个功能分支

远程调用方法 HttpInvoker

  • 服务端
  1. 服务端定义接口
public interface UserHttpService {  
   List getUserByAcount(Stringname,String password);  
   void insert(User user);  
}
  1. 服务端接口实现
publicclass UserHttpServiceImpl implements UserHttpService {  
   
   @Autowired  
   private UserMapper userMapper;  
   @Override  
   public ListgetUserByAcount(String name, String password) {  
            System.err.println("httpInvoker获取用户信息:"+ name + password);  
            return new ArrayList();  
   }  
   @Override  
   public void insert(User user) {  
            System.err.println("httpInvoker开始插入用户信息:"+ user.toString());  
   }  
   
}
  1. 服务端接口暴露 类似与Controller
  
  
      
      



    
    
        
          
        
    

  1. web.xml
      
        dispatcherServlet  
        org.springframework.web.servlet.DispatcherServlet  
          
            contextConfigLocation  
              
            classpath:applicationContext-httpinvoker.xml  
           
          
      
      
        dispatcherServlet  
        *  
     
  • 客户端
  1. 客户端接口
public interface UserHttpService {  
   List getUserByAcount(Stringname,String password);  
   void insert(User user);  
}
  1. 客户端配置
  
         
         

  1. 客户端调用
    @RequestMapping(value = "/httpInvokerTest")  
    @ResponseBody  
    public BaseMapVo httpInvokerTest(String name, String password) {  
       BaseMapVo vo = new BaseMapVo();  
       long startDate = Calendar.getInstance().getTimeInMillis();  
       System.out.println("httpInvoker客户端开始调用" + startDate);  
       UserHttpService rmi = (UserHttpService) ApplicationContextUtil.getInstance().getBean("httpInvokerProxy");  
       rmi.getUserByAcount("张三", ":张三的密码");  
       System.out.println("httpInvoker客户端调用结束" +  (Calendar.getInstance().getTimeInMillis()-startDate));  
       vo.setRslt("sucess");  
       return vo;  
    }

原理解析

通过http请求,封装序列化的对象,通过动态代理的方式进行信息获取

spring 源码解析

public Object invoke(MethodInvocation methodInvocation) throws Throwable {
    // 如果是调用toString()方法则直接本地打印下方法信息
    if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
        return "HTTP invoker proxy for service URL [" + getServiceUrl() + "]";
    }
    // 构建RemoteInvocation对象,服务器和客户端统一使用该类进行通信
    RemoteInvocation invocation = createRemoteInvocation(methodInvocation);
    RemoteInvocationResult result;
    try {
    // 使用JDK自带的HttpURLConnection将序列化后的invocation的发送出去
        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);
    }
}

我们最关心的是当我们调用接口的方法时,HttpInvoker是如何做到调用到远方系统的方法的,其实HttpInvokerProxyFactoryBean最后返回的是一个代理类(Cglib Proxy或者Jdk Proxy),我们调用接口的任何方法时,都会先执行HttpInvokerClientInterceptor的invoke()方法,

result = executeRequest(invocation, methodInvocation);

然后通过HttpUrlClient将序列化的invocation传输到服务端,服务端在返回invocationResult

你可能感兴趣的:(HttpInvoker远程调用原理解析)