【源碼分析設計模式 8,1307頁字節跳動Java面試全套真題解析火了

安卓馬安 2021-09-20 00:04:11 阅读数:773

分析 模式 8,1307 java 全套

六、動態代理

======

1、動態代理特點


  • 代理對象不需要實現接口,但是目標對象要實現接口;

  • 代理對象的生成,是利用JDK的API,動態的在內存中構建代理對象;

  • 動態代理也叫JDK代理或接口代理;

2、使用JDK實現動態代理


jdk實現動態代理必須有實現接口InvocationHandler的處理類,用於執行被代理類的方法。

(1)接口IMovie


package designMode.advance.proxy.dynamic;
public interface IMovie {
void play(String movieName);
void advertising(Boolean isBoforMovie,String txt);
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

(2)實現類Movie


package designMode.advance.proxy.dynamic;
public class Movie implements IMovie {
@Override
public void play(String movieName) {
System.out.println("您正在觀看電影《"+movieName+"》");
}
@Override
public void advertising(Boolean isBoforMovie, String txt) {
if(isBoforMovie){
System.out.println("影片馬上開始,"+txt);
}else{
System.out.println("影片正片已經結束,馬上彩蛋環節,不要離開哦,"+txt);
}
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.

(3)代理類MovieProxy


package designMode.advance.proxy.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MovieProxy {
private Object target;
public MovieProxy(Object target) {
this.target = target;
}
/*
*
* public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler h) * 1、ClassLoader loader:指定當前目標對象使用的類加載器,獲取加載器的方法; * 2、Class<?>[] interfaces:目標對象實現的接口類型,使用泛型方式確認類型;
* 3、InvocationHandler h:事情處理,執行目標對象的方法時,會觸發事情處理器方法,會吧當前
*
* */
public Object getProxyInstance(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK代理開始~~");
//反射機制調用目標對象的方法
Object ret = method.invoke(target,args);
System.out.println("JDK代理結束~~");
return ret;
}
});
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.

(4)測試類


package designMode.advance.proxy.dynamic;
public class Client {
public static void main(String[] args) {
IMovie target = new Movie();
IMovie proxyInstance = (IMovie) new MovieProxy(target).getProxyInstance();
System.out.println("proxyInstance="+proxyInstance.getClass());
proxyInstance.advertising(true,"素小暖入駐CSDN啦,快來關注我啊");
proxyInstance.play(" 速度與激情8 ");
proxyInstance.advertising(false,"素小暖入駐CSDN啦,快來關注我啊");
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.

(5)控制臺輸出

【源碼分析設計模式 8,1307頁字節跳動Java面試全套真題解析火了_後端

3、使用JDK實現動態代理源碼分析


(1)代理對象會在內部緩存,如果沒有緩存則會由ProxyClassFactory生成。

首先會做接口校驗,比如是否可以從提供的classLoader獲取接口

【源碼分析設計模式 8,1307頁字節跳動Java面試全套真題解析火了_後端_02

(2) invoke方法的具體實現類,DynamicProxy

【源碼分析設計模式 8,1307頁字節跳動Java面試全套真題解析火了_Java_03

?(3)DynamicProxy類,調用invoke方法,生成代理對象,實現動態代理,並存入緩存

【源碼分析設計模式 8,1307頁字節跳動Java面試全套真題解析火了_Java_04

?七、cglib代理

==========

JDK實現動態代理需要實現類通過接口定義業務方法,對於沒有接口的類,如何實現動態代理呢,這就需要CGLib了。CGLib采用了非常底層的字節碼技術,其原理是通過字節碼技術為一個類創建子類,並在子類中采用方法攔截的技術攔截所有父類方法的調用,順勢織入橫切邏輯。但因為采用的是繼承,所以不能對final修飾的類進行代理。JDK動態代理與CGLib動態代理均是實現Spring AOP的基礎。

1、引入jar包


【源碼分析設計模式 8,1307頁字節跳動Java面試全套真題解析火了_Java_05

2、普通類Movie



package designMode.advance.proxy.cglib;
public class Movie {
public void play(String movieName) {
System.out.println("我是cglib代理,不需要實現接口,您正在觀看電影《"+movieName+"》");
}
public void advertising(Boolean isBoforMovie, String txt) {
if(isBoforMovie){
System.out.println("影片馬上開始,"+txt);
}else{
System.out.println("影片正片已經結束,馬上彩蛋環節,不要離開哦,"+txt);
}
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

3、代理類MovieProxy



package designMode.advance.proxy.cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MovieProxy implements MethodInterceptor {
//維護一個目標對象
private Object target;
//構造器,傳入一個被代理的對象
public MovieProxy(Object target) {
this.target = target;
}
//返回一個代理對象: 是 target 對象的代理對象
public Object getProxyInstance() {
//1. 創建一個工具類
Enhancer enhancer = new Enhancer();
//2. 設置父類
enhancer.setSuperclass(target.getClass());
//3. 設置回調函數
enhancer.setCallback(this);
//4. 創建子類對象,即代理對象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib代理開始~~");
Object returnVal = method.invoke(target,objects);
System.out.println("Cglib代理結束~~");
return returnVal;
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.

4、測試類



package designMode.advance.proxy.cglib;
public class Client {
public static void main(String[] args) {
//創建目標對象
Movie target = new Movie();
//獲取到代理對象,並且將目標對象傳遞給代理對象
Movie proxyInstance = (Movie)new MovieProxy(target).getProxyInstance();
//執行代理對象的方法,觸發intecept 方法,從而實現 對目標對象的調用
proxyInstance.advertising(true,"素小暖入駐CSDN啦,快來關注我啊");
proxyInstance.play(" 速度與激情8 ");
proxyInstance.advertising(false,"素小暖入駐CSDN啦,快來關注我啊");
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

5、控制臺輸出


【源碼分析設計模式 8,1307頁字節跳動Java面試全套真題解析火了_程序員_06

八、幾種常見的代理模式介紹

=============

1、防火牆代理


內網通過代理穿透防火牆,實現對公網的訪問。

2、緩存代理


當請求圖片文件等資源時,先到緩存中去,如果沒有再到數據庫中取,然後緩存。

3、遠程代理


遠程對象的本地代錶,通過它可以把遠程對象當做本地對象來調用。

4、同步代理


主要在多線程編程中使用,完成多線程間的同步工作。

九、mybatis中的代理模式

===============

下面我們進入configuration.addMapper(mapperInterface);這個方法看看源碼如何實現


public <T> void addMapper(Class<T> type) {
### 最後
金三銀四到了,送上一個小福利!
**[CodeChina開源項目:【一線大廠Java面試題解析+核心總結學習筆記+最新講解視頻】](https://ali1024.coding.net/public/P7/Java/git)**
![【源碼分析設計模式 8,1307頁字節跳動Java面試全套真題解析火了_Java_07](https://s2.51cto.com/images/20210919/1632066979862886.jpg)
![【源碼分析設計模式 8,1307頁字節跳動Java面試全套真題解析火了_後端_08](https://s9.51cto.com/images/20210919/1632066979317274.jpg)
![【源碼分析設計模式 8,1307頁字節跳動Java面試全套真題解析火了_Java_09](https://s6.51cto.com/images/20210919/1632066980476814.jpg)

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
版权声明:本文为[安卓馬安]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/09/20210920000411156i.html