動態(tài)代理
代理模式
概念:為其它對象提供一種代理以控制對這個對象的訪問
本質:觸發(fā)被代理安排;但是執(zhí)行者還是被代理本身執(zhí)行(包括動態(tài)代理)
類圖

-
Subject抽象主題角色
可以是抽象類也可以是接口
-
RealSubject具體主題角色
委托角色、被代理角色(業(yè)務邏輯的具體執(zhí)行者)
-
Proxy代理主題角色
委托類、代理類;它負責對真實角色的應用,把所有抽象主題類定義的方法委托給真實主題角色實現(xiàn),并且在真實主題角色處理完畢前后做預處理和善后處理的工作。
抽象主題類
public interface Subject { void method(); }真實主題類
public class RealSubject implements Subject { //實現(xiàn)方法 @Override public void method() { //具體業(yè)務處理 } }代理類
public class Proxy implements Subject { //要代理的對象 private Subject subject; //構造函數(shù)中;傳入要代理的對象 public Proxy(Subject realSubject) { this.subject = realSubject; } //實現(xiàn)接口中定義的方法 @Override public void method() { //預處理 this.before(); //代理的對象執(zhí)行業(yè)務邏輯 this.subject.method(); //善后處理 this.after(); } private void before() { //預處理 } private void after() { //善后處理 } }
為什么使用代理
-
職責清晰
真實的角色就是實現(xiàn)實際的業(yè)務邏輯,不用關心其它非本職的工作
高擴展
補充功能
動態(tài)代理
概念
在實現(xiàn)階段不關心代理誰,而在運行階段才指定代理哪個對象
為什么會產(chǎn)生動態(tài)代理
- 靜態(tài)代理代理類和被代理類實現(xiàn)了相同的接口,導致代碼重復,可擴展性差(被代理類增加方法,代理類也要實現(xiàn)這個方法)
- 靜態(tài)代理代理類只服務于一種類型的代理
動態(tài)代理分類
動態(tài)代理主要分為JDK動態(tài)代理和cglib動態(tài)代理兩大類
JDK動態(tài)代理
必要條件:必須有被代理類的接口
UML圖

抽象被代理角色
public interface Subject {
//業(yè)務操作
public void doSomething(String str);
}
真實被代理角色
public class RealSubject implements Subject{
//業(yè)務操作
@Override
public void doSomething(String str) {
System.out.println("do something------> " + str);
}
}
動態(tài)代理Handler
public class MyInvocationHandler implements InvocationHandler{
//被代理的對象
private Object target;
//通過構造函數(shù)傳入被代理對象
public MyInvocationHandler(Object target) {
this.target = target;
}
//參數(shù)1:proxy 動態(tài)代理對象
//參數(shù)2:method 正在執(zhí)行的方法
//參數(shù)3:args 調用目標方法時傳入的實參
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//執(zhí)行被代理的方法
return method.invoke(this.target, args);
}
測試類1
public class Client1 {
public static void main(String[] args) {
//定義被代理類
Subject realSubject = new RealSubject();
//定義一個handler
InvocationHandler handler = new MyInvocationHandler(realSubject);
//動態(tài)代理類
//第一個參數(shù):用于定義代理類的類加載器;傳入被代理類接口的類加載器(動態(tài))
//注意 第一個參數(shù)加載器 不是handler的加載器,handler不是代理類
//第二個參數(shù):被代理類的接口
//第三個參數(shù):InvocationHandler,用來處理方法的調用
Subject proxy = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
handler);
//代理的行為
proxy.doSomething("Finish");
}
}
輸出:
do something------> Finish
測試類2
public class Client2 {
public static void main(String[] args)
throws Exception {
//定義被代理類
Subject realSubject = new RealSubject();
//定義一個handler
InvocationHandler handler = new MyInvocationHandler(realSubject);
//使用Proxy生成一個動態(tài)代理類ProxyClass
Class<?> proxyClass = Proxy.getProxyClass(Subject.class.getClassLoader(),
new Class[] {Subject.class});
//獲取proxyClass類中一個invocationHandler參數(shù)的構造器
Constructor<?> constructor =
proxyClass.getConstructor(new Class[] {InvocationHandler.class});
//調用constructor 的newInstance方法創(chuàng)建動態(tài)實例
Subject proxy = (Subject) constructor.newInstance(new Object[] {handler});
//代理的行為
proxy.doSomething("Finish");
}
}
輸出:
do something------> Finish
JDK動態(tài)代理分析
Proxy
提供用于創(chuàng)建動態(tài)代理類和代理對象的靜態(tài)方法,它也是所有動態(tài)代理類的父類。
Proxy提供了如下兩個方法來創(chuàng)建動態(tài)代理類和動態(tài)代理實例
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
創(chuàng)建一個動態(tài)代理類所對應的class對象,該代理類將實現(xiàn)interfaces所指定的所有接口。如以上測試類2
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
直接創(chuàng)建一個動態(tài)代理對象,該代理對象實現(xiàn)了interfaces指定的系列接口,執(zhí)行代理對象的每個方法時都會被替換執(zhí)行InvocationHandler對象的invoke方法
動態(tài)代理類由輸出到硬盤
public class CreateProxyClass {
public static void main(String[] args) {
// 使用Proxy生成一個動態(tài)代理類ProxyClass
Class<?> proxyClass = Proxy.getProxyClass(
Subject.class.getClassLoader(),
new Class[] { Subject.class });
//將動態(tài)生成的代理類生成字節(jié)碼;并輸出到D盤Proxy.class
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy",
proxyClass.getInterfaces());
String path = "D://Proxy.class";
try (FileOutputStream out = new FileOutputStream(path);){
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
查看 D://Proxy.class
import com.dwb.design.proxy.demo1.*;
import java.lang.reflect.*;
public final class $Proxy extends Proxy implements Subject
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy(final InvocationHandler invocationHandler) {
super(invocationHandler);
}
public final boolean equals(final Object o) {
try {
return (boolean)super.h.invoke(this, $Proxy.m1, new Object[] { o });
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
public final String toString() {
try {
return (String)super.h.invoke(this, $Proxy.m2, null);
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
//重點查看該方法:我們寫的業(yè)務方法;
public final void doSomething(final String s) {
try {
//對應到 InvocationHandler的三個參數(shù);為什么第一個為動態(tài)代理類
//解釋了,調用方法最后都會調用重寫的InvocationHandler 的invoke方法
super.h.invoke(this, $Proxy.m3, new Object[] { s });
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
public final int hashCode() {
try {
return (int)super.h.invoke(this, $Proxy.m0, null);
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
static {
try {
$Proxy.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
$Proxy.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class<?>[])new Class[0]);
$Proxy.m3 = Class.forName("com.dwb.design.proxy.demo1.Subject").getMethod("doSomething", Class.forName("java.lang.String"));
$Proxy.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class<?>[])new Class[0]);
}
catch (NoSuchMethodException ex) {
throw new NoSuchMethodError(ex.getMessage());
}
catch (ClassNotFoundException ex2) {
throw new NoClassDefFoundError(ex2.getMessage());
}
}
}
運行時動態(tài)代理UML

說明:藍色部分為運行時生成的代理對象$Proxy; 該代理類繼承了Proxy、實現(xiàn)了被代理接口、組合了InvocationHandler;
代理對象執(zhí)行過程:
- 先調用自身實現(xiàn)的被代理接口方法
- 調用組合的invocation對象,invoke方法(參數(shù)1:代理對象,參數(shù)2:被代理接口方法,參數(shù)3:方法參數(shù))
- 反射執(zhí)行被代理方法;invocation對象中invoke方法體內(nèi)method.invoke(this.target, args)