圖片來自必應java
代理模式(Proxy):Proxy是「代理人」的意思,意思是有一些工做不必定須要本人去完成,而是能夠委託代理人去完成。代理模式屬於結構型模式,至關於咱們爲委託對象提供了一個訪問控制,當外部客戶端想要訪問委託對象的時候,經過代理對象訪問。bash
首先咱們來看一下代理模式的UML類圖:網絡
從UML類圖中能夠看到,當客戶端想要訪問一個對象的時候,能夠經過訪問Proxy這個代理類,這樣就達到了訪問控制的目的。下面咱們經過一個例子來講明一下代理模式的具體做用。好比如今有一個圖書館,咱們能夠從圖書館中借書或者買書,那麼咱們能夠定義一個接口類型以下,對比UML類圖中的Subject:app
public interface ILibrary{
void borrow();
void buy();
}
複製代碼
那麼咱們能夠定義一個ILibrary的實現類,對比UML類圖中的RealSubject:框架
public class Library implements ILibrary{
@Override
public void buy(){
System.out.println("buy book");
}
@Override
public void borrow(){
System.out.println("borrow book");
}
}
複製代碼
那麼當咱們定義好Library這個實例後,好比咱們如今想要在借書以前作一個標記「書被借出了」。那麼咱們有幾種方式能夠去實現,好比咱們能夠直接修改Library,但可能下次又會加一個相似「哪一種書被借出了」、「第幾區第幾排的書被借出了」相似的需求,那麼咱們就就要不斷的去修改原有的類,或者不斷的繼承原有的類去修改方法,因此咱們直接修改原有的類是不可行的。這時候,咱們就須要一個代理類,幫助咱們去實現相似的方法、對比UML類圖中的Proxy:ide
public class LibraryProxy implements ILibrary{
private Library library;
public LibraryProxy(Library library){
this.library = library;
}
@Override
public void buy(){
library.buy();
}
@Override
public void borrow(){
System.out.println("---tag---");
library.borrow();
}
}
複製代碼
那麼咱們能夠在使用中:ui
public class ProxyTest{
public static void main(String[] args){
ILibrary library = new LibraryProxy(new Library());
library.buy();
library.borrow();
}
}
複製代碼
上面代碼輸出的結果爲:this
buy book
---tag---
borrow book
複製代碼
從上面的代碼能夠看出,咱們經過聚合的方法,經過代理持有一個委託類的實例,客戶端經過代理類訪問委託類的對象,從而實現一些操做。這就是代理模式的簡單實現。那麼還有個問題,若是咱們想在買書的上面也加上相似的需求,咱們或許能夠在代理中直接加上代碼,但若是咱們在ILibrary中再加入一些方法,好比「還書」、「下架書」、「上架書」等等等的方法,咱們都要去代理中給這些方法寫上一樣的代碼,很麻煩,這時候咱們就可使用動態代理去解決這個問題。若是要使用動態代理,咱們來新建一個類,名字叫作DynamicLibraryHandlerspa
public class DynamicLibraryHandler implements InvocationHandler {
private Object library;
public DynamicLibraryHandler(Object library){
this.library = library;
}
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
preStart(); // 執行一些操做
System.out.println("---pre---");
method.invoke(pingpai, args);
System.out.println("---end---");
doEnd(); // 執行一些操做
return null;
}
}
複製代碼
而後修改一下咱們的main方法:代理
public class ProxyTest{
public static void main(String[] args){
// ILibrary library = new LibraryProxy(new Library());
// library.buy();
// library.borrow();
DynamicLibraryHandler h = new DynamicLibraryHandler(new Library());
ILibrary lib = Proxy.newProxyInstance(ILibrary.class.getClassLoader(), new Class[]{ILibrary.class}, h); //獲取代理對象
lib.buy();
lib.borrow();
}
}
複製代碼
上面的代碼輸出結果爲:
---pre---
buy book
---end---
---pre---
borrow book
---end---
複製代碼
能夠看到,咱們並無實現代理類,也對每一個方法都加上了咱們想要的需求,關鍵點就在InvocationHandler 和 Proxy.newProxyInstance() 上,那麼首先來看一下InvocationHandler
的源碼:
/** * {@code InvocationHandler} is the interface implemented by * the <i>invocation handler</i> of a proxy instance. * * 每一個代理實例都有一個與其關聯的Invocation handler, 當調用實例的方法的時候,方法調用將會 * 被分發到其InvocationHandler的invoke方法。 * ... * @author Peter Jones * @see Proxy * @since 1.3 */
public interface InvocationHandler {
...
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
複製代碼
從InvocationHandler
的註釋能夠看出來,當生成的代理類調用它的方法的時候,該方法將會被InvocationHandler
轉發,調用其invoke()
方法,實現代理。
從上面的例子中能夠看出,代理類的建立是經過 Proxy.newProxyInstance()
建立的,再來看下其源碼:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
/* * Look up or generate the designated proxy class. */
Class<?> cl = getProxyClass0(loader, intfs); // 經過ClassLoader和interface找到相關類
try {
// Android-changed: sm is always null
// if (sm != null) {
// checkNewProxyPermission(Reflection.getCallerClass(), cl);
// }
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
// Android-changed: Removed AccessController.doPrivileged
cons.setAccessible(true);
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
...
}
}
複製代碼
從上面的源碼中能夠看出來,代理類是經過 getProxyClass0(loader, intfs)
獲取的,那麼再來看一下 getProxyClass0(loader, intfs)
的源碼:
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
return proxyClassCache.get(loader, interfaces);
}
複製代碼
從源碼看出來是經過 proxyClassCache
獲取的:
private static final ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>>{
...
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
Class<?> interfaceClass = null;
try {
//經過interface找到接口類
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
...
}
/* * 將每一個非公共的接口所在的包記錄下來,是爲了將代理類與接口定義在同一個包下 * 而且驗證全部的非公共的接口都在同一個包內 */
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
...
return generateProxy(proxyName, interfaces, loader, methodsArray,
exceptionsArray);
}
}
}
複製代碼
能夠看出來,經過native的 generateProxy()
方法生成的代理類。動態代理在不少地方都有用到,好比咱們經常使用的網絡框架Retrofit。
Kotlin中的委託模式的實現方式,在代碼上顯得更加清晰一些,咱們首先來引用一段官方的例子:
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main() {
val b = BaseImpl(10)
Derived(b).print()
}
複製代碼
這裏咱們看到kotlin中使用到了一個by 的關鍵字,by就表示b就是咱們在前面所說的UML類圖中的RealSubject。咱們能夠將這段代碼使用Android Studio轉爲Java代碼看一下就能夠看出來了:
public final class Derived implements Base {
// $FF: synthetic field
private final Base $$delegate_0;
public Derived(@NotNull Base b) {
Intrinsics.checkParameterIsNotNull(b, "b");
super();
this.$$delegate_0 = b;
}
public void println() {
this.$$delegate_0.println();
}
}
複製代碼
上面代碼已經很清楚了,和咱們的代理模式寫法同樣。咱們把上面的代碼稍做修改:
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(val b: Base) : Base by b{
override fun print(){
b.print()
print("adc")
}
}
fun main() {
val b = BaseImpl(10)
Derived(b).print()
}
複製代碼
這樣咱們的程序輸出結果就是
10
abc
複製代碼