010 Spring Boot@Async异步执行方法

Spring中用@Async注解标记的方法,称为异步方法,它会在调用方的当前线程之外的独立的线程中执行,其实就相当于我们自己new Thread(()-> System.out.println("hello world !"))这样在另一个线程中去执行相应的业务逻辑。

@Async注解使用条件

  1. @Async注解一般用在类的方法上,如果用在类上,那么这个类所有的方法都是异步执行的;
  2. 所使用的@Async注解方法的类对象应该是Spring容器管理的bean对象;
  3. 调用异步方法类上需要配置上注解@EnableAsync(不讨好理解,看一下下面的案例就明白了)

 

如果在控制器里启动异步线程,会被视为一起请求,异步线程的启动也被视为一次请求但application为空,因此如果像009文档那样做了AOP全局WEB请求日志记录,那么请在里面添加非空判断,就像下列这样:

/**
 * 用AOP记录WEB请求日志
 */
@Aspect
@Component
@Log4j
public class WebLogAspect {
    /**
     * 定义切点,切入指定包下的全部类的全部方法
     */
    @Pointcut("execution(* com.blacktv.springboot.Controller.*.*(*))")
    public void webLog() {}

    /**
     * 前置增强拦截请求参数信息
     */
    @Before("webLog()")
    public void webLogBefore(JoinPoint joinPoint) {
        ServletRequestAttributes app = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        /**
         * 如果在控制器里调用了异步线程,这里必须加上非空判断,异步线程的启动也被视为一次请求但application为空,
         * 如果这里不加一个非空判断,会抛出null异常导致异步线程启动失败。
         */
        if (app == null)
            return;
        HttpServletRequest request = app.getRequest();
        //记录URL、IP、访问方法
        log.info("URL:" + request.getRequestURI());
        log.info("IP:" + request.getRemoteAddr());
        log.info("HTTP_METHOD:" + request.getMethod());
        //记录请求参数
        Enumeration enumeration = request.getParameterNames();
        while (enumeration.hasMoreElements()) {
            String key = enumeration.nextElement();
            log.info("key:" + key + " ,value:" + request.getParameter(key));
        }
    }

    /**
     * 后置增强,记录返回内容
     *
     * @param result
     */
    @AfterReturning(returning = "result", pointcut = "webLog()")
    public void webLohA(Object result) {
        // 后置增强也添加非空判断
        if (result == null)
            return;
        log.info("result:" + result);
    }
}

异步案例:

/**
 * 在控制器中启动异步线程,要想调用异步线程类需要在本类标注@EnableAsync
 */
@RestController
@EnableAsync
public class TestA {
    @Autowired
    private TestB testB;
    /**
     * 用户传入秒数,决定异步线程的休眠时间
     *
     * @param second
     * @return
     */
    @GetMapping(value = "/test")
    public String test(int second) throws InterruptedException {
        if(second <= 0)
            return "休眠时间不能小于等于0秒";
        testB.test(second); //启动异步线程 
        return "异步线程已启动,休眠时间" + second + "s";
    }
}

/**
 * 异步多线程类,需要用@Async标注
 */
@Async
@Service
public class TestB {
    /**
     * 每隔指定秒数输出一次
     *
     * @param second 休眠时间,单位秒
     * @throws InterruptedException
     */
    public void test(int second) throws InterruptedException {
        while (true) {
            Thread.sleep(second * 1000);//休息second秒
            System.out.println("TestB计时" + second + "秒");
        }
    }
}

启动跑一下:

010 Spring Boot@Async异步执行方法_第1张图片

010 Spring Boot@Async异步执行方法_第2张图片

你可能感兴趣的:(boot,spring,boot,aop,java)