最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

@Transaction,@Async在同一個類中注解失效的原因分析及解決

 更新時間:2021年12月28日 14:43:36   作者:baisq2017  
這篇文章主要介紹了@Transaction,@Async在同一個類中注解失效的原因分析及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

@Transaction @Async在同一個類中注解失效

在同一個類中,一個方法調用另外一個有注解(比如@Async,@Transational)的方法,注解是不會生效的。

比如,下面代碼例子中,有兩方法,一個有@Async注解,一個沒有。第一次如果調用了有注解的test()方法,會啟動@Async注解作用;第一次如果調用testAsync(),因為它內部調用了有注解的test(),如果你以為系統(tǒng)也會為它啟動Async作用,那就錯了,實際上是沒有的。

@Service
public class TestAsyncService {
  public void testAsync() throws Exception {
    test();
  }
  @Async
  public void test() throws InterruptedException{
    Thread.sleep(10000);//讓線程休眠,根據輸出結果判斷主線程和從線程是同步還是異步
    System.out.println("異步threadId:"+Thread.currentThread().getId());
  }
}

運行結果:testAsync()主線程和從線程()test()從線程同步執(zhí)行。

原因:spring 在掃描bean的時候會掃描方法上是否包含@Async注解,如果包含,spring會為這個bean動態(tài)地生成一個子類(即代理類,proxy),代理類是繼承原來那個bean的。

此時,當這個有注解的方法被調用的時候,實際上是由代理類來調用的,代理類在調用時增加異步作用。

然而,如果這個有注解的方法是被同一個類中的其他方法調用的,那么該方法的調用并沒有通過代理類,而是直接通過原來的那個bean,所以就沒有增加異步作用,我們看到的現象就是@Async注解無效。

下面用偽代碼闡述一下原因

@Service  
class A{  
    @Async
    method b(){...}  
    method a(){    //標記1  
        b();  
    }  
}  
//Spring掃描注解后,創(chuàng)建了另外一個代理類,并為有注解的方法加上異步效果  
class proxy$A{  
    A objectA = new A();  
    method b(){    //標記2  
        //異步執(zhí)行Async  
        objectA.b();  
    }  
    method a(){    //標記3  
        objectA.a();    //由于a()沒有注解,所以不會異步執(zhí)行,而是直接調用A的實例的a()方法  
    }  
}  

當我們調用A的bean的a()方法的時候,也是被proxyA攔截,執(zhí)行proxyA攔截,執(zhí)行proxyA.a()(標記3),然而,由以上代碼可知,這時候它調用的是objectA.a(),也就是由原來的bean來調用a()方法了,所以代碼跑到了“標記1”。由此可見,“標記2”并沒有被執(zhí)行到,所以異步執(zhí)行的效果也沒有運行。

說說解決

了解了失效的原因,解決的方法就簡單了(兩種):

  • 把這兩個方法分開到不同的類中
  • 把注解加到類名上面

@Async的實現類方式

詳解:用于開啟異步處理的接口, @Async,使用異步必須再啟動類加上@EnableAsync

方法1:實現接口AsyncConfigurer

@Configuration
public class ThreadConfiguration implements AsyncConfigurer {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    @Bean
    public Executor getAsyncExecutor() {
        executor.setThreadNamePrefix("Zy-TaskExecutor-");
        executor.setCorePoolSize(50);// 核心線程池大小
        executor.setMaxPoolSize(200);// 最大可創(chuàng)建的線程數
        executor.setQueueCapacity(1000);// 隊列最大長度
        executor.setKeepAliveSeconds(300);// 線程池維護線程所允許的空閑時間
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        logger.info("任務線程池初始化...");
        return executor;
    }
    /**
     * 只有在方法上添加@Async的出現異常才會跳到此方法中
     * */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        logger.error("線程執(zhí)行出現異常....");
        return (e, method, arguments) -> logger.error("exception method : " + method.getName() + " message:" + e.getMessage(), e);
    }
    /**
     * 線程監(jiān)控類,訪問/monitor
     * */
    @Bean
    public ServletRegistrationBean threadPoolMonitorServlet() {
        ServletRegistrationBean registration = new ServletRegistrationBean(new HttpServlet() {
            @Override
            protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                resp.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
                PrintWriter writer = resp.getWriter();
                writer.print("corePoolSize : " + executor.getCorePoolSize());
                writer.flush();
                writer.close();
            }
        });
        registration.addUrlMappings("/monitor/*");
        logger.info("springboot線程監(jiān)控start!");
        return registration;
    }
}

