欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java面試常見模式問題---代理模式

 更新時(shí)間:2021年06月09日 14:07:15   作者:興趣使然の草帽路飛  
代理模式是常用的java設(shè)計(jì)模式,他的特征是代理類與委托類有同樣的接口,代理類主要負(fù)責(zé)為委托類預(yù)處理消息、過濾消息、把消息轉(zhuǎn)發(fā)給委托類,以及事后處理消息
  • 本篇總結(jié)的是 代理設(shè)計(jì)模式,后續(xù)會(huì)經(jīng)常更新~
  • 代理模式最直觀的解釋就是,通過代理,將被代理對(duì)象 “增強(qiáng)”!(即,擴(kuò)展被代理對(duì)象的功能)
  • 代理模式分為靜態(tài)代理,和動(dòng)態(tài)代理:動(dòng)態(tài)代理的代理類是動(dòng)態(tài)生成的 , 靜態(tài)代理的代理類是我們提前寫好的邏輯。
  • Java 中實(shí)現(xiàn)動(dòng)態(tài)代理的方式有 2 種:
  • JDK 動(dòng)態(tài)代理
  • CGLIB 動(dòng)態(tài)代理

1、靜態(tài)代理

靜態(tài)代理角色分析

  • 抽象角色 :一般使用接口或者抽象類來實(shí)現(xiàn)。
  • 真實(shí)角色 :被代理的角色。
  • 代理角色: 代理真實(shí)角色 , 代理真實(shí)角色后 ,一般會(huì)做一些附屬的操作。
  • 調(diào)用方:使用代理角色來進(jìn)行一些操作。

我們以租客租客租房子為例,涉及到的對(duì)象有:租客、中介、房東。(房東即為被代理對(duì)象,中介即為代理對(duì)象)

租客通過中介之手租住房東的房子,代理對(duì)象中介需要尋找租客租房,并從中獲取中介費(fèi)用。

代碼實(shí)現(xiàn)

Rent.java 即抽象角色

// 抽象角色:租房
public interface Rent {
   public void rent();
}

Host.java 即真實(shí)角色

// 真實(shí)角色: 房東,房東要出租房子
public class Host implements Rent{
   public void rent() {
       System.out.println("房屋出租");
  }
}

Proxy.java 即代理角色

//代理角色:中介
public class Proxy implements Rent {
   private Host host;
   public Proxy() { }
   public Proxy(Host host) {
       this.host = host;
  }
   // 租房
   public void rent(){
       seeHouse();
       host.rent();
       fare();
  }
   // 看房
   public void seeHouse(){
       System.out.println("帶房客看房");
  }
   // 收中介費(fèi)
   public void fare(){
       System.out.println("收中介費(fèi)");
  }
}

Client.java 調(diào)用方,即客戶

// 客戶類,一般客戶都會(huì)去找代理!
public class Client {
   public static void main(String[] args) {
       // 房東要租房
       Host host = new Host();
       // 中介幫助房東
       Proxy proxy = new Proxy(host);
       // 你去找中介!
       proxy.rent();
  }
}

靜態(tài)代理的缺點(diǎn)

需要手動(dòng)創(chuàng)建代理類,如果需要代理的對(duì)象多了,那么代理類也越來越多。

為了解決,這個(gè)問題,就有了動(dòng)態(tài)代理 !

2、動(dòng)態(tài)代理

說到動(dòng)態(tài)代理,面試的時(shí)候肯定會(huì)問動(dòng)態(tài)代理的兩種實(shí)現(xiàn)方式:

先來看公共的 UserService 接口,和 UserServiceImpl 實(shí)現(xiàn)類:

/**
 * @author csp
 * @date 2021-06-03
 */
public interface UserService {
    /**
     * 登錄
     */
    void login();
    /**
     * 登出
     */
    void logout();
}
/**
 * @author csp
 * @date 2021-06-03
 */
public class UserServiceImpl implements UserService{
    @Override
    public void login() {
        System.out.println("用戶登錄...");
    }
    @Override
    public void logout() {
        System.out.println("用戶推出登錄...");
    }
}

JDK 動(dòng)態(tài)代理

代碼如下

/**
 * @author csp
 * @date 2021-06-03
 */
