SSM(十三) 将dubbo暴露出HTTP服务(上)

简介: 通常来说一个dubbo服务都是对内给内部调用的,但也有可能一个服务就是需要提供给外部使用,并且还不能有使用语言的局限性。比较标准的做法是对外的服务我们统一提供一个openAPI,这样的调用方需要按照标准提供相应的appID以及密钥来进行验签才能使用。这样固然是比较规范和安全,但复杂度也不亚于开发一个单独的系统了。

前言


通常来说一个dubbo服务都是对内给内部调用的,但也有可能一个服务就是需要提供给外部使用,并且还不能有使用语言的局限性。


比较标准的做法是对外的服务我们统一提供一个openAPI,这样的调用方需要按照标准提供相应的appID以及密钥来进行验签才能使用。这样固然是比较规范和安全,但复杂度也不亚于开发一个单独的系统了。


这里所讲到的没有那么复杂,就只是把一个不需要各种权限检验的dubbo服务对外提供为HTTP服务。


调用示例:


dubbo-http封面.jpg


准备工作


以下是本文所涉及到的一些知识点:


  • Spring相关知识。


  • Java反射相关知识。


  • SpringMVC相关知识。


其实思路很简单,就是利用SpringMVC提供一个HTTP接口。


在该接口中通过入参进行反射找到具体的dubbo服务实现进行调用。


HttpProviderConf配置类


首先需要定义一个HttpProviderConf类用于保存声明需要对外提供服务的包名,毕竟我们反射时需要用到一个类的全限定名:


public class HttpProviderConf {
    /**
     * 提供http访问的包
     */
    private List<String> usePackage ;
    //省略getter setter方法
}


就只有一个usePackage成员变量,用于存放需要包名。


至于用List的原因是允许有多个。


请求响应入参、出参


HttpRequest入参


public class HttpRequest {
    private String param ;//入参
    private String service ;//请求service
    private String method ;//请求方法
    //省略getter setter方法
}


其中param是用于存放真正调用dubbo服务时的入参,传入json在调用的时候解析成具体的参数对象。


service存放dubbo服务声明的interface API的包名。


method则是真正调用的方法名称。


HttpResponse 响应


public class HttpResponse implements Serializable{
    private static final long serialVersionUID = -552828440320737814L;
    private boolean success;//成功标志
    private String code;//信息码
    private String description;//描述
    //省略getter setter方法
}


这里只是封装了常用的HTTP服务的响应数据。


暴露服务controller


最重要的则是controller里的实现代码了。


先贴代码:


