生活随笔
收集整理的這篇文章主要介紹了
将dubbo暴露HTTP服务
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
通常來說一個dubbo服務都是對內的,也就是給內部調用的,但也有可能一個服務就是需要提供給外部使用,并且還不能有使用語言的局限性。
比較標準的做法是對外的服務我們統一提供一個openAPI,這樣的調用方需要按照標準提供相應的appID以及密鑰來進行驗簽才能使用。這樣固然是比較規范和安全,但復雜度也不亞于開發一個單獨的系統了。
這里所講到的沒有那么復雜,就只是把一個不需要各種權限檢驗的dubbo服務對外提供為HTTP服務。
實現思路:
1、定義HttpProviderConf配置類
主要用于保存聲明需要對外提供服務的包名
package com.bsk.dubbo.http.conf;import java.util.List;public class HttpProviderConf {/*** 提供http訪問的包*/private List<String> usePackage ;public List<String> getUsePackage() {return usePackage;}public void setUsePackage(List<String> usePackage) {this.usePackage = usePackage;}
}
2、封裝請求響應類
package com.bsk.dubbo.http.req;
/*** 請求*/
public class HttpRequest {private String param ;//入參private String service ;//請求serviceprivate String method ;//請求方法public String getParam() {return param;}public void setParam(String param) {this.param = param;}public String getService() {return service;}public void setService(String service) {this.service = service;}public String getMethod() {return method;}public void setMethod(String method) {this.method = method;}
}
其中param是用于存放真正調用dubbo服務時的入參,傳入json在調用的時候解析成具體的參數對象。
service存放dubbo服務聲明的interface API的包名。
method則是真正調用的方法名稱。
package com.bsk.dubbo.http.rsp;import java.io.Serializable;/*** 響應*/
public class HttpResponse implements Serializable{private static final long serialVersionUID = -552828440320737814L;private boolean success;//成功標志private String code;//信息碼private String description;//描述public boolean isSuccess() {return success;}public void setSuccess(boolean success) {this.success = success;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}
}
?3、編寫暴露服務Controller接口
利用SpringMVC提供一個HTTP接口。
在該接口中通過入參進行反射找到具體的dubbo服務實現進行調用。
package com.bsk.dubbo.http.controller;import com.alibaba.fastjson.JSON;
import com.bsk.dubbo.http.conf.HttpProviderConf;
import com.bsk.dubbo.http.req.HttpRequest;
import com.bsk.dubbo.http.rsp.HttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.*;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;@Controller
@RequestMapping("/dubboAPI")
public class DubboController implements ApplicationContextAware {private final static Logger logger = LoggerFactory.getLogger(DubboController.class);@Autowiredprivate 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;}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}
將這些實現封裝成一個功能模塊
具體使用請參考博文:SSM(十三) 將dubbo暴露出HTTP服務 | crossoverJie's Blog
4、測試示例
使用Jmeter工具進行測試:?
?測試結果:
5、總結
通常來說這樣提供的HTTP接口再實際中用的不多,但是很方便調試。
比如寫了一個dubbo的查詢接口,在測試環境或者是預發布環境中就可以直接通過HTTP請求的方式進行簡單的測試,或者就是查詢數據。比在Java中寫單測來測試或查詢快很多。
總結
以上是生活随笔為你收集整理的将dubbo暴露HTTP服务的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。