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

Java設(shè)計模式之代理模式與@Async異步注解失效的解決

 更新時間:2022年07月27日 09:34:43   作者:kaico2018  
代理模式是Java常見的設(shè)計模式之一。所謂代理模式是指客戶端并不直接調(diào)用實際的對象,而是通過調(diào)用代理,來間接的調(diào)用實際的對象

自定義注解實現(xiàn)方式

JDK動態(tài)代理實現(xiàn)自定義異步注解(@Async)

實現(xiàn)思路:

  • 首先自定義一個注解,命名為:ExtAsync
  • 實現(xiàn)一個接口,這個接口的實現(xiàn)類就是被代理類
  • 實現(xiàn)jdk的InvocationHandler接口,根據(jù)反射獲取目標(biāo)方法的信息,判斷是否有異步注解,如果有則另起一個線程異步執(zhí)行去。

1、異步注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExtAsync {
}

2、接口和實現(xiàn)類

//接口
public interface OrderService {
    String addOrder();
    void addOrderLog();
}
//實現(xiàn)類
public class OrderServiceImpl implements OrderService {
    private OrderService orderServiceProxy;
    public String addOrder() {
        System.out.println(Thread.currentThread().getName() + ">>>流程1");
        orderServiceProxy.addOrderLog();
        System.out.println(Thread.currentThread().getName() + ">>>流程3");
        return "addOrder";
    }
    @ExtAsync
    public void addOrderLog() {
        System.out.println(Thread.currentThread().getName() + ">>>流程2");
    }
    public void setOrderServiceProxy(OrderService orderServiceProxy) {
        this.orderServiceProxy = orderServiceProxy;
    }
}

3、JDK動態(tài)代理需要實現(xiàn)的InvocationHandler接口類

public class MayiktInvocationHandler implements InvocationHandler {
    /**
     * 目標(biāo)對象
     */
    private Object target;
    /**
     * 定義線程池
     */
    private ExecutorService executorService;
    public MayiktInvocationHandler(Object target) {
        this.target = target;
        executorService = Executors.newFixedThreadPool(10);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //使用反射技術(shù)執(zhí)行目標(biāo)方法
//        ExtAsync extAsync = method.getDeclaredAnnotation(ExtAsync.class);
        //根據(jù)接口的信息查找到目標(biāo)對象的的方法
        Method methodImpl = target.getClass().getMethod(method.getName(), method.getParameterTypes());
        ExtAsync extAsync = methodImpl.getDeclaredAnnotation(ExtAsync.class);
        if (extAsync == null) {
            // 該方法上沒有加上異步注解,則直接調(diào)用目標(biāo)方法
            return method.invoke(target, args);
        }
        // 單獨開啟一個線程異步處理目標(biāo)方法
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    method.invoke(target, args);
                } catch (Exception e) {
                }
            }
        });
        return null;
    }
    /**
     * 生成代理類
     *
     * @param <T>
     * @return
     */
    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }
}

4、測試類

public class Test001 {
    public static void main(String[] args) {
        OrderServiceImpl orderServiceImpl = new OrderServiceImpl();
        MayiktInvocationHandler mayiktInvocationHandler =
                new MayiktInvocationHandler(orderServiceImpl);
        // 使用Jdk生成代理對象
        OrderService orderServiceProxy = mayiktInvocationHandler.getProxy();
        // 將代理設(shè)置給目標(biāo)對象
        orderServiceImpl.setOrderServiceProxy(orderServiceProxy);
        orderServiceProxy.addOrder();
    }
}

總結(jié)分析:加上自定義的異步注解,查看輸出的日志順序,然后注釋掉異步注解,再看輸出的日志順序。

SpringAOP實現(xiàn)自定義異步注解

核心在于AOP切面類上:攔截加了自定義異步注解的方法,看起一個線程執(zhí)行目標(biāo)方法。

@Component
@Aspect
@Slf4j
public class ExtAsyncAop {
    private ExecutorService executorService;
    public ExtAsyncAop() {
        executorService = Executors.newFixedThreadPool(10);
    }
    @Around(value = "@annotation(com.kaico.designMode.proxy.aopAsync.ext.ExtAsync)")
    public void doBefore(ProceedingJoinPoint joinPoint) throws Throwable {
        // 直接獲取到方法上有加上ExtAsync
        log.info(">>>攔截到我們方法上有加上ExtAsync");
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                // 執(zhí)行我們的目標(biāo)方法
                try {
                    joinPoint.proceed();
                } catch (Throwable throwable) {
                    throwable.printStackTrace();
                }
            }
        });
    }
}

Spring的異步注解@Async失效分析

注解原理:AOP技術(shù)–》動態(tài)代理技術(shù)

Spring中是如何綜合使用Cglib和Jdk動態(tài)代理呢?

  • 如果被代理類有實現(xiàn)接口的情況下默認(rèn)采用 Jdk動態(tài)代理 可以轉(zhuǎn)換為Cglib
  • 如果被代理類沒有實現(xiàn)接口的情況下采用Cglib

異步注解失效:

1、如果控制類(加了@RestController的類)中的有方法加上了異步注解,并且有實現(xiàn)接口的情況下,則采用JDK動態(tài)代理,控制類沒有注冊到SpringMVC容器中。

