1.主类
import com.cnczsq.mall.elephant.utils.SpringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author : zhang sq
* @date : 2019/10/8 11:24
* SpringBoot注解多线程
**/
@RestController
@RequestMapping("/AsyncTest")
@Api(value = "注解多线程测试", description = "AsyncTest")
public class AsyncTest {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
private Asyncs asyncs;
@GetMapping("/test")
@ApiOperation(value = "线程测试")
@Transactional
public String test() {
//直接调用失效,为单线程
doAsyncMethod();
doAsyncMethod();
doAsyncMethod();
doAsyncMethod();
doAsyncMethod();
//从写类单独管理 ,注入调用,多线程
asyncs.doAsyncMethod();
asyncs.doAsyncMethod();
asyncs.doAsyncMethod();
asyncs.doAsyncMethod();
asyncs.doAsyncMethod();
//内部调用,通过获取bean对象,调用,多线程
AsyncTest bean = SpringUtils.getBean(AsyncTest.class);
bean.doAsyncMethod();
bean.doAsyncMethod();
bean.doAsyncMethod();
bean.doAsyncMethod();
bean.doAsyncMethod();
log.info("主线程执行结束......");
return "SUCCESS";
}
/**
* @Description //同类方法中的异步标签
**/
@Async
public void doAsyncMethod() {
try {
Thread.sleep(2000);
log.info("2直接调用类异步方法执行了......");
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.单独管理线程,注入类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* @author : zhang sq
* @date : 2019/10/8 11:26
**/
@Component
public class Asyncs {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Async
public void doAsyncMethod() {
try {
Thread.sleep(2000);
log.info("1注入类异步方法执行了......");
}catch (Exception e){
e.printStackTrace();
}
}
}
3.SpringUtil工具类,获取spring管理bean
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @author : zhang sq
* @date : 2019/8/30 17:17
**/
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtils.applicationContext == null) {
SpringUtils.applicationContext = applicationContext;
}
}
//获取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//通过name获取 Bean.
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
//通过class获取Bean.
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
//通过name,以及Clazz返回指定的Bean
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
4.测试结果
结果:直接在类里面调用,为单线程处理@Async 不生效 , 可以使用单独管理线程注入调用,或者获取spring管理的Bean对象,调用,都可以达到异步效果;
常见@Async注解不生效原因:
1.@SpringBootApplication启动类当中没有添加注解@EnableAsync注解。
2.没有走Spring的代理类。因为@Transactional和@Async注解的实现都是基于Spring的AOP,而AOP的实现是基于动态代理模式实现的。那么注解失效的原因就很明显了,有可能因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器
3.还有一种说法是 异步方法使用注解@Async的返回值只能为void或者Future。我测试好像不存在这个问题(待定)