laitimes

7 magic tricks to boost Spring Boot throughput

author:Java coders take you to learn programming

First, asynchronous execution

There are two ways to implement it:

1. Use asynchronous annotations@aysnc, Start Class: Add @EnableAsync annotations

2. JDK 8 itself has a very useful Future class , CompletableFuture

@AllArgsConstructor

public class AskThread implements Runnable{

private CompletableFuture<Integer> re = null;

public void run() {

int myRe = 0;

try {

myRe = re.get() * re.get();

} catch (Exception e) {

e.printStackTrace();

}

System.out.println(myRe);

}

public static void main(String[] args) throws InterruptedException {

final CompletableFuture<Integer> future = new CompletableFuture<>();

new Thread(new AskThread(future)).start();

Simulates a long calculation process

Thread.sleep(1000);

Inform the completion result

future.complete(60);

}

}

In this example, a thread is started, at which point the AskThread object has not yet got the data it needs, and execution to myRe = re.get() * re.get() blocks. We simulate a long calculation process by sleeping for 1 second and tell the result of the calculation to the future execution result, and the AskThread thread will continue to execute. If you're learning Spring Boot, recommend a free tutorial that's been running for years and continues to be updated: http://blog.didispace.com/spring-boot-learning-2x/

public class Calc {

public static Integer calc(Integer para) {

try {

Simulates a long execution

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

return to * to;

}

public static void main(String[] args) throws ExecutionException, InterruptedException {

final CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> calc(50))

.thenApply((i) -> Integer.toString(i))

.thenApply((str) -> "\"" + str + "\"")

.thenAccept(System.out::println);

future.get();

}

}

The CompletableFuture.supplyAsync method constructs a CompletedFuture instance, and in the supplieAsync() method, it executes the passed arguments in a new thread. Here it executes the calc() method, which may be slower, but this does not affect the construction speed of the PackageAbleFuture instance, and supplyAsync() returns immediately.

The returned PackageAbleFuture instance can be used as a contract for this call to obtain the final calculation result on any future occasion. Recently sorted out a copy of the latest interview information, which contains the interview questions of each big factory in 2021, do not miss the small partners who plan to jump ship, click to get it!

SupplyAsync is used to provide the return value of the case, CompletableFuture also has an asynchronous call method runAsync (Runnable runnable) that does not require a return value, and generally we use this method more when optimizing the Controller. Both of these methods execute in the ForkJoinPool.common thread pool without specifying a thread pool, and all threads in this thread pool are Daemon threads, so when the main thread ends, these threads exit the system whenever execution is complete.

Core Code:

CompletableFuture.runAsync(() ->

this.afterBetProcessor(betRequest,betDetailResult,appUser,id)

);

Asynchronous calls are implemented using Callable

@RestController

public class HelloController {

private static final Logger logger = LoggerFactory.getLogger(HelloController.class);

@Autowired

private HelloService hello;

@GetMapping("/helloworld")

public String helloWorldController() {

return hello.sayHello();

}

/**

* Asynchronous calls to restful

* When the controller return value is Callable, Springmvc starts a thread to hand over the Callable to TaskExecutor to handle

Then the PatchcherServlet and all the spring interceptors exit the main thread and leave the reaction open

* When the Callable finishes, Springmvc restarts the allocation of a request request, and then the PatcherServlet restarts

* Call and process the return result of the Callable asynchronous execution, and then return the view

*

* @return

*/

@GetMapping("/hello")

public Callable<String> helloController() {

logger.info(Thread.currentThread().getName() + "Enter helloController method");

Callable<String> callable = new Callable<String>() {

@Override

public String call() throws Exception {

logger.info(Thread.currentThread().getName() + "Go to call method");

String say = hello.sayHello();

logger.info(Thread.currentThread().getName() + "Return from helloService method");

return say;

}

};

logger.info(Thread.currentThread().getName() + "Return from helloController method");

return callable;

}

}

Asynchronously calls WebAsyncTask

@RestController

