springboot @Async使用

使用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("接收到线程池拒绝的线程!");
        }

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值