@Controller
@RequestMapping("/dubboAPI")
public class DubboController implements ApplicationContextAware{
    private final static Logger logger = LoggerFactory.getLogger(DubboController.class);
    @Autowired
    private HttpProviderConf httpProviderConf;
    //缓存作用的map
    private final Map<String, Class<?>> cacheMap = new HashMap<String, Class<?>>();
    protected ApplicationContext applicationContext;
    @ResponseBody
    @RequestMapping(value = "/{service}/{method}",method = RequestMethod.POST)
    public String api(HttpRequest httpRequest, HttpServletRequest request,
                      @PathVariable String service,
                      @PathVariable String method) {
        logger.debug("ip:{}-httpRequest:{}",getIP(request), JSON.toJSONString(httpRequest));
        String invoke = invoke(httpRequest, service, method);
        logger.debug("callback :"+invoke) ;
        return invoke ;
    }
    private String invoke(HttpRequest httpRequest,String service,String method){
        httpRequest.setService(service);
        httpRequest.setMethod(method);
        HttpResponse response = new HttpResponse() ;
        logger.debug("input param:"+JSON.toJSONString(httpRequest));
        if (!CollectionUtils.isEmpty(httpProviderConf.getUsePackage())){
            boolean isPac = false ;
            for (String pac : httpProviderConf.getUsePackage()) {
                if (service.startsWith(pac)){
                    isPac = true ;
                    break ;
                }
            }
            if (!isPac){
                //调用的是未经配置的包
                logger.error("service is not correct,service="+service);
                response.setCode("2");
                response.setSuccess(false);
                response.setDescription("service is not correct,service="+service);
            }
        }
        try {
            Class<?> serviceCla = cacheMap.get(service);
            if (serviceCla == null){
                serviceCla = Class.forName(service) ;
                logger.debug("serviceCla:"+JSON.toJSONString(serviceCla));
                //设置缓存
                cacheMap.put(service,serviceCla) ;
            }
            Method[] methods = serviceCla.getMethods();
            Method targetMethod = null ;
            for (Method m : methods) {
                if (m.getName().equals(method)){
                    targetMethod = m ;
                    break ;
                }
            }
            if (method == null){
                logger.error("method is not correct,method="+method);
                response.setCode("2");
                response.setSuccess(false);
                response.setDescription("method is not correct,method="+method);
            }
            Object bean = this.applicationContext.getBean(serviceCla);
            Object result = null ;
            Class<?>[] parameterTypes = targetMethod.getParameterTypes();
            if (parameterTypes.length == 0){
                //没有参数
                result = targetMethod.invoke(bean);
            }else if (parameterTypes.length == 1){
                Object json = JSON.parseObject(httpRequest.getParam(), parameterTypes[0]);
                result = targetMethod.invoke(bean,json) ;
            }else {
                logger.error("Can only have one parameter");
                response.setSuccess(false);
                response.setCode("2");
                response.setDescription("Can only have one parameter");
            }
            return JSON.toJSONString(result) ;
        }catch (ClassNotFoundException e){
            logger.error("class not found",e);
            response.setSuccess(false);
            response.setCode("2");
            response.setDescription("class not found");
        } catch (InvocationTargetException e) {
            logger.error("InvocationTargetException",e);
            response.setSuccess(false);
            response.setCode("2");
            response.setDescription("InvocationTargetException");
        } catch (IllegalAccessException e) {
            logger.error("IllegalAccessException",e);
            response.setSuccess(false);
            response.setCode("2");
            response.setDescription("IllegalAccessException");
        }
        return JSON.toJSONString(response) ;
    }
    /**
     * 获取IP
     * @param request
     * @return
     */
    private String getIP(HttpServletRequest request) {
        if (request == null)
            return null;
        String s = request.getHeader("X-Forwarded-For");
        if (s == null || s.length() == 0 || "unknown".equalsIgnoreCase(s)) {
            s = request.getHeader("Proxy-Client-IP");
        }
        if (s == null || s.length() == 0 || "unknown".equalsIgnoreCase(s)) {
            s = request.getHeader("WL-Proxy-Client-IP");
        }
        if (s == null || s.length() == 0 || "unknown".equalsIgnoreCase(s)) {
            s = request.getHeader("HTTP_CLIENT_IP");
        }
        if (s == null || s.length() == 0 || "unknown".equalsIgnoreCase(s)) {
            s = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (s == null || s.length() == 0 || "unknown".equalsIgnoreCase(s)) {
            s = request.getRemoteAddr();
        }
        if ("127.0.0.1".equals(s) || "0:0:0:0:0:0:0:1".equals(s))
            try {
                s = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException unknownhostexception) {
                return "";
            }
        return s;
    }
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }


相关文章
|
2月前
|
Java Maven Windows
使用Java创建集成JACOB的HTTP服务
本文介绍了如何在Java中创建一个集成JACOB的HTTP服务,使Java应用能够调用Windows的COM组件。文章详细讲解了环境配置、动态加载JACOB DLL、创建HTTP服务器、实现IP白名单及处理HTTP请求的具体步骤,帮助读者实现Java应用与Windows系统的交互。作者拥有23年编程经验,文章来源于稀土掘金。著作权归作者所有,商业转载需授权。
使用Java创建集成JACOB的HTTP服务
|
1月前
|
监控 Dubbo Java
dubbo学习三:springboot整合dubbo+zookeeper,并使用dubbo管理界面监控服务是否注册到zookeeper上。
这篇文章详细介绍了如何将Spring Boot与Dubbo和Zookeeper整合,并通过Dubbo管理界面监控服务注册情况。
75 0
dubbo学习三:springboot整合dubbo+zookeeper,并使用dubbo管理界面监控服务是否注册到zookeeper上。
|
1月前
|
关系型数据库 MySQL 数据库
vertx 的http服务表单提交与mysql验证
本文介绍了如何使用Vert.x处理HTTP服务中的表单提交,并通过集成MySQL数据库进行验证,包括项目依赖配置、表单HTML代码和完整的Vert.x服务代码。
16 2
|
3月前
|
JSON Dubbo Java
【Dubbo协议指南】揭秘高性能服务通信,选择最佳协议的终极攻略!
【8月更文挑战第24天】在分布式服务架构中,Apache Dubbo作为一款高性能的Java RPC框架,支持多种通信协议,包括Dubbo协议、HTTP协议及Hessian协议等。Dubbo协议是默认选择,采用NIO异步通讯,适用于高要求的内部服务通信。HTTP协议通用性强,利于跨语言调用;Hessian协议则在数据传输效率上有优势。选择合适协议需综合考虑性能需求、序列化方式、网络环境及安全性等因素。通过合理配置,可实现服务性能最优化及系统可靠性提升。
55 3
|
3月前
|
机器学习/深度学习 Ubuntu Linux
在Linux中,如何按照该要求抓包:只过滤出访问http服务的,目标ip为192.168.0.111,一共抓1000个包,并且保存到1.cap文件中?
在Linux中,如何按照该要求抓包:只过滤出访问http服务的,目标ip为192.168.0.111,一共抓1000个包,并且保存到1.cap文件中?
|
3月前
|
缓存 Dubbo Java
Dubbo服务消费者启动与订阅原理
该文章主要介绍了Dubbo服务消费者启动与订阅的原理,包括服务消费者的启动时机、启动过程以及订阅和感知最新提供者信息的方式。
Dubbo服务消费者启动与订阅原理
|
3月前
|
Dubbo 网络协议 Java
深入掌握Dubbo服务提供者发布与注册原理
该文章主要介绍了Dubbo服务提供者发布与注册的原理,包括服务发布的流程、多协议发布、构建Invoker、注册到注册中心等过程。
深入掌握Dubbo服务提供者发布与注册原理
|
3月前
|
负载均衡 Dubbo Java
Dubbo服务Spi机制和原理
该文章主要介绍了Dubbo中的SPI(Service Provider Interface)机制和原理,包括SPI的基本概念、Dubbo中的SPI分类以及SPI机制的实现细节。
Dubbo服务Spi机制和原理
|
3月前
|
C# 开发者 Windows
勇敢迈出第一步:手把手教你如何在WPF开源项目中贡献你的第一行代码,从选择项目到提交PR的全过程解析与实战技巧分享
【8月更文挑战第31天】本文指导您如何在Windows Presentation Foundation(WPF)相关的开源项目中贡献代码。无论您是初学者还是有经验的开发者,参与这类项目都能加深对WPF框架的理解并拓展职业履历。文章推荐了一些适合入门的项目如MvvmLight和MahApps.Metro,并详细介绍了从选择项目、设置开发环境到提交代码的全过程。通过具体示例,如添加按钮点击事件处理程序,帮助您迈出第一步。此外,还强调了提交Pull Request时保持专业沟通的重要性。参与开源不仅能提升技能,还能促进社区交流。
44 0
|
3月前
|
负载均衡 中间件 Go
五分钟给你的 gRPC 服务加上 HTTP 接口
五分钟给你的 gRPC 服务加上 HTTP 接口