public class HelloController {

private static final Logger logger = LoggerFactory.getLogger(HelloController.class);

@Autowired

private HelloService hello;

/**

* Asynchronous requests with timeouts Customize client timeouts via WebAsyncTask

*

* @return

*/

@GetMapping("/world")

public WebAsyncTask<String> worldController() {

logger.info(Thread.currentThread().getName() + "Enter helloController method");

If the 3s clock does not return, it is considered to have timed out

WebAsyncTask<String> webAsyncTask = new WebAsyncTask<>(3000, new Callable<String>() {

@Override

public String call() throws Exception {

logger.info(Thread.currentThread().getName() + "Go to call method");

String say = hello.sayHello();

logger.info(Thread.currentThread().getName() + "Return from helloService method");

return say;

}

});

logger.info(Thread.currentThread().getName() + "Return from helloController method");

webAsyncTask.onCompletion(new Runnable() {

@Override

public void run() {

logger.info(Thread.currentThread().getName() + "Execute completed");

}

});

webAsyncTask.onTimeout(new Callable<String>() {

@Override

public String call() throws Exception {

logger.info(Thread.currentThread().getName() + " onTimeout");

When the timeout occurs, the exception is thrown directly, allowing the outer layer to handle the timeout exception uniformly

throw new TimeoutException ("call timeout");

}

});

return webAsyncTask;

}

/**

* Asynchronous invocation, exception handling, detailed processing process see MyExceptionHandler class

*

* @return

*/

@GetMapping("/exception")

public WebAsyncTask<String> exceptionController() {

logger.info(Thread.currentThread().getName() + "Enter helloController method");

Callable<String> callable = new Callable<String>() {

@Override

public String call() throws Exception {

logger.info(Thread.currentThread().getName() + "Go to call method");

throw new TimeoutException ("call timed out!");

}

};

logger.info(Thread.currentThread().getName() + "Return from helloController method");

return new WebAsyncTask<>(20000, callable);

}

}

Second, increase the maximum number of connections embedded to Tomcat

@Configuration

public class TomcatConfig {

@Bean

public ConfigurableServletWebServerFactory webServerFactory() {

TomcatServletWebServerFactory tomcatFactory = new TomcatServletWebServerFactory();

tomcatFactory.addConnectorCustomizers(new MyTomcatConnectorCustomizer());

tomcatFactory.setPort(8005);

tomcatFactory.setContextPath("/api-g");

return tomcatFactory;

}

class MyTomcatConnectorCustomizer implements TomcatConnectorCustomizer {

public void customize(Connector connector) {

Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();

Sets the maximum number of connections

protocol.setMaxConnections(20000);

Sets the maximum number of threads

protocol.setMaxThreads(2000);

protocol.setConnectionTimeout(30000);

}

}

}

Third, the use of @ComponentScan () positioning the sweep bag is faster than @SpringBootApplication sweep bag

Fourth, the default tomcat container is changed to Undertow (Jboss server, Tomcat throughput 5000, Undertow throughput 8000)

<exclusions>

<exclusion>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-tomcat</artifactId>

</exclusion>

</exclusions>

to read:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-undertow</artifactId>

</dependency>

Use BufferedWriter for buffering

Sixth, deferred mode to implement asynchronous invocation

@RestController

public class AsyncDeferredController {

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

private final LongTimeTask taskService;

@Autowired

public AsyncDeferredController(LongTimeTask taskService) {

this.taskService = taskService;

}

@GetMapping("/deferred")

public DeferredResult<String> executeSlowTask() {

logger.info(Thread.currentThread().getName() + "Enter executeSlowTask method");

DeferredResult<String> deferredResult = new DeferredResult<>();

Invoke a task that executes for a long time

taskService.execute(deferredResult);

when using deferred.setResult("world"); This method will return from a long task and continue the process in the controller

logger.info(Thread.currentThread().getName() + "Returned from executeSlowTask method");

The timeout callback method

deferredResult.onTimeout(new Runnable(){

@Override

public void run() {

logger.info(Thread.currentThread().getName() + " onTimeout");

Returns a timeout information

deferredResult.setErrorResult("time out!");

}

});

The callback method that completes the processing, whether it is timeout or the processing is successful, will enter this callback method

deferredResult.onCompletion(new Runnable(){

@Override

public void run() {

logger.info(Thread.currentThread().getName() + " onCompletion");

}

});

return deferredResult;

}

}

Asynchronous calls can be intercepted using AsyncHandler Interceptor

@Component

public class MyAsyncHandlerInterceptor implements AsyncHandlerInterceptor {

private static final Logger logger = LoggerFactory.getLogger(MyAsyncHandlerInterceptor.class);

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

return true;

}

@Override

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,

ModelAndView modelAndView) throws Exception {

// HandlerMethod handlerMethod = (HandlerMethod) handler;

logger.info (Thread.currentThread().getName()+ "The service call completes, returns the result to the client");

}

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

throws Exception {

if(null != ex){

System.out.println("An exception occurred:"+ex.getMessage());

}

}

@Override

public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

After interception, the data is re-written back, replacing the original hello world with the following string

String resp = "my name is chhliu!";

response.setContentLength(resp.length());

response.getOutputStream().write(resp.getBytes());

logger.info(Thread.currentThread().getName() + "Enter the afterConcurrentHandlingStarted method");

}

}

I spent 2 months to sort out a set of JAVA development technical data, covering Java basics, distributed, microservices and other mainstream technical materials, including large factory face experience, learning notes, source code handouts, project practice, and explanatory videos.

7 magic tricks to boost Spring Boot throughput
7 magic tricks to boost Spring Boot throughput
7 magic tricks to boost Spring Boot throughput

Hope to help some friends who want to improve their abilities through self-study, get information, scan the code and pay attention to it

Remember to forward + follow + private message

Private Message Reply【2022 Interview Information】

Receive more learning materials