方法2:直接注入bean

@Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setMaxPoolSize(200);
        executor.setQueueCapacity(1000);
        executor.setCorePoolSize(50);
        executor.setKeepAliveSeconds(300);
        executor.setThreadNamePrefix("Zy-TaskExecutor-");
        // 線程池對拒絕任務(無線程可用)的處理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        log.info("任務線程池初始化...");
        return executor;
    }

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • 使用ShardingJDBC進行數據分片以及讀寫分離

    使用ShardingJDBC進行數據分片以及讀寫分離

    ShardingJDBC是一個輕量級的Java框架,提供了數據分片、讀寫分離、分布式主鍵生成等數據訪問功能,本文將給大家介紹如何使用ShardingJDBC進行數據分片以及讀寫分離,需要的朋友可以參考下
    2024-01-01
  • 詳談Servlet和Filter的區(qū)別以及兩者在Struts2和Springmvc中的應用

    詳談Servlet和Filter的區(qū)別以及兩者在Struts2和Springmvc中的應用

    下面小編就為大家?guī)硪黄斦凷ervlet和Filter的區(qū)別以及兩者在Struts2和Springmvc中的應用。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • java實現學生成績錄入系統(tǒng)

    java實現學生成績錄入系統(tǒng)

    這篇文章主要為大家詳細介紹了java實現學生成績錄入系統(tǒng),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • 詳解java中if語句和switch的使用

    詳解java中if語句和switch的使用

    這篇文章主要介紹了java中if語句和switch的使用,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • SpringBoot微信消息接口配置詳解

    SpringBoot微信消息接口配置詳解

    這篇文章主要介紹了SpringBoot 微信消息接口配置詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-06-06
  • SpringBoot服務器端解決跨域問題

    SpringBoot服務器端解決跨域問題

    這篇文章主要介紹了SpringBoot服務器端解決跨域問題,幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下
    2020-11-11
  • 全面解析SpringBoot文件上傳功能

    全面解析SpringBoot文件上傳功能

    這篇文章主要為大家全面解析SpringBoot文件上傳功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • SpringMVC實現賬號只能在一處登陸

    SpringMVC實現賬號只能在一處登陸

    這篇文章主要為大家詳細介紹了SpringMVC如何實現賬號只能在一處登陸,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • 深入理解Java Socket通信

    深入理解Java Socket通信

    本篇文章主要介紹了深入理解Java Socket,Java中的網絡通信是通過Socket實現的,Socket分為ServerSocket和Socket兩大類,有興趣的可以了解一下
    2017-02-02
  • Mybatis中的自定義映射resultMap

    Mybatis中的自定義映射resultMap

    在MyBatis中,自定義映射resultMap可以讓你精確控制如何將數據庫返回的結果集映射到Java對象上,本文給介紹了Mybatis之自定義映射resultMap,需要的朋友可以參考下
    2024-03-03

最新評論

滨海县| 萝北县| 宿迁市| 新建县| 佛冈县| 周宁县| 华容县| 枝江市| 白水县| 阳信县| 平度市| 嫩江县| 大厂| 安国市| 宝清县| 昌江| 安庆市| 金华市| 潼关县| 洛扎县| 津市市| 西藏| 墨脱县| 泊头市| 台东市| 胶州市| 确山县| 抚顺市| 莱州市| 巴南区| 汝州市| 汪清县| 临朐县| 凤阳县| 即墨市| 上饶市| 会同县| 郓城县| 临湘市| 嘉祥县| 随州市|