在多个内网系统之上,增加一个网关服务,统一对第三方应用进行鉴权与认证,方可对内部资源服务进行访问,网关服务主要起到鉴权认证,请求转发主要借助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();
}
}
}
© 著作权归作者所有