第1章 代理模式概念介紹
1-1 代理模式概念及分類
- 面向對象的設計思維
- 瞭解多態的概念
瞭解反射機制
代理模式基本概念及分類
- 瞭解代理模式開發中應用場景
- 掌握代理模式實現方法
- 理解JDK動態代理實現
代理模式定義:爲其他對象提供一種代理以控制這個對象的訪問。
代理對象起到中介作用,可去掉功能服務或增加額外的服務。
- 遠程代理
爲不同地理的對象,提供局域網代表對象 - 虛擬代理
根據需要將資源消耗很大的對象進行延時,真正需要的時候進行創建 - 保護代理
控制對一個對象的訪問的權限 - 智能代理
提供對目標對象額外服務
第2章 常用代理模式原理
2-1 靜態代理概念及實現
智能引用代理
- 靜態代理
- 動態代理
靜態代理:代理和被代理對象在代理之前是確定的。他們都實現相同的接口或者繼承相同的抽象類。
public interface Moveable {
void move();
}
public class Car implements Moveable {
@Override
public void move() {
//實現開車
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽車行駛中....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Car2 extends Car {
@Override
public void move() {
long starttime = System.currentTimeMillis();
System.out.println("汽車開始行駛....");
super.move();
long endtime = System.currentTimeMillis();
System.out.println("汽車結束行駛.... 汽車行駛時間:"
+ (endtime - starttime) + "毫秒!");
}
}
public class Car3 implements Moveable {
public Car3(Car car) {
super();
this.car = car;
}
private Car car;
@Override
public void move() {
long starttime = System.currentTimeMillis();
System.out.println("汽車開始行駛....");
car.move();
long endtime = System.currentTimeMillis();
System.out.println("汽車結束行駛.... 汽車行駛時間:"
+ (endtime - starttime) + "毫秒!");
}
}
public class Client {
/**
* 測試類
*/
public static void main(String[] args) {
// Car car = new Car();
// car.move();
//使用集成方式
// Moveable m = new Car2();
// m.move();
//使用聚合方式實現
Car car = new Car();
Moveable m = new Car3(car);
m.move();
}
}
通過繼承和聚合兩種方式都能實現代理,但究竟哪種更好呢?
2-2 聚合比繼承更適合代理模式
實現功能疊加
- 方法move()
- 增加方法運行時間處理
- 增加權限管理
- 增加日誌處理
public interface Moveable {
void move();
}
public class Car implements Moveable {
@Override
public void move() {
//實現開車
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽車行駛中....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class CarLogProxy implements Moveable {
public CarLogProxy(Moveable m) {
super();
this.m = m;
}
private Moveable m;
@Override
public void move() {
System.out.println("日誌開始....");
m.move();
System.out.println("日誌結束....");
}
}
public class CarTimeProxy implements Moveable {
public CarTimeProxy(Moveable m) {
super();
this.m = m;
}
private Moveable m;
@Override
public void move() {
long starttime = System.currentTimeMillis();
System.out.println("汽車開始行駛....");
m.move();
long endtime = System.currentTimeMillis();
System.out.println("汽車結束行駛.... 汽車行駛時間:"
+ (endtime - starttime) + "毫秒!");
}
}
public class Client {
/**
* 測試類
*/
public static void main(String[] args) {
Car car = new Car();
CarLogProxy clp = new CarLogProxy(car);
CarTimeProxy ctp = new CarTimeProxy(clp);
ctp.move();
}
}
2-3 瞭解 JDK 動態代理
動態產生代理,實現對不同類,不同方法的代理
ProxySubject->Proxy–>ProxyHandler–>RealSubject
Java動態代理類位於java.lang.reflect包下,一般主要涉及到以下兩個類
- Interface InvocationHandler:該接口中僅定義了一個方法public object invoke(
Object obj,Method method,Object[] args)在實際使用時,第一個參數obj一般是指
代理類,method是被代理的方法,args爲該方法的參數數組。這個抽象方法在代理中
動態實現。 - Proxy:該類即爲動態代理類static Object newProxyInstance(ClassLoader loader,
Class[] interfaces,InvocationHandler h):返回代理類的一個實例,返回後的代理類
可以當作被代理類使用(可使用被代理類的在接口中聲明過的方法)
public interface Moveable {
void move();
}
public class Car implements Moveable {
@Override
public void move() {
//實現開車
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽車行駛中....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TimeHandler implements InvocationHandler {
public TimeHandler(Object target) {
super();
this.target = target;
}
private Object target;
/*
* 參數:
* proxy 被代理對象
* method 被代理對象的方法
* args 方法的參數
*
* 返回值:
* Object 方法的返回值
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
long starttime = System.currentTimeMillis();
System.out.println("汽車開始行駛....");
method.invoke(target);
long endtime = System.currentTimeMillis();
System.out.println("汽車結束行駛.... 汽車行駛時間:"
+ (endtime - starttime) + "毫秒!");
return null;
}
}
public class Test {
/**
* JDK動態代理測試類
*/
public static void main(String[] args) {
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Class<?> cls = car.getClass();
/**
* loader 類加載器
* interfaces 實現接口
* h InvocationHandler
*/
Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),
cls.getInterfaces(), h);
m.move();
}
}
所謂Dynamic Proxy是這樣一種class:
它是在運行時生成的class
該class需要實現一組interface
使用動態代理時,必須實現InvocationHandler接口
動態代理實現步驟
- 創建一個實現接口InvocationHandler的類,它必須實現invoke方法
- 創建被代理的類以及接口
- 調用Proxy的靜態方法,創建一個代理類
newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h) - 通過代理調用方法
2-4 使用 cglib 動態產生代理
- JDK動態代理
- 只能代理實現了接口的類
- 沒有實現接口的類不能實現JDK的動態代理
- CGLIB動態代理
- 針對類來實現代理的
- 對指定目標類產生一個子類,通過方法攔截技術攔截所有父類方法的調用
public class Train {
public void move(){
System.out.println("火車行駛中...");
}
}
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
//設置創建子類的類
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/**
* 攔截所有目標類方法的調用
* obj 目標類的實例
* m 目標方法的反射對象
* args 方法的參數
* proxy代理類的實例
*/
@Override
public Object intercept(Object obj, Method m, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("日誌開始...");
//代理類調用父類的方法
proxy.invokeSuper(obj, args);
System.out.println("日誌結束...");
return null;
}
}
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
Train t = (Train)proxy.getProxy(Train.class);
t.move();
}
}
第3章 自定義類模擬 JDK 動態代理的實現
3-1 模擬 JDK 動態代理實現思路分析及簡單實現
動態代理實現思路
實現功能:通過Proxy的newProxyInstance返回代理對象
- 聲明一段源碼(動態產生代理)
- 編譯源碼(JDK Compiler API),產生新的類(代理類)
- 將這個類load到內存當中,產生一個新的對象(代理對象)
- return 代理對象
3-2 完善動態代理實現
public interface Moveable {
void move();
}
public class Proxy {
public static Object newProxyInstance(Class infce) throws Exception{
String rt = "\r\n";
String methodStr = "";
for(Method m : infce.getMethods()){
methodStr += " @Override" + rt +
" public void " + m.getName() + "() {" + rt +
" long starttime = System.currentTimeMillis();" + rt +
" System.out.println(\"汽車開始行駛....\");" + rt +
" m." + m.getName() + "();" + rt +
" long endtime = System.currentTimeMillis();" + rt +
" System.out.println(\"汽車結束行駛.... 汽車行駛時間:\" " + rt +
" + (endtime - starttime) + \"毫秒!\");" + rt +
" }" ;
}
String str =
"package com.imooc.proxy;" + rt +
"public class $Proxy0 implements " + infce.getName() + " {" + rt +
" public $Proxy0(" + infce.getName() + " m) {" + rt +
" super();" + rt +
" this.m = m;" + rt +
" }" + rt +
" private " + infce.getName() + " m;" + rt +
methodStr + rt +
"}" ;
//產生代理類的java文件
String filename = System.getProperty("user.dir") +"/bin/com/imooc/proxy/$Proxy0.java";
File file = new File(filename);
FileUtils.writeStringToFile(file, str);
//編譯
//拿到編譯器
JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
//文件管理者
StandardJavaFileManager fileMgr =
complier.getStandardFileManager(null, null, null);
//獲取文件
Iterable units = fileMgr.getJavaFileObjects(filename);
//編譯任務
CompilationTask t = complier.getTask(null, fileMgr, null, null, null, units);
//進行編譯
t.call();
fileMgr.close();
//load 到內存
ClassLoader cl = ClassLoader.getSystemClassLoader();
Class c = cl.loadClass("com.imooc.proxy.$Proxy0");
Constructor ctr = c.getConstructor(infce);
return ctr.newInstance(new Car());
}
}
public class Client {
/**
* 測試類
* @throws Exception
*/
public static void main(String[] args) throws Exception {
Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class);
m.move();
}
}
3-3 動態代理實現添加 InvocationHandler
public interface Moveable {
void move();
}
public class Car implements Moveable {
@Override
public void move() {
//實現開車
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽車行駛中....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public interface InvocationHandler {
public void invoke(Object o,Method m);
}
public class TimeHandler implements InvocationHandler {
private Object target;
public TimeHandler(Object target) {
super();
this.target = target;
}
@Override
public void invoke(Object o, Method m) {
try {
long starttime = System.currentTimeMillis();
System.out.println("汽車開始行駛....");
m.invoke(target);
long endtime = System.currentTimeMillis();
System.out.println("汽車結束行駛.... 汽車行駛時間:"
+ (endtime - starttime) + "毫秒!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Proxy {
@SuppressWarnings("unchecked")
public static Object newProxyInstance(Class infce,InvocationHandler h) throws Exception{
String rt = "\r\n";
String methodStr = "";
for(Method m : infce.getMethods()){
methodStr += " @Override" + rt +
" public void " + m.getName() + "() {" + rt +
" try{" + rt +
" Method md = " + infce.getName() + ".class.getMethod(\""
+ m.getName() + "\");" + rt +
" h.invoke(this,md);" +rt+
" }catch(Exception e){ e.printStackTrace();}" + rt +
" }" ;
}
String str =
"package com.imooc.proxy;" + rt +
"import java.lang.reflect.Method;" + rt +
"import com.imooc.proxy.InvocationHandler;" + rt+
"public class $Proxy0 implements " + infce.getName() + " {" + rt +
" public $Proxy0(InvocationHandler h) {" + rt +
" this.h = h;" + rt +
" }" + rt +
" private InvocationHandler h;" + rt+
methodStr + rt +
"}" ;
//產生代理類的java文件
String filename = System.getProperty("user.dir") +"/bin/com/imooc/proxy/$Proxy0.java";
File file = new File(filename);
FileUtils.writeStringToFile(file, str);
//編譯
//拿到編譯器
JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
//文件管理者
StandardJavaFileManager fileMgr =
complier.getStandardFileManager(null, null, null);
//獲取文件
Iterable units = fileMgr.getJavaFileObjects(filename);
//編譯任務
CompilationTask t = complier.getTask(null, fileMgr, null, null, null, units);
//進行編譯
t.call();
fileMgr.close();
//load 到內存
ClassLoader cl = ClassLoader.getSystemClassLoader();
Class c = cl.loadClass("com.imooc.proxy.$Proxy0");
Constructor ctr = c.getConstructor(InvocationHandler.class);
return ctr.newInstance(h);
}
}
public class Client {
/**
* 測試類
* @throws Exception
*/
public static void main(String[] args) throws Exception {
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class,h);
m.move();
}
}
第4章 代理模式總結
4-1 課程總結
- 代理概念、分類及應用場景
- 靜態代理(繼承、聚合)
- JDK動態代理實現日誌處理功能
- 產生動態代理不僅可以使用jdk動態代理,也可以使用其他的方式,如cglib.
- 模擬JDK動態代理實現
常見代理模
- 遠程代理
- 智能引用代理
- 虛擬代理
- 保護代理
智能引用代理
- 日誌處理
- 權限管理
- 事務處理
也叫AOP面向切面編程