2、如果控制類(加了@RestController的類)中有的方法加上了異步注解,但是沒有實現(xiàn)接口的情況下,則采用CGLIB動態(tài)代理,控制類可以注冊到SpringMVC容器,但是異步注解會失效。

為什么失效?

底層使用動態(tài)代理模式,在代理類創(chuàng)建線程,如果沒有經(jīng)過代理類就不會創(chuàng)建線程,所以必須從Sping中獲取代理對象,通過代理對象.方法,才會經(jīng)過代理類實現(xiàn)創(chuàng)建線程異步操作。因為在控制類的方法增加異步注解的時候,調(diào)用該方法時調(diào)用的不是代理對象的方法,而是當(dāng)前對象的方法。

1、不要在當(dāng)前類直接使用異步注解,因為沒有經(jīng)歷過代理類。

2、官方建議新建一個類來進(jìn)行異步操作。

原理: 如果在控制類(實現(xiàn)接口的類)上的方法上加了異步注解,采用JDK動態(tài)代理技術(shù),代理基于接口實現(xiàn),而接口中沒有加上@RestController注解,所以代理對象無法注冊到SpringMVC容器中。反之,如果控制類沒有實現(xiàn)接口,則采用CGLIB動態(tài)代理,生成的代理對象是采用繼承目標(biāo)對象(@RestController也會繼承過來),這時代理對象可以注入帶SpringMVC容器中。

到此這篇關(guān)于Java設(shè)計模式之代理模式與@Async異步注解失效的解決的文章就介紹到這了,更多相關(guān)Java代理模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring?Boot?Admin?監(jiān)控指標(biāo)接入Grafana可視化的實例詳解

    Spring?Boot?Admin?監(jiān)控指標(biāo)接入Grafana可視化的實例詳解

    Spring Boot Admin2 自帶有部分監(jiān)控圖表,如圖,有線程、內(nèi)存Heap和內(nèi)存Non Heap,這篇文章主要介紹了Spring?Boot?Admin?監(jiān)控指標(biāo)接入Grafana可視化,需要的朋友可以參考下
    2022-11-11
  • MP(MyBatis-Plus)實現(xiàn)樂觀鎖更新功能的示例代碼

    MP(MyBatis-Plus)實現(xiàn)樂觀鎖更新功能的示例代碼

    這篇文章主要介紹了MP(MyBatis-Plus)實現(xiàn)樂觀鎖更新功能的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • SpringBoot使用JavaMailSender實現(xiàn)發(fā)送郵件

    SpringBoot使用JavaMailSender實現(xiàn)發(fā)送郵件

    JavaMailSender是Spring Framework中的一個接口,用于發(fā)送電子郵件,本文主要為大家詳細(xì)介紹了SpringBoot如何使用JavaMailSender實現(xiàn)發(fā)送郵件,需要的可以參考下
    2023-12-12
  • Mybatis自定義攔截器和插件開發(fā)詳解

    Mybatis自定義攔截器和插件開發(fā)詳解

    這篇文章主要給大家介紹了關(guān)于Mybatis自定義攔截器和插件開發(fā)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Java Swing組件下拉菜單控件JComboBox用法示例

    Java Swing組件下拉菜單控件JComboBox用法示例

    這篇文章主要介紹了Java Swing組件下拉菜單控件JComboBox用法,結(jié)合具體實例形式分析了Swing組件下拉菜單控件JComboBox的具體定義、使用方法及相關(guān)使用注意事項,需要的朋友可以參考下
    2017-11-11
  • springboot對壓縮請求的處理方法

    springboot對壓縮請求的處理方法

    這篇文章主要介紹了springboot對壓縮請求的處理,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-05-05
  • Java中抽象類和接口的用法詳解

    Java中抽象類和接口的用法詳解

    這篇文章主要為大家詳細(xì)介紹了Java中抽象類和接口的使用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-08-08
  • 詳解IDEA中SpringBoot整合Servlet三大組件的過程

    詳解IDEA中SpringBoot整合Servlet三大組件的過程

    這篇文章主要介紹了詳解IDEA中SpringBoot整合Servlet三大組件的過程,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • 一文帶你入門JDK8新特性——Lambda表達(dá)式

    一文帶你入門JDK8新特性——Lambda表達(dá)式

    這篇文章主要介紹了JDK8新特性——Lambda表達(dá)式的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)JAVA開發(fā),感興趣的朋友可以了解下
    2020-08-08
  • java如何連接數(shù)據(jù)庫executeUpdate()和executeQuery()

    java如何連接數(shù)據(jù)庫executeUpdate()和executeQuery()

    這篇文章主要介紹了java如何連接數(shù)據(jù)庫executeUpdate()和executeQuery(),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03

最新評論

历史| 广平县| 南城县| 沙湾县| 灵丘县| 阿尔山市| 罗山县| 石渠县| 自贡市| 蒲江县| 宜章县| 南投县| 易门县| 邓州市| 沁阳市| 高唐县| 日照市| 梅州市| 奉化市| 金寨县| 丰原市| 大足县| 龙泉市| 奎屯市| 南郑县| 寿光市| 连山| 家居| 甘德县| 淮北市| 皋兰县| 汉寿县| 行唐县| 垫江县| 司法| 奉新县| 永昌县| 壶关县| 江安县| 馆陶县| 锡林郭勒盟|