springBoot中异步调用

springBoot中异步调用

上传文件,同时生成预览地址,顺序执行比较慢,考虑用异步调用,文件上传成功后返回页面,并异步调用接口生成预览地址。

1、介绍

异步请求的处理。除了异步请求,一般上我们用的比较多的应该是异步调用。通常在开发过程中,会遇到一个方法是和实际业务无关的,没有紧密性的。比如记录日志信息等业务。这个时候正常就是启一个新线程去做一些业务处理,让主线程异步的执行其他业务。

2、使用方式(基于spring下)

  • 需要在启动类加入@EnableAsync使异步调用@Async注解生效
  • 在需要异步执行的方法上加入此注解即可@Async,默认的线程池中执行

注意事项:

  • 3、注意事项

  • 调用的异步方法,不能为同一个类的方法(包括同一个类的内部类),简单来说,因为Spring在启动扫描时会为其创建一个代理类,而同类调用时,还是调用本身的代理类的,所以和平常调用是一样的。其他的注解如@Cache等也是一样的道理,说白了,就是Spring的代理机制造成的。所以在开发中,最好把异步服务单独抽出一个类来管理。下面会重点讲述。。

    4、什么情况下会导致@Async异步方法会失效?

  1. 调用同一个类下注有@Async异步方法:在spring中像@Async和@Transactional、cache等注解本质使用的是动态代理,其实Spring容器在初始化的时候Spring容器会将含有AOP注解的类对象“替换”为代理对象(简单这么理解),那么注解失效的原因就很明显了,就是因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器,那么解决方法也会沿着这个思路来解决。
  2. 调用的是静态(static )方法
  3. 调用(private)私有化方法

    5、解决4中问题1的方式(其它2,3两个问题自己注意下就可以了)

  4. 将要异步执行的方法单独抽取成一个类,原理就是当你把执行异步的方法单独抽取成一个类的时候,这个类肯定是被Spring管理的,其他Spring组件需要调用的时候肯定会注入进去,这时候实际上注入进去的就是代理类了。
  5. 其实我们的注入对象都是从Spring容器中给当前Spring组件进行成员变量的赋值,由于某些类使用了AOP注解,那么实际上在Spring容器中实际存在的是它的代理对象。那么我们就可以通过上下文获取自己的代理对象调用异步方法

 

3.上代码

  1.  启动类加入@EnableAsync
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.scheduling.annotation.EnableAsync;

@EnableAsync
@MapperScan("com.chinacoal.microservice.impl.mapper")
public class AttachmentApplication {

	public static void main(String[] args) {
		SpringApplication.run(AttachmentApplication.class, args);
	}
	
}
  1. controller
package com.chinacoal.microservice.impl.controller;

import com.chinacoal.microservice.impl.service.impl.SyncAttfileServiceImpl;
import com.chinacoal.microservice.model.attachment.CcmsAttList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * @author sc
 * @createTime 2019/12/18 10:30
 * @description
 */
@RestController
public class SyncController {

    @Autowired
    private SyncAttfileServiceImpl syncServiceImpl;

    /**
     * 顺序 调用
     * @return
     */
   @GetMapping(value = "/test1")
    public  String test1(){
        System.out.println("111111111");
        String test1 = syncServiceImpl.getTest1();
        System.out.println(test1);
        System.out.println("2222222");
         return  "success";
    }


    /**
     * 异步 调用
     * @return
     */
    @GetMapping(value = "/test2")
     public String test2(){
        System.out.println("111111111");
         syncServiceImpl.getTest2();
        System.out.println("2222222");
        return  "success";
    }
    /**
     * 异步 调用 业务逻辑测试
     * @return
     */
    @GetMapping(value = "/test3")
    public  String test3(){
        System.out.println("111111111");
        List<CcmsAttList> list =new ArrayList<>();
        int count=0;
        try {
            Thread.sleep(50);
            System.out.println("ccc");
            count=1;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("bbb");
        if(count ==1){
            CcmsAttList entity=new CcmsAttList();
            entity.setAttId(1+"");
            entity.setAttRefId("A"+1);
            syncServiceImpl.test3(entity.getAttId(),entity.getAttRefId());
        }
        System.out.println("2222222");
        return  "success";
    }

}
  1. service
    package com.chinacoal.microservice.impl.service;
    
    /**
     * @author sc
     * @createTime 2019/12/18 11:15
     * @description
     */
    public interface SyncAttfileService {
    
        /**
         * 异步 生成预览地址
         * @param attId  附件id
         * @param attRefId 附件地址
         */
        public void syncPreview(String attId, String attRefId);
    
    
        public String getTest1();
    
        public String getTest2();
    
        public void test3(String attId, String attRefId);
    
    }
    

    serviceImpl

    package com.chinacoal.microservice.impl.service.impl;
    
    import com.chinacoal.microservice.api.FileManagerClient;
    import com.chinacoal.microservice.impl.mapper.CcmsAttListMapper;
    import com.chinacoal.microservice.impl.service.SyncAttfileService;
    import com.chinacoal.microservice.model.attachment.CcmsAttList;
    import com.chinacoal.microservice.util.result.CodeMsg;
    import com.chinacoal.microservice.util.result.Result;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    /**
     * @author sc
     * @createTime 2019/12/18 10:39
     * @description
     */
    @Service
    @Slf4j
    public class SyncAttfileServiceImpl  implements SyncAttfileService {
    
        @Resource
        private FileManagerClient fileManagerServiceClient;
    
        @Autowired
        private CcmsAttListMapper ccmsAttListMapper;
    
        /**
         * 顺序调用
         * @return
         */
       public String getTest1(){
            try {
                Thread.sleep(1000);
                System.out.println("顺序调用");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return Thread.currentThread().getName()+"顺序调用执行完毕";
        }
    
        /**
         * 异步调用  有@Async注解的方法,默认就是异步执行的,会在默认的线程池中执行,但是此方法不能在本类调用;启动类需添加直接开启异步执行@EnableAsync
         * @return
         */
        @Async
        public String getTest2(){
            try {
                Thread.sleep(1000);
                System.out.println("异步调用");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return Thread.currentThread().getName()+"异步调用执行完毕";
        }
        /**
         * 异步调用  有@Async注解的方法,默认就是异步执行的,会在默认的线程池中执行,但是此方法不能在本类调用;启动类需添加直接开启异步执行@EnableAsync
         * @return
         */
        @Async
        public void test3(String attId, String attRefId){
            log.info("异步生成文件预览地址接受参数附件id :"+attId +" 附件引用地址:"+attRefId);
            try {
                Thread.sleep(1000);
                System.out.println("异步调用"+attId);
            } catch (Exception e) {
                e.printStackTrace();
                log.info("调文件管理服务异常:原文件转其他文件" +CodeMsg.ERROR_FILE_UPLOAD.fillArgs(e.getMessage()));
            }
        }
    
    
        /**
         * 异步 生成预览地址
         * @param attId
         * @param attRefId
         */
        @Override
        @Async
        public void syncPreview(String attId, String attRefId){
            log.info("异步生成文件预览地址接受参数附件id :"+attId +" 附件引用地址:"+attRefId);
            //原文件 转其他文件
            Result<String> resultUpload = null;
            try {
                CcmsAttList ccmsAttList=new CcmsAttList();
                resultUpload = fileManagerServiceClient.preview(attRefId);
                int code = resultUpload.getCode();
                if(code != 10000){
                    log.info("调文件管理服务异常:原文件转其他文件" +resultUpload.getMsg());
                    return ;
                }
                String previewPath= resultUpload.getData();
                log.info("原文件转其他文件返回值:"+previewPath);
                ccmsAttList.setAttId(attId);
                ccmsAttList.setPreviewPath(previewPath);
                ccmsAttListMapper.updateById(ccmsAttList);
            } catch (Exception e) {
                e.printStackTrace();
                log.info("调文件管理服务异常:原文件转其他文件" +CodeMsg.ERROR_FILE_UPLOAD.fillArgs(e.getMessage()));
            }
        }
    
    
    }
    

    测试

调用test1  同步执行

 

 

测试test2 异步调用

测试test3 异步

 

 参照文档

https://blog.csdn.net/zhanaolu4821/article/details/80941825

https://blog.csdn.net/weixin_39800144/article/details/79046237

https://www.cnblogs.com/baixianlong/p/10661591.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章