在多个内网系统之上,增加一个网关服务,统一对第三方应用进行鉴权与认证,方可对内部资源服务进行访问,网关服务主要起到鉴权认证,请求转发主要借助Servlet3.0的异步特性实现,结合springboot进行开发。
同步请求会将整个请求链路的发起,解析,响应在一个同步逻辑中进行。
采用异步处化可以将请求中耗时操作交给线程池做异步处理,在高并发场景下,通过调用一个非web服务线程处理耗时逻辑,提高系统并发性。
由于线程池是隔离的,可以对线程池做业务隔离分组,进行请求分级,监控等。
之前有几篇文章介绍了认证和鉴权的实现思路,可参考系统鉴权流程及签名生成规则,公网API安全--OAuth认证,互联网通用架构技术----公网API安全规范。
转发的思路主要希望可以将客户端请求直接转发到业务系统,网关系统对于请求api,通过识别入参的条件进行不同业务系统的路由,请求api不做干扰直接转发。
/** * Description * * @author Mr. Chun. */@WebListenerpublic class AppContextListener implements ServletContextListener { /** * 通过ContextListener进行线程池初始化 * * @param servletContextEvent */ @Override public void contextInitialized(ServletContextEvent servletContextEvent) { ThreadPoolExecutor executor = new ThreadPoolExecutor( 100, 200, 50000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(100)); servletContextEvent.getServletContext().setAttribute("executor", executor); } /** * 通过ContextListener进行线程池销毁 * @param servletContextEvent */ @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { ThreadPoolExecutor executor = (ThreadPoolExecutor) servletContextEvent.getServletContext().getAttribute("executor"); executor.shutdown(); } }
/** * Description * ... * @author Mr. Chun. */@WebServlet(urlPatterns = "/qbs/route", asyncSupported = true) public class AsyncLongRunningServlet extends HttpServlet { private static final long serialVersionUID = 1L; private static final Logger logger = LoggerFactory.getLogger(AsyncLongRunningServlet.class); @Autowired private RestTemplate restTemplate; @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { logger.info("==== 进入Servlet的时间:" + new Date() + " ===="); long startTime = System.currentTimeMillis(); logger.info("AsyncLongRunningServlet Start::Name=" + Thread.currentThread().getName() + "::ID=" + Thread.currentThread().getId()); req.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true); //在子线程中执行业务调用,并由其负责输出响应,主线程退出 AsyncContext ctx = req.startAsync(); ctx.setTimeout(9000); ThreadPoolExecutor executor = (ThreadPoolExecutor) req.getServletContext().getAttribute("executor"); executor.execute(new AsyncRequestProcessor(restTemplate, ctx, req.getMethod(), req.getParameter("api"))); // 任务提交线程池 long endTime = System.currentTimeMillis(); logger.info("AsyncLongRunningServlet End::Name=" + Thread.currentThread().getName() + "::ID=" + Thread.currentThread().getId() + "::Time Taken=" + (endTime - startTime) + " ms."); logger.info("==== 结束Servlet的时间:" + new Date() + " ===="); } }
/** * Description * ... * * @author Mr. Chun. */public class AsyncRequestProcessor implements Runnable { private static final Logger logger = LoggerFactory.getLogger(AsyncRequestProcessor.class); private String url = "http://localhost:8080/"; private RestTemplate restTemplate; private AsyncContext ctx = null; private String requestMethod = ""; public AsyncRequestProcessor(RestTemplate restTemplate, AsyncContext ctx, String requestMethod, String api) { this.restTemplate = restTemplate; this.ctx = ctx; this.requestMethod = requestMethod; url = url + api; } public void run() { try { // 业务请求转发在这里处理 // 请求入参 Map map = ctx.getRequest().getParameterMap(); // 最终请求参数 MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<>(); Iterator iterator = map.keySet().iterator(); while (iterator.hasNext()) { String key = (String) iterator.next(); if (!ResponseBuilder.isSysParam(key)) { paramMap.add(key, map.get(key).toString()); } } String json = ""; if ("GET".equals(requestMethod)) { json = restTemplate.getForObject(url, String.class, paramMap); } else if ("POST".equals(requestMethod)) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(paramMap, headers); ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class); json = response.getBody(); } ResponseBuilder.responseWrite((HttpServletResponse) ctx.getResponse(), json); logger.info("==== 业务处理完毕的时间:" + new Date() + " ===="); ctx.complete(); // 通知容器,异步处理完成 } catch (Exception e) { logger.error("AsyncExecutor e: " + e.getMessage()); e.printStackTrace(); } } }
© 著作权归作者所有
本文分享自微信公众号 - 服务端技术杂谈(ITIBB2014)
原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。
原始发表时间:2017-12-07
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句