JavaEE學習日誌持續更新----> 必看!JavaEE學習路線(文章總彙)
動態代理
裝飾者設計模式
裝飾者設計模式(靜態代理)和動態代理的目的:增強原有對象的功能(連接池方法close)
設計模式基於面向對象思想
裝飾思想在IO中大量應用,所有的緩衝流、打印流都叫裝飾流
Reader(原始流) BufferedReader(裝飾流)
如:地暖,就是地面的裝飾者,保留地面原有的承重功能,添加了取暖效果
使用IO流時,new BufferedReader(原始流)
實現裝飾者模式的步驟:
- 被裝飾者和裝飾者必須擁有相同的父類,或者實現相同的接口
- 使用裝飾者的同時,必須提供被裝飾者,new 裝飾者(被裝飾者)
- 方法如果不需要增強,直接使用。需要增強,定義或重寫
自定義裝飾流MyBufferedReader
自定義一個裝飾類
模擬方法readLine()
package com.itheima.decoration;
import java.io.IOException;
import java.io.Reader;
/*
自定義一個裝飾類
模擬方法readLine()
*/
public class MyBufferedReader extends Reader {
private Reader r;
//new MyBufferedReader(FileReader())
public MyBufferedReader(Reader r){
this.r = r;
}
/*
實現讀取文本一行的功能
原有的功能不能破壞,read()可以讀取一個字符
利用原有功能read(),實現讀取一行
*/
public String readLine() throws IOException{
int len = 0;
StringBuilder sb = new StringBuilder();
//read()返回-1,文件結束
while ((len = r.read())!= -1){
//判斷讀取到的字符是不是\r, int和char做運算,char自動變成int
if(len == '\r'){
continue;
}
//判斷讀取到的字符是不是\n
if(len == '\n'){
//這一行讀取結束
//從容器中,取出字符串返回
return sb.toString();
}
//有效的字符,追加緩衝區
sb.append((char)len);
}
//文件讀取結束,判斷緩衝區中是否還有內容
if(sb.length()>0){
return sb.toString();
}
return null;
}
@Override
public int read(char[] chars, int i, int i1) throws IOException {
return 0;
}
@Override
public void close() throws IOException {
r.close();
}
}
測試類
public class Demo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("d:\\1.txt");
//創建自定義的裝飾類,傳遞原始流
MyBufferedReader my = new MyBufferedReader(fr);
String line = null;
while((line=my.readLine())!=null){
System.out.println(line);
}
my.close();
}
}
類加載器
類加載器(ClassLoader)
作用:加載運行的class文件進入內存,並創建class對象。
動態代理原理
Proxy工具類
實現動態代理
- 被代理對象 :ArrayList (方法:add,size,get,remove)
- 代理對象,只要使用被代理對象的方法,通過代理對象
如:代理對象讓別人只能用ArrayList的size方法
Proxy類的方法
static Object newProxyInstance(ClassLoader loader, 類<?>[] interfaces, InvocationHandler h)
返回指定接口的代理實例,該接口將方法調用分派給指定的調用處理程序。
方法參數:
- 傳遞被代理對象的加載器
ArrayList.class.getClassLoader
- 被代理對象實現的所有接口ArrayList.class.getInterfaces
- InvocationHandler接口實現類,代理對象執行的方法
返回值Object:被代理後的對象
InvocationHandler接口方法:
Object invoke(Object proxy, 方法 method, Object[] args)
處理代理實例上的方法調用並返回結果。
方法參數:
proxy
: 被代理的對象ArrayListmethod
:被代理對象的方法,如:add,size,get,removeargs
:被代理對象的方法的實際參數
返回值Objec
t:執行被代理對象的方法的返回值。如:被代理對象的size() 返回長度
實現動態代理:讓被代理對象ArrayList只能調用size()方法
public class Demo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
//方法getProxy,返回被代理後的對象
List<String> proxyList = getProxy(list);
System.out.println(proxyList.size());//3
System.out.println(proxyList.get(0));//java.lang.RuntimeException: 禁止調用該方法
}
/*
定義方法,實現ArrayList對象的動態代理
生成被代理的對象,執行集合的方法size被允許
傳遞被代理的對象,返回代理後的對象
*/
public static List<String> getProxy(ArrayList<String> list){
//傳遞被代理對象的加載器
//傳遞被代理對象實現的接口
//傳遞InvocationHandler接口的實現類
//返回值:被代理後的對象
return (List<String>)Proxy.newProxyInstance(list.getClass().getClassLoader(), list.getClass().getInterfaces(), new InvocationHandler() {
/*
被代理對象執行的方法
調用集合的任意方法,都會執行invoke
proxy:被代理的對象
method:被代理對象調用的方法
objects:調用方法傳遞的實際參數
返回值:被調用方法的返回值
Method類方法:getName()獲取執行的方法名
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//不是size方法,就不讓調用
String name = method.getName();
if("size".equals(name)){
//是size,允許調用方法,size()返回長度
return method.invoke(list,args);
}else {
throw new RuntimeException("禁止調用該方法");
}
}
});
}
}