public class JDKProxyFactory implements InvocationHandler {
    // 目標(biāo)對(duì)象(被代理對(duì)象)
    private Object target;
    public JDKProxyFactory(Object target) {
        super();
        this.target = target;
    }
    /**
     * 創(chuàng)建代理對(duì)象
     *
     * @return
     */
    public Object createProxy() {
        // 1.得到目標(biāo)對(duì)象的類加載器
        ClassLoader classLoader = target.getClass().getClassLoader();
        // 2.得到目標(biāo)對(duì)象的實(shí)現(xiàn)接口
        Class<?>[] interfaces = target.getClass().getInterfaces();
        // 3.第三個(gè)參數(shù)需要一個(gè)實(shí)現(xiàn)invocationHandler接口的對(duì)象
        Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this);
        return newProxyInstance;
    }
    /**
     * 真正執(zhí)行代理增強(qiáng)的方法
     *
     * @param proxy  代理對(duì)象.一般不使用
     * @param method 需要增強(qiáng)的方法
     * @param args   方法中的參數(shù)
     * @return
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDK 動(dòng)態(tài)代理:登錄/登出前邏輯校驗(yàn)......");
        Object invoke = method.invoke(target, args);
        System.out.println("JDK 動(dòng)態(tài)代理:登錄/登出后日志打印......");
        return invoke;
    }
    public static void main(String[] args) {
        // 1.創(chuàng)建對(duì)象
        UserServiceImpl userService = new UserServiceImpl();
        // 2.創(chuàng)建代理對(duì)象
        JDKProxyFactory jdkProxyFactory = new JDKProxyFactory(userService);
        // 3.調(diào)用代理對(duì)象的增強(qiáng)方法,得到增強(qiáng)后的對(duì)象
        UserService userServiceProxy = (UserService) jdkProxyFactory.createProxy();
        userServiceProxy.login();
        System.out.println("==================================");
        userServiceProxy.logout();
    }
}

輸出結(jié)果如下

JDK 動(dòng)態(tài)代理:登錄/登出前邏輯校驗(yàn)......
用戶登錄...
JDK 動(dòng)態(tài)代理:登錄/登出后日志打印......
==================================
JDK 動(dòng)態(tài)代理:登錄/登出前邏輯校驗(yàn)......
用戶推出登錄...
JDK 動(dòng)態(tài)代理:登錄/登出后日志打印......

CGLIB 動(dòng)態(tài)代理

代碼如下:

/**
 * @author csp
 * @date 2021-06-03
 */
public class CglibProxyFactory implements MethodInterceptor {
    // 目標(biāo)對(duì)象(被代理對(duì)象)
    private Object target;
    // 使用構(gòu)造方法傳遞目標(biāo)對(duì)象
    public CglibProxyFactory(Object target) {
        super();
        this.target = target;
    }
    /**
     * 創(chuàng)建代理對(duì)象
     *
     * @return
     */
    public Object createProxy() {
        // 1.創(chuàng)建Enhancer
        Enhancer enhancer = new Enhancer();
        // 2.傳遞目標(biāo)對(duì)象的class
        enhancer.setSuperclass(target.getClass());
        // 3.設(shè)置回調(diào)操作
        enhancer.setCallback(this);
        return enhancer.create();
    }
    /**
     * 真正執(zhí)行代理增強(qiáng)的方法
     * @param o 代理對(duì)象
     * @param method 要增強(qiáng)的方法
     * @param objects 要增強(qiáng)方法的參數(shù)
     * @param methodProxy 要增強(qiáng)的方法的代理
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib 動(dòng)態(tài)代理:登錄/登出前邏輯校驗(yàn)......");
        Object invoke = method.invoke(target, objects);
        System.out.println("cglib 動(dòng)態(tài)代理:登錄/登出后日志打印......");
        return invoke;
    }
    public static void main(String[] args) {
        // 1.創(chuàng)建對(duì)象
        UserServiceImpl userService = new UserServiceImpl();
        // 2.創(chuàng)建代理對(duì)象
        CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(userService);
        // 3.調(diào)用代理對(duì)象的增強(qiáng)方法,得到增強(qiáng)后的對(duì)象
        UserService userServiceProxy = (UserService) cglibProxyFactory.createProxy();
        userServiceProxy.login();
        System.out.println("==================================");
        userServiceProxy.logout();
    }
}

測(cè)試結(jié)果如下

cglib 動(dòng)態(tài)代理:登錄/登出前邏輯校驗(yàn)......
用戶登錄...
cglib 動(dòng)態(tài)代理:登錄/登出后日志打印......
==================================
cglib 動(dòng)態(tài)代理:登錄/登出前邏輯校驗(yàn)......
用戶推出登錄...
cglib 動(dòng)態(tài)代理:登錄/登出后日志打印......

面試題一:JDK動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理區(qū)別?

① JDK 動(dòng)態(tài)代理本質(zhì)上是實(shí)現(xiàn)了被代理對(duì)象的接口,而 CGLib 本質(zhì)上是繼承了被代理對(duì)象,覆蓋其中的方法。

② JDK 動(dòng)態(tài)代理只能對(duì)實(shí)現(xiàn)了接口的類生成代理,CGLib 則沒有這個(gè)限制。但是 CGLib 因?yàn)槭褂美^承實(shí)現(xiàn),所以 CGLib 所以無法對(duì) final 、private 方法static方法進(jìn)行代理。

③ JDK 動(dòng)態(tài)代理是 JDK 里自帶的,CGLib 動(dòng)態(tài)代理需要引入第三方的 jar 包。

④ 在調(diào)用代理方法上,JDK動(dòng)態(tài)代理是通過反射機(jī)制調(diào)用,CGLib 是通過 FastClass 機(jī)制直接調(diào)用。(看過一篇文章,介紹說 FastClass 簡(jiǎn)單的理解,就是使用一個(gè) index 下標(biāo)作為入?yún)?,可以直接定位到要調(diào)用的方法直接,并進(jìn)行調(diào)用)

在性能上,JDK1.7 之前,由于使用了 FastClass 機(jī)制,CGLib 在執(zhí)行效率上比 JDK 快,但是隨著 JDK 動(dòng)態(tài)代理的不斷優(yōu)化,從 JDK 1.7 開始,JDK 動(dòng)態(tài)代理已經(jīng)明顯比 CGLib 更快了。

面試題二:JDK 動(dòng)態(tài)代理為什么只能對(duì)實(shí)現(xiàn)了接口的類生成代理?

根本原因是通過 JDK 動(dòng)態(tài)代理生成的類已經(jīng)繼承了 Proxy 類,所以無法再使用繼承的方式去對(duì)類實(shí)現(xiàn)代理。

總結(jié)

文章會(huì)不定時(shí)更新,有時(shí)候一天多更新幾篇,如果幫助您復(fù)習(xí)鞏固了知識(shí)點(diǎn),還請(qǐng)三連支持一下,后續(xù)會(huì)一點(diǎn)點(diǎn)的更新!希望大家多多關(guān)注腳本之家的其他內(nèi)容!

  • Java中volatile關(guān)鍵字的作用與用法詳解

    Java中volatile關(guān)鍵字的作用與用法詳解

    volatile關(guān)鍵字雖然從字面上理解起來比較簡(jiǎn)單,但是要用好不是一件容易的事情。這篇文章主要介紹了Java中volatile關(guān)鍵字的作用與用法詳解的相關(guān)資料,需要的朋友可以參考下
    2016-09-09
  • JDK更換IDEA如何修改圖文詳解

    JDK更換IDEA如何修改圖文詳解

    這篇文章主要給大家介紹了關(guān)于JDK更換IDEA如何修改的相關(guān)資料,Java的不同版本的JDK之間存在細(xì)微的差別,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • java編程題之順時(shí)針打印矩陣

    java編程題之順時(shí)針打印矩陣

    這篇文章主要為大家詳細(xì)介紹了java編程題之順時(shí)針打印矩陣,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • SpringBoot2零基礎(chǔ)到精通之?dāng)?shù)據(jù)與頁面響應(yīng)

    SpringBoot2零基礎(chǔ)到精通之?dāng)?shù)據(jù)與頁面響應(yīng)

    SpringBoot是一種整合Spring技術(shù)棧的方式(或者說是框架),同時(shí)也是簡(jiǎn)化Spring的一種快速開發(fā)的腳手架
    2022-03-03
  • java8新特性之方法引用示例代碼

    java8新特性之方法引用示例代碼

    這篇文章主要給大家介紹了關(guān)于java8新特性之方法引用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 舉例分析Python中設(shè)計(jì)模式之外觀模式的運(yùn)用

    舉例分析Python中設(shè)計(jì)模式之外觀模式的運(yùn)用

    這篇文章主要介紹了Python中設(shè)計(jì)模式之外觀模式的運(yùn)用,外觀模式主張以分多模塊進(jìn)行代碼管理而減少耦合,需要的朋友可以參考下
    2016-03-03
  • Java中FileWriter類的常用方法說明

    Java中FileWriter類的常用方法說明

    這篇文章主要介紹了Java中FileWriter類的常用方法說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java的AQS基本原理詳細(xì)分析

    Java的AQS基本原理詳細(xì)分析

    這篇文章主要介紹了Java的AQS基本原理詳細(xì)分析,AQS是Abstract Queued Synchronizer的簡(jiǎn)稱,AQS提供了一種實(shí)現(xiàn)阻塞鎖和一系列依賴FIFO等待隊(duì)列的同步器的框架,本文主要講解分析其基本原理,需要的朋友可以參考下
    2024-01-01
  • 詳解Java springboot 整合Shiro框架

    詳解Java springboot 整合Shiro框架

    這篇文章主要為大家介紹了Java springboot 整合Shiro框架,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • 最新評(píng)論