使用Async标签前需要springboot的启动类上使用@EnableAsync开启异步。
在业务方法上添加@Async 该方法返回的类型必须是Object或者void。
package com.cn.zcj.controller.message;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.swing.Spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.MessageSource;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.cn.zcj.container.SpringContextHolder;
/**
* 类职责:国际化语言的测试controller<br/>
*
* <p>Title: MessageController.java</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2018 xxxx有限公司</p>
* <p>Company: xxxx有限公司</p>
*
* <p>Author:Cent.Zcj</p>
* <p>CreateTime:2018年5月22日 上午11:34:13
*/
@Controller
@RequestMapping("/freemarker")
public class FreemarkerController {
private final static String MESSAGE_TEST_PAGE = "fail-ar";
private final static String MYLOCALERESOLVER_CLASS_PATH = "com.cn.zcj.utils.locale.MyLocaleResolver";
//http://127.0.0.1:8080/freemarker/freemarker?i18n_language=en_US
@RequestMapping("/freemarker")
public ModelAndView freemarker(Locale locale,HttpServletRequest request){
HttpSession session = request.getSession();
session.setAttribute("123", "value");;
System.out.println(session.getAttribute("123"));
System.out.println(locale.getLanguage());
ModelAndView modelAndView = new ModelAndView(MESSAGE_TEST_PAGE);
modelAndView.addObject("payment1", "123");
ayscTest();
ayscTest1();
FreemarkerController fController = SpringContextHolder.getBeanByClass(this.getClass());
fController.ayscTest();
fController.ayscTest1();
fController.ayscTest2();
System.out.println("执行freemarker方法的主方法结束!");
return modelAndView;
}
@Async
public void ayscTest() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("进入ayscTest方法!即将睡眠!");
}
@Async
public void ayscTest1() {
System.out.println("进入ayscTest1方法!");
}
@Async
public Object ayscTest2() {
//必须是Object或者是void
System.out.println("进入ayscTest2方法!");
return Boolean.FALSE;
}
@SuppressWarnings("static-access")
@RequestMapping("/defaultLang")
public ModelAndView defaultLang(Locale locale,HttpServletRequest request,HttpServletResponse response) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{
ModelAndView modelAndView = new ModelAndView(MESSAGE_TEST_PAGE);
modelAndView.addObject("payment1", "123");
Locale defaultLocale = new Locale("en_US");
/*locale.setDefault(defaultLocale);*/
Class myLocaleResolver=Class.forName(MYLOCALERESOLVER_CLASS_PATH);
Method setLocaleMethod=myLocaleResolver.getMethod("setLocale",HttpServletRequest.class,HttpServletResponse.class,Locale.class);
setLocaleMethod.invoke(myLocaleResolver.newInstance(),request,response,defaultLocale);
return modelAndView;
}
}
执行结果:
value
en
============http-nio-8080-exec-1============
进入ayscTest方法!即将睡眠!
进入ayscTest1方法!
2019-01-22 20:43:37.000 INFO 5448 --- [nio-8080-exec-1] .s.a.AnnotationAsyncExecutionInterceptor : No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either
进入ayscTest1方法!
执行freemarker方法的主方法结束!
进入ayscTest2方法!
============SimpleAsyncTaskExecutor-1============
进入ayscTest方法!即将睡眠!
/**
* 现象:测试异步方法不生效 ayscTest--->ayscTest1--->主方法实效
* 原因:@Async、@Transactional等注解的实现Aop做的
* 异步方法不能是private aop底层是代理 jdk是代理接口,interface不存在private的方法和属性
* cglib是类代理,private的方法不会存在子类中
* spring容器初始化后加载bean会扫描其方法是否包含上诉的注解,存在则为这个bean创建一个代理类。调用方法时,通过在代理调用处理方法前启动线程、开启事务操作
* 然后本类方法中有调用被上诉注解注释的方法,调用方并不走代理,而是直接调用bean中的方法,故@Async、@Transactional等注解失效
* 解决办法:调用方法调用代理类执行被调用方法
*/
运行结果可以看出@Async标签使用了SimpleAsyncTaskExecutor来执行异步执行任务。
2019-01-22 20:43:37.000 INFO 5448 --- [nio-8080-exec-1] .s.a.AnnotationAsyncExecutionInterceptor : No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either
可以通过指定线程池执行异步方法!!!
package com.cn.zcj.thread.async;
import java.util.concurrent.ThreadPoolExecutor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/**
* 类职责:spring 异步方法执行器<br/>
*
* <p>Title: AsyncTaskExecutor.java</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2017 浙江**信息技术有限公司</p>
* <p>Company: 浙江**信息技术有限公司</p>
*
* <p>Author:Cent</p>
* <p>CreateTime:2019年1月28日上午10:43:54
*/
@Configuration
public class MyAsyncTaskExecutor {
/**
* 自定义异步执行器
*/
@Bean(name="taskExecutor")
public AsyncTaskExecutor getTaskExecutor() {
ThreadPoolTaskExecutor asyncExecutor = new ThreadPoolTaskExecutor();
asyncExecutor.setThreadNamePrefix("异步方法执行器 asyncExecutor-");
asyncExecutor.setMaxPoolSize(20);
asyncExecutor.setMaxPoolSize(20);
asyncExecutor.setQueueCapacity(100);
// 使用默认的丢弃策略
asyncExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
return asyncExecutor;
}
}
由于我们使用默认的丢弃策略,当队列的长度超过100时,会抛出异常java.util.concurrent.RejectedExecutionException。
我们需要在上面的方法中try catch
try {
fController.ayscTest1();
fController.ayscTest2();
} catch (Exception e) {
System.out.println("接收到线程池拒绝的线程!");
}