Java中servicehandler,ServiceController 服务接口异步请求处理

本文介绍了一种利用异步请求处理提高服务接口性能的方法。通过ServiceController统一接收请求,并分发给具体的ServiceHandler进行处理。支持JSON和XML格式的数据交换,并可灵活配置同步或异步处理方式。

异步请求处理可以提高服务接口的吞吐量、响应能力等,这里介绍一个简单的实现参考:

ServiceController,服务接口调度中心,处理并分发所有访问/service/{name}的请求,

ServiceHandler,服务处理者接口;ServiceHandlerAbstract,服务处理者抽象类,供继承

ServiceHandlerDatetime,日期服务处理者,参考实现

ServiceRequester,服务访问工具类

配置web.xml支持异步请求处理,所有的filter和servlet都要配置支持async-supported

true

ServiceController,检查加密授权secret参数,通过后分发给服务名name对应的ServiceHandler处理

支持请求参数Map,可以get或post

支持请求正文为json或xml格式,转换为JSONObject和XMLObject

支持异步或同步处理,例如ServiceHandlerDatetime就声明为同步处理,而比较耗时的服务则最好声明为异步处理

@RestController

@RequestMapping("service")

public class ServiceController {

private Logger logger = LoggerFactory.getLogger(getClass());

private static HttpHeaders headers = new HttpHeaders();

private Map serviceHandlers = new HashMap<>();

public static String secret = GlobalConfig.getProperty("service.controller.secret", "vyj2mtc5i1r4");

public static JSONObject BadRequest = JSON.parseObject("{\"status\":\"200\", \"error\":\"bad request\"}");

public static String BadRequestXML = new XMLObject("response").add("status", "200").add("error", "bad request").toString();

static {

headers.set("Access-Control-Allow-Origin", "*");

}

@RequestMapping(value= {"{name}", "{name}/**"})

public Object service(final HttpServletRequest request, final @PathVariable String name) {

final Map params = RequestUtil.stringMap(request);

final String content = getContent(request);

final boolean isXml = request.getRequestURI().endsWith(".xml");

final JSONObject data = !isXml ? getJson(content) : null;

final XMLObject xml = isXml ? getXml(content) : null;

logger.info(request.getMethod()+request.getRequestURI());

if(params.size()>0) logger.info("params: "+JSON.toJSONString(params));

if(data!=null || xml!=null) logger.info("body: "+(data!=null ? data.toJSONString() : xml.toString()));

//检查加密授权

boolean legal = secret.equals(params.get("secret"));

if(!legal && data!=null) legal = secret.equals(data.getString("secret"));

if(!legal && xml!=null) legal = secret.equals(xml.get("secret"));

if(!legal) {

Object obj = isXml ? BadRequestXML : BadRequest;

logger.info("result: "+obj.toString());

return new HttpEntity(obj, headers);

}

//处理请求

final ServiceHandler serviceHandler = serviceHandlers.get(name);

if(serviceHandler==null) { //非法请求

Object obj = isXml ? BadRequestXML : BadRequest;

logger.info("result: "+obj.toString());

return new HttpEntity(obj, headers);

}

if(serviceHandler.async()) {

return new Callable() {

public Object call() throws Exception {

return handle(serviceHandler, request, params, isXml ? xml : data);

}

};

}else {

return handle(serviceHandler, request, params, isXml ? xml : data);

}

}

private Object handle(ServiceHandler handler, HttpServletRequest request, Map params, Object body) {

boolean isXml = request.getRequestURI().endsWith(".xml");

Object obj = isXml ? handler.handle(request, params, (XMLObject)body) : handler.handle(request, params, (JSONObject)body);

obj = obj!=null ? obj : (isXml ? BadRequestXML : BadRequest);

logger.info("result: "+obj.toString());

return new HttpEntity(isXml ? obj.toString() : obj, headers);

}

public boolean register(ServiceHandler serviceHandler) {

if(serviceHandler!=null && StringUtils.isNotBlank(serviceHandler.name())) {

ServiceHandler handler = serviceHandlers.get(serviceHandler.name());

if(handler!=null) logger.warn("service handler key already exist, replace it: "+handler+", using this: "+serviceHandler);

serviceHandlers.put(serviceHandler.name(), serviceHandler);

return true;

}

logger.warn("bad service handler to register: "+serviceHandler);

return false;

}

private JSONObject getJson(String content) {

try {

if(StringUtils.isNotBlank(content) && content.startsWith("{")) return JSON.parseObject(content);

} catch (Exception e) {

logger.warn("fail to parse content to json: "+e.getMessage(), e);

}

return null;

}

private XMLObject getXml(String content) {

try {

if(StringUtils.isNotBlank(content) && content.startsWith("

} catch (Exception e) {

logger.warn("fail to parse content to xml: "+e.getMessage(), e);

}

return null;

}

private String getContent(HttpServletRequest request) {

try {

return IOUtils.toString(request.getInputStream(), Charsets.UTF_8);

} catch (Exception e) {

logger.warn("fail to get content of request: "+e.getMessage(), e);

}

return null;

}

}

ServiceHandler

public interface ServiceHandler {

/** 服务名称*/

String name();

/** 是否异步,耗时任务请使用异步 */

boolean async();

/** key-value数据处理并响应json */

JSONObject handle(HttpServletRequest request, Map params, JSONObject body);

/** method rquestUri headers params body 都可以处理 */

XMLObject handle(HttpServletRequest request, Map params, XMLObject body);

}

ServiceHandlerAbstract

public abstract class ServiceHandlerAbstract implements ServiceHandler, InitializingBean {

protected @Autowired ServiceController serviceController;

protected Logger logger = LoggerFactory.getLogger(getClass());

public void afterPropertiesSet() throws Exception {

serviceController.register(this);

}

public boolean async() {

return false;

}

public JSONObject handle(HttpServletRequest request, Map params, JSONObject body) {

return null;

}

public XMLObject handle(HttpServletRequest request, Map params, XMLObject body) {

return null;

}

}

ServiceHandlerDatetime,注解@Component以便被spring扫描为bean

@Component

public class ServiceHandlerDatetime extends ServiceHandlerAbstract {

private String name = "datetime";

@Override

public String name() {

return name;

}

public JSONObject handle(HttpServletRequest request, Map params, JSONObject body) {

String format = params.get("format");

if(format==null && body!=null) format = body.getString("format");

String datetime = datetime(format);

JSONObject json = new JSONObject();

json.put(name, datetime);

return json;

}

public XMLObject handle(HttpServletRequest request, Map params, XMLObject body) {

String format = params.get("format");

if(format==null && body!=null) format = body.get("format");

String datetime = datetime(format);

XMLObject xml = new XMLObject("response");

xml.add(name, datetime);

return xml;

}

private String datetime(String format) {

FormatType formatType = FormatType.DAYTIME;

if(format!=null && format.length()>0) {

try {

formatType = FormatType.valueOf(format);

}catch (Exception e) {

logger.warn("bad datetime format: "+format);

}

}

return DateUtil.format(new Date(), formatType);

}

}

ServiceRequesterTester

String service = GlobalConfig.getProperty("front_url")+"/service/";

String datetime = service+"datetime.json";

String datetimeXML = service+"datetime.xml";

int requestCount = 10000;

@Test public void request() {

final CountDownLatch latch = new CountDownLatch(requestCount);

final IntHolder success = new IntHolder(0);

long s = System.currentTimeMillis();

for(int i=0;i

TaskUtil.submit(new Runnable() {

@Override

public void run() {

Object obj = null;

switch(success.value%3) {

case 0:

Map params = ServiceRequester.paramsWithSecret();

obj = ServiceRequester.request(datetime, params);

break;

case 1:

JSONObject data = ServiceRequester.jsonWithSecret();

data.put("format", "DAYSHORTTIME");

obj = ServiceRequester.request(datetime, data);

break;

case 2:

XMLObject xml = ServiceRequester.xmlWithSecret();

xml.add("format", "DAY");

obj = ServiceRequester.request(datetimeXML, xml);

break;

}

System.out.println(obj);

if(obj!=null) success.value++;

latch.countDown();

}

});

}

try {

latch.await();

} catch (InterruptedException e) {

e.printStackTrace();

}

//success: 9996/10000, total ms: 29701 异步处理

//success: 10000/10000, total ms: 12905 同步处理

System.out.println("success: "+success.value+"/"+requestCount+", total ms: "+(System.currentTimeMillis()-s));

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值