当项目中的一些非核心业务运行时,影响到用户核心业务的响应时间,导致用户体验下降,这个时候异步操作方案就因由而生了。异步操作方案就是指将非核心业务的耗时操作放到新的线程中异步执行。例如:
new Thread(new Runnable() {
@Override
public void run() {
//耗时操作
}
}).start();
在并发比较小的时候是可以的,但是一旦并发量比较大时,反复创建线程和销毁线程会带来很大系统开销,进而影响整体性能。
SpringBoot 工程中默认支持异步操作,通过异步操作提高核心业务的响应速度。
我们可以在SpringBoot工程启动类的上面,添加启动异步操作的注解(@EnableAsync)描述,代码如下:
@EnableAsync
@SpringBootApplication
public class AsyncApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncApplication.class, args);
}
}
假如此时某个业务方法需要执行异步操作,可以使用@Async注解对方法进行描述,例如写日志的业务,关键代码如下:
@Async
public void saveLog(SysLog entity){
sysLogDao.insertLog(entity);
}
其中,@Async注解描述的方法,在Spring中会认为这是一个异步切入点方法, 在这个切入点方法执行时,底层会通过通知方法获取线程池中的线程,通过池中的线程调用切入点方法(底层默认池类型为ThreadPoolExecutor类型)
假如异步方法有返回值,可以采用AsyncResult对返回值进行封装,例如:
@Async
public Future<Integer> saveLog(SysLog entity){
int result=sysLogDao.insertLog(entity);
return new AsyncResult<Integer>(result);
}
虽然Future可以用于描述一个异步计算的结果,但是这个结果值的获取还是需要阻塞获取。如果阻塞获取其实没意义了,本来想用异步就是为了不阻塞,所以一般建议阻塞方法不写具体返回值。
SpringBoot工程在启动时,会默认配置一个线程池,当默认的线程池配置,不满足我们实际项目需求时,我们可以对线程池进行自定义的配置,SpringBoot配置文件application.properties(或者application.yml)中的关键配置如下:
spring.task.execution.pool.core-size=8
spring.task.execution.pool.max-size=256
spring.task.execution.pool.keep-alive=60000
spring.task.execution.pool.queue-capacity=512
spring.task.execution.thread-name-prefix=async-service-task-
Spring 框架中提供了一种声明式事务的处理方式,此方式基于AOP代理,可以将具体业务逻辑与事务处理进行解耦。也就是让我们的业务代码逻辑不受污染或少量污染,就可以实现事务控制。
SpringBoot工程中,可以通过@Transactional注解描述业务类或方法,进而告诉Spring框架,类中的所有方法或某些方法为切入点方法。这些方法执行时会进行事务控制。例如:
@Transactional(readOnly = false,rollbackFor = Throwable.class)
public class XxxServiceImpl implements XxxService{
@Transactional(readOnly=true) //方法上的事务控制策略优先级高
int deleteById(Long... id)
}
其中,@Transactional常用属性有:
三大组件指的是:监听器(Listener)、过滤器(Filter)与处理器(Servlet)。
使用的时候都是,先定义,然后在注册到spring中(使用@bean的方法注入)。
import org.springframework.stereotype.Component;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* 这里的监听器用于监听服务的启动和销毁
*/
public class DemoListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("服务启动了");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("服务销毁了");
}
}
/**
* 在这里配置javaee规范中的三大组件
*/
@Configuration
public class ComponentConfig {
......
//注册监听器
@Bean
public ServletListenerRegistrationBean servletListenerRegistrationBean(){
ServletListenerRegistrationBean bean=
new ServletListenerRegistrationBean(new DemoListener());
return bean;
}
}
package com.jt.filter;
import javax.servlet.*;
import java.io.IOException;
/**
* javaee规范中的过滤器,对请求和响应数据进行过滤
* 1)统一数据的编码
* 2)统一数据格式校验 (今日头条的灵犬系统)
* 3)统一身份认证
*/
public class DemoFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("==doFilter==");
servletRequest.setCharacterEncoding("UTF-8");
String id= servletRequest.getParameter("id");
System.out.println("id="+id);
filterChain.doFilter(servletRequest,servletResponse);
}
}
package com.jt.config;
/**
* 在这里配置javaee规范中的三大组件
*/
@Configuration
public class ComponentConfig {
....
//注册过滤器
@Bean
public FilterRegistrationBean filterRegistrationBean(){
FilterRegistrationBean bean=
new FilterRegistrationBean(new DemoFilter());
bean.addUrlPatterns("/hello");//对哪个请求进行处理
return bean;
}
}
package com.jt.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* JavaEE规范中的Servlet
*/
public class DemoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("==doGet==");
resp.getWriter().println("hello client");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
//...
}
package com.jt.config;
/**
* 在这里配置javaee规范中的三大组件
*/
@Configuration
public class ComponentConfig {
.....
//注册servlet
@Bean
public ServletRegistrationBean servletRegistrationBean(){
ServletRegistrationBean bean=new ServletRegistrationBean();
bean.setServlet(new DemoServlet());
bean.addUrlMappings("/hello");
return bean;
}
}