程序猿羊 程序猿小杨 2023-07-11 07:30 发表于上海
收录于合集#springboot12个
推荐大家关注一个公众号
程序猿小杨
分享Java相关技术、数据库、Python、职场、感悟、视频资源等干货和学习心得。 如:kettle、ES、redis\mongoDB、springboot、Zookeeper、高并发多线程、中间件、JVM、程序员攻略等。
73篇原创内容
公众号
推荐文章:
1、springBoot对接kafka,批量、并发、异步获取消息,并动态、批量插入库表;
2、SpringBoot用线程池ThreadPoolTaskExecutor异步处理百万级数据;
一、异步执行
1.1、使用@aysnc(异步注解)
参考文章:SpringBoot使用@Async实现多线程异步
1.2、JDK8自带Future类-CompletableFuture
二、增加内嵌Tomcat的最大连接数
package com.wonders.common.config;
import org.apache.coyote.http11.Http11NioProtocol;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Description: TODO:增加内嵌Tomcat的最大连接数
* @Author: yyalin
* @CreateDate: 2023/6/30 9:59
* @Version: V1.0
*/
@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(org.apache.catalina.connector.Connector connector) {
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
//设置最大连接数
protocol.setMaxConnections(15000);
//设置最大线程数
protocol.setMaxThreads(1000);
//设置连接超时时间
protocol.setConnectionTimeout(30000);
}
}
}
三、选择Undertow代替内嵌tomcat容器
默认tomcat容器改为Undertow(Jboss下的服务器),Tomcat的吞吐量为5000,Undertow的吞吐量为8000)。
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
改为:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
四、Async异步调用可用AsyncHandlerInterceptor进行拦截
package com.wonders.interceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Description: TODO:Async异步调用可以使用AsyncHandlerInterceptor进行拦截
* @Author: yyalin
* @CreateDate: 2023/6/30 10:26
* @Version: V1.0
*/
@Component
@Slf4j
public class AsyncHandlerInterImpl implements AsyncHandlerInterceptor {
/**
* 功能描述:拦截于请求刚进入时,进行判断,需要boolean返回值,
* 如果返回true将继续执行,如果返回false,将不进行执行。一般用于登录校验。
* @MethodName: preHandle
* @MethodParam: [request, response, handler]
* @Return: boolean
* @Author: yyalin
* @CreateDate: 2023/6/30 10:33
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler)
throws Exception {
return true;
}
/**
* 功能描述:拦截于方法成功返回后,视图渲染前,可以对modelAndView进行操作
* @MethodName: postHandle
* @MethodParam: [request, response, handler, modelAndView]
* @Return: void
* @Author: yyalin
* @CreateDate: 2023/6/30 10:34
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler,ModelAndView modelAndView) throws Exception {
// HandlerMethod handlerMethod = (HandlerMethod) handler;
log.info(Thread.currentThread().getName()+ "服务调用完成,返回结果给客户端");
}
/**
* 功能描述:拦截于方法成功返回后,视图渲染前,可以进行成功返回的日志记录
* @MethodName: afterCompletion
* @MethodParam: [request, response, handler, ex]
* @Return: void
* @Author: yyalin
* @CreateDate: 2023/6/30 10:35
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex)
throws Exception {
if(null != ex){
log.info("发生异常:"+ex.getMessage());
}
}
/**
* 功能描述:AsyncHandlerInterceptor中的afterConcurrentHandlingStarted()方法,
* 会在Controller方法异步执行时开始执行,
* 但是Interceptor的postHandle()方法则是需要等到Controller的异步执行完之后才能执行
* @MethodName: afterConcurrentHandlingStarted
* @MethodParam: [request, response, handler]
* @Return: void
* @Author: yyalin
* @CreateDate: 2023/6/30 10:36
*/
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request,
HttpServletResponse response,
Object handler)
throws Exception {
// 拦截之后,重新写回数据,将原来的hello world换成如下字符串
String resp = "my name is yyalin!";
response.setContentLength(resp.length());
response.getOutputStream().write(resp.getBytes());
log.info(Thread.currentThread().getName() + " 进入afterConcurrentHandlingStarted方法");
}
}
主要流程如下:
1、拦截器是一个列表,按顺序执行所有拦截器的preHandle方法,一直遇到return false为止,比如:第二个preHandle方法是return false,则第三个以及以后所有拦截器都不会执行。若都是return true,则按顺序加载完preHandle方法。
2、执行主方法(即controller里的接口),若中间抛出异常,则跟return false效果一致,不会继续执行postHandle,只会倒序执行afterCompletion方法。
3、在主方法(即controller里的接口)执行完业务逻辑(页面还未渲染数据)时,按倒序执行postHandle方法。若第三个拦截器的preHandle方法return false,则会执行第二个和第一个的postHandle方法和afterCompletion(postHandle都执行完才会执行这个,也就是view页面渲染完数据后,执行after进行清理工作)方法。(注意:postHandle和afterCompletion都是倒序执行)。
更多详细资料,请关注个人微信公众号或搜索“程序猿小杨”添加。
部分内容借鉴网站(表示感谢): https://blog.csdn.net/vincent_duan/article/details/100880498
https://mp.weixin.qq.com/s/lxDr3PyVcIcEpUC16cNgMg