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

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