查看“@Async”的源代码
←
@Async
跳转至:
导航
,
搜索
因为以下原因,您没有权限编辑本页:
您所请求的操作仅限于该用户组的用户使用:
用户
您可以查看与复制此页面的源代码。
https://segmentfault.com/a/1190000008981884 https://baijiahao.baidu.com/s?id=1700394969228178875&wfr=spider&for=pc 失效原因 *没有在@SpringBootApplication启动类当中添加注解@EnableAsync注解。 *异步方法使用注解@Async的返回值只能为void或者Future。 *没有走Spring的代理类。因为@Transactional和@Async注解的实现都是基于Spring的AOP,而AOP的实现是基于动态代理模式实现的。那么注解失效的原因就很明显了,有可能因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器。 *同一个类中的方法调用任然需要走proxy PROPAGATION_NOT_SUPPORTED不生效的原因 同一个类中的方法调用任然需要走proxy 直接调用是不会有效果的 第二点和第三点容易犯...... 解决方法: 这里具体说一下第三种情况的解决方法。 *注解的方法必须是public方法。 *方法一定要从另一个类中调用,也就是从类的外部调用,类的内部调用是无效的。 *如果需要从类的内部调用,需要先获取其代理类,下面上代码 <source> @Service public class XxxService{ public void methodA(){ ... XxxService xxxServiceProxy = SpringUtil.getBean(XxxService.class); xxxServiceProxy.methodB(); ... } @Async public void methodB() { ... } </source> *@Transactional 加于private方法, 无效 *@Transactional 加于未加入接口的public方法, 再通过普通接口方法调用, 无效 *@Transactional 加于接口方法, 无论下面调用的是private或public方法, 都有效 *@Transactional 加于接口方法后, 被本类普通接口方法直接调用, 无效 *@Transactional 加于接口方法后, 被本类普通接口方法通过接口调用, 有效 *@Transactional 加于接口方法后, 被它类的接口方法调用, 有效 *@Transactional 加于接口方法后, 被它类的私有方法调用后, 有效 PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。 PROPAGATION_NESTED -- 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。 前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。 ==xml方式启用== component-scan.xml <source> <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:security="http://www.springframework.org/schema/security" xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd" default-autowire="byName" default-lazy-init="false"> <!-- <context:component-scan base-package="com.ling2.core.security.login" /> <context:component-scan base-package="com.ling2.springbatch" /> --> <context:annotation-config /> <context:component-scan base-package="com.deloitte.*" /> <!--使用spring的异步@Async简单定义方式 --> <task:annotation-driven executor="asyncExecutor" /> <task:executor id="asyncExecutor" pool-size="100-10000" queue-capacity="10" /> </beans> </source> ==@Async中的事务No Session found for current thread== 注意ling框架中,代码必须放在server下才有事务否则加了@Transactional也没有用 参考[[MailSendService]] http://blog.csdn.net/blueheart20/article/details/44648667 * @Async调用中的事务处理机制 在@Async标注的方法,同时也适用了@Transactional进行了标注;在其调用数据库操作之时,将无法产生事务管理的控制,原因就在于其是基于异步处理的操作。 那该如何给这些操作添加事务管理呢?可以将需要事务管理操作的方法放置到异步方法内部,在内部被调用的方法上添加@Transactional. 例如: *方法A,使用了@Async/@Transactional来标注,但是无法产生事务控制的目的。 *方法B,使用了@Async来标注, B中调用了C、D,C/D分别使用@Transactional做了标注,则可实现事务控制的目的。 ==参考代码== [[IitDeuctionClaimAsyncServiceImpl]] <source> /** * 一定要批量读取结果, 否则不能达到异步的效果!! * 异步方法和调用类不要在同一个类中 * 注解扫描时,要注意过滤,避免重复实例化,因为存在覆盖问题,@Async就失效了 * @param params * @return * @throws Exception */ public PageResult<DeductionClaimDetailHVo> queryValidateIitDeductionClaimHVoAsync(Map params) throws Exception { PageResult<IitDeductionClaimH> claimHs = findIitDeductionClaimH(params, true); List<Future<DeductionClaimDetailHVo>> futures = new ArrayList<>(); long start = System.currentTimeMillis(); for (IitDeductionClaimH claimH : claimHs.getList()) { Future<DeductionClaimDetailHVo> future = iitDeductionClaimAsyncService.convertIitDeductionClaimHToDeductionClaimDetailHVoAsync(claimH); futures.add(future); } List<DeductionClaimDetailHVo> hVos = new ArrayList<>(); for (Future future : futures) { DeductionClaimDetailHVo vo = (DeductionClaimDetailHVo) future.get(); hVos.add(vo); } logger.info("queryValidateIitDeductionClaimHVoAsync合计消耗时间:"+String.format("任务执行成功,耗时{%s}毫秒", System.currentTimeMillis() - start)); PageResult<DeductionClaimDetailHVo> results = new PageResult<>(); results.setList(hVos); results.setPageIndex(claimHs.getPageIndex()); results.setPageSize(claimHs.getPageSize()); results.setPageIndexString(claimHs.getPageIndexString()); results.setTotal(claimHs.getTotal()); return results; } private void buildDetail_lvo(IitDeductionClaimH iitDeductionClaimH, DeductionClaimDetailHVo result, boolean withAttachment) throws Exception { long prestart = System.currentTimeMillis(); .............................................................................. logger.info("buildDetail_lvo 前序任务消耗时间:"+String.format("任务执行成功,耗时{%s}毫秒", System.currentTimeMillis() - prestart)); List<Future<DeductionClaimDetailHVo>> futures = new ArrayList<>(); long endstart = System.currentTimeMillis(); Future<DeductionClaimDetailHVo> futureMonthAmount = iitDeductionClaimAsyncService.processMonthAmount(result); futures.add(futureMonthAmount); Future<DeductionClaimDetailHVo> futureYearSum = iitDeductionClaimAsyncService.processYearSum(result); futures.add(futureYearSum); Future<DeductionClaimDetailHVo> futurePersionInfo = iitDeductionClaimAsyncService.processPersionInfo(iitDeductionClaimH,result); futures.add(futurePersionInfo); for (Future future : futures) { future.get(); } logger.info("buildDetail_lvo 后续任务消耗时间:"+String.format("任务执行成功,耗时{%s}毫秒", System.currentTimeMillis() - endstart)); } private Future<DxlUserVO> buildDxlUserVO(RemoteUserService remoteUserService, SysUserVO userVO) { ..... return new AsyncResult<>(dxlUserVO); } </source> ==线程池设置== @Bean("buildCusTaskExecutor") public Executor taskExecutor() { ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler(); executor.setPoolSize(50); //最大个数 executor.setThreadNamePrefix("buildCus-"); //线程池名称 //该方法就是这里的关键,用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean,这样这些异步任务的销毁就会先于Redis线程池的销毁 executor.setWaitForTasksToCompleteOnShutdown(true); //该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。 executor.setAwaitTerminationSeconds(3); return executor; } @Async("buildCusTaskExecutor") ==@EnableAsync== 让@Async注解能够生效,还需要在Spring Boot的主程序中配置@EnableAsync
返回至
@Async
。
导航菜单
个人工具
登录
命名空间
页面
讨论
变种
视图
阅读
查看源代码
查看历史
更多
搜索
导航
首页
最近更改
随机页面
技术文档
技术索引
mediawiki技术
easyui
tms
VAT模块详细设计
VAT文档目录结构
概要设计文档
常用链接
修改侧边栏
百度链接
百度云盘
开发者中心
BEA程序
应用组成
mantis
wiki
个人信息
家族族谱
工具
链入页面
相关更改
特殊页面
页面信息