Using multithreading to improve rest service performance
Improve server throughput by processing rest services asynchronously
Using runnable to handle the rest service asynchronously
Asynccontroller.java
@RestController@GetMapping("/async")public class AsyncController { private Logger logger = LoggerFactory.getLogger(getClass()); @RequestMapping("/order") public Callable<String> order() throws Exception { logger.info("主线程开始"); Callable<String> result = new Callable<String>() { @Override public String call() throws Exception { logger.info("副线程开始"); Thread.sleep(2000); // 模拟处理下单消耗的时间 logger.info("副线程结束"); return "success"; } }; logger.info("主线程结束"); return result; }}
Using Deferredresult to handle the rest service asynchronously
App 1/thread 1: Receive the next order request, put it in message queue
Apply 1/Thread 2: Listener, listen for Message Queuing for order Processing results, return HTTP response
Application 2: Processing the next order logic
Asynccontroller.java
@GetMapping("/order2")public DeferredResult<String> order2() throws Exception { logger.info("主线程开始"); // 主线程,相当于图中应用1/线程1,接收HTTP请求 // 收到下单请求,生成一个随机订单号,放到消息队列里 String orderNumber = RandomStringUtils.randomNumeric(8); mockQueue.setPlaceOrder(orderNumber); // 用于接收处理结果 DeferredResult<String> result = new DeferredResult<>(); deferredResultHolder.getMap().put(orderNumber, result); logger.info("主线程结束"); return result;}
Mockqueue.java, Analog queue
@Componentpublic class MockQueue { private String placeOrder; // 下单消息 private String completeOrder; // 订单完成订单完成 private Logger logger = LoggerFactory.getLogger(getClass()); public String getPlaceOrder() { return placeOrder; } public void setPlaceOrder(String placeOrder) { // 此线程是模拟应用2,处理下单逻辑 new Thread(() -> { logger.info("接到下单请求:" + placeOrder); try { Thread.sleep(1000); // 模拟处理下单过程 } catch (InterruptedException e) { e.printStackTrace(); } this.completeOrder = placeOrder; logger.info("下单请求处理完毕:" + placeOrder); }).start(); } public String getCompleteOrder() { return completeOrder; } public void setCompleteOrder(String completeOrder) { this.completeOrder = completeOrder; }}
Deferredresultholder.java, for passing Deferredresult objects between thread 1 and Threads 2
@Componentpublic class DeferredResultHolder { // 订单号,订单处理结果 private Map<String, DeferredResult<String>> map = new HashMap<>(); public Map<String, DeferredResult<String>> getMap() { return map; } public void setMap(Map<String, DeferredResult<String>> map) { this.map = map; }}
Queuelistener.java, Listener
@Componentpublic class Queuelistener implements applicationlistener<contextrefreshedevent> {@Autowired privat e mockqueue mockqueue; @Autowired private Deferredresultholder Deferredresultholder; Private Logger Logger = Loggerfactory.getlogger (GetClass ()); @Override public void Onapplicationevent (Contextrefreshedevent contextrefreshedevent) {//equivalent to figure application 1/thread 2, Analog listener New Thread ((), {while (true) {if (Stringutils.isnotblank (Mockqueue.getcompleteorder ( )) {String ordernumber = Mockqueue.getcompleteorder (); Logger.info ("Return Order Processing Result:" + ordernumber); Deferredresultholder.getmap (). Get (OrderNumber). Setresult ("Place order Success"); Mockqueue.setcompleteorder (NULL); } else {try {thread.sleep (100); } catch (Interruptedexception e) {}}}). Start (); }}
Launch the app and access Http://localhost:8080/async/order2
Asynchronous processing Configuration
Intercepting requests for asynchronous processing with interceptors in the configuration of the thread pool
// 用拦截器拦截异步处理的请求,有如下两个方法注册拦截器,分别对应异步处理的两种方式// 区别是有超时时间// configurer.registerCallableInterceptors()// configurer.registerDeferredResultInterceptors()// Runnable使用的简单的异步线程池来处理,线程不可重用
Using swagger to automatically generate documents to introduce swagger
Introducing Dependencies, Immoc-security-demo/pom.xml
<!-- 引入swagger --><dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.7.0</version></dependency><dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.7.0</version></dependency>
Add annotations, Demoapplication.java
@EnableSwagger2 // 启用Swagger2
Restart the app to access the link http://localhost:8080/swagger-ui.html
Detailed description
Description of the method
@ApiOperation(value = "用户查询服务")
Description of the parameter
// 参数被封装到对象里@ApiModelProperty("用户名")// 参数直接写在方法里@ApiParam("用户ID")
Using Wiremock to forge rest services
Wiremock comes in handy when working in parallel with front-end development, in the development phase, when the front-end includes app and page development needs test data. This is different from how you can write a web app to provide test data. Because Wiremock does not have to be restarted, it is convenient to define URLs and return data.
Download and launch
Download: http://wiremock.org/docs/running-standalone/
Specify the port to start:
java -jar wiremock-standalone-2.18.0.jar --port 9999# --port 9999 指定端口,默认端口8080, --port 0 随机端口
Impersonation requests and responses
Introducing Dependencies
<!-- 引入WireMock--><dependency> <groupId>com.github.tomakehurst</groupId> <artifactId>wiremock</artifactId></dependency><dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId></dependency>
Write code, Mockserver.java
public class MockServer { public static void main(String[] args) throws IOException { configureFor("192.168.5.210", 9999); // configureFor(9999); removeAllMappings(); mock("/order/1", "01.txt"); mock("/order/2", "02.txt"); } private static void mock(String url, String fileName) throws IOException { ClassPathResource resource = new ClassPathResource("mock/response/" + fileName); String content = StringUtils.join(FileUtils.readLines(resource.getFile(), "UTF-8"), "\n"); stubFor(get(urlPathEqualTo(url)) .willReturn(aResponse().withBody(content).withStatus(200))); }}
Developing restful APIs using Spring MVC (cont.)