什么是代理模式?
代理模式就是為其他對象提供一種代理來對該對象進行訪問控制。
生活實例:
1)房產中介,他就是一個代理,由房東全權授權中介來進行房產的售前咨詢,相關事宜的處理等。
2)滴滴代駕,就是授權代駕可以駕駛你的車輛,并將車輛行駛至目的地,期間代駕可以進行對車輛的一些簡單的操作。
代理---“鐵三角”:
-
抽象角色:
為“代理角色”和“真實角色”提供的一套對外的公共方法(一般定義為接口)
interface ProxyInterface {
fun confirmAction(inputString :String,name:String);
}
-
真實角色:
真正的業(yè)務實現邏輯,他需要實現“抽象角色”中的接口;class RealInstance : ProxyInterface { private val TAG = "RealInstance"; override fun confirmAction(inputString: String,name: String) { Log.e(TAG,"真實實例對象----"+"調用confirmAction()") } }
-
代理角色:
他同“真實角色”一樣,實現了“抽象角色”中的接口,同時擁有對“真實角色”的引用,然后通過“真實角色”的引用來實現“抽象角色”中的抽象方法,且可以自己在抽象方法中增加自己的一些操作等。class ProxyInstance(realInstance: RealInstance) : ProxyInterface { val TAG = "ProxyInstance"; var mRealInstance: RealInstance = realInstance override fun confirmAction(inputString: String,name:String) { Log.e(TAG, "我是代理,我的confirmAction被調用") mRealInstance.confirmAction(inputString,name) } }三者之間的類關系如圖所示:
鐵三角類圖.png
了解了上面的“鐵三角”,那相信我們對代理模式就已經完全明白了代理模式了。。。。很簡單吧?。。?!別高興的太早了,一步一步帶你進去深淵。。。。
代理的用途:
- 通過引入代理對象的方式來間接的訪問目標對象,防止直接訪問目標對象給系統(tǒng)帶來不必要的復雜性;
- 通過代理對象進行對目標對象的訪問控制;
好,那我們就來聊聊怎么使用? 今天先聊一下靜態(tài)代理和動態(tài)代理。
代理使用:
1)靜態(tài)代理:
顧名思義,就是我們在實現代理模式時,在編輯階段就需要將對象的代理者都準備好,在程序運行時使用。
val proxyInstance = ProxyInstance(RealInstance())
proxyInstance.confirmAction("測試代理模式","")
缺點:
1.當需要代理的真實角色多時,我們的代理對象是不是也需要很多,這樣就會出現代理對象和代碼量變大的情況
2.如果我們想要擴展一下抽象接口的方法,那么真實角色和代理角色都需要維護,這樣是不是維護、擴展能力也比較差
既然靜態(tài)代理有那么明顯的缺點,我們有沒有辦法解決呢,答案是肯定的,這就是我們下面的動態(tài)代理。
2)動態(tài)代理:
相對于靜態(tài)代理而言,動態(tài)代理則是在程序運行時再創(chuàng)建對象的代理類和實例,也就是說有程序幫我們去創(chuàng)建代理類及其實例,這樣效率很明顯要低些。
JDK已經為我們提供好了API了,我們直接用JDK API就可以了,如下:
val newProxyInstance = Proxy.newProxyInstance(RealInstance::class.java.classLoader,
arrayOf(ProxyInterface::class.java),
object : InvocationHandler {
override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
if (args?.size!! > 1) {
return method?.invoke(RealInstance(), args[0],args[1])
}
return null
}
}
) as ProxyInterface
newProxyInstance.confirmAction("hello","我是代理對象");
上述代碼中,有兩個關鍵的API: Proxy和InvocationHandler,下面我們就深入“敵營”來了解一下。
源碼剖析:
Proxy 提供了創(chuàng)建動態(tài)代理類和實例的靜態(tài)方法,它也是有這些方法穿件的所有動態(tài)代理類的超類。是一個實現在運行時進行創(chuàng)建直接接口列表的類。
先來看看動態(tài)代理實現的流程圖,

然后再看源碼,下面源碼已經做了詳細的備注。
Proxy 類中的成員變量和方法:
package java.lang.reflect;//在此包下
/////////////////////////////////////////////////////////////////////////////////
//靜態(tài)成員
private static final Class<?>[] constructorParams =
{ InvocationHandler.class };
/**
* 返回指定接口的代理類的實例,該接口將方法調用分派給指定的調用處理程序。
*----loader - 類加載器來定義代理類---當前真實角色的類加載器
*----interfaces - 代理類實現的接口列表 他是一個數組:因為一個代理可以代理多個實例對象
*----h - 調度方法調用的調用處理函數
*/
@CallerSensitive
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);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
//獲取代理類的public構造方法的引用
final Constructor<?> cons = cl.getConstructor(constructorParams);//constructorParams 靜態(tài)成員
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
cons.setAccessible(true);
}
//使用帶指定參數:h的構造器cons來生成該構造器所代表的代理類的實例,并將該代理類實例返回
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
///////////////////////////////////////////////////////////
/**
* a cache of proxy classes
代理類的緩存
*/
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
/**
* Generate a proxy class. Must call the checkProxyAccess method
* to perform permission checks before calling this.
從緩存中讀取代理類,如果存在則直接返回該代理類,否則創(chuàng)建該代理類
*/
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
代理的緩存WeakCache
package java.lang.reflect;
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
//使用外部傳入的key 生成cacheKey
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
//線程安全的原子操作擔保 ConcurrentMap
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
//從原緩存map中查找cacheKey ,如果找不到則創(chuàng)建一個新的map 添加到緩存map中,并將新的map一起返回
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
//1.使用可以生成subkey ,從新的map獲取可以對應的Supplier提供者
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
//無限循環(huán)來查找值,如果找到就返回,沒有找到就創(chuàng)建一個新的值
while (true) {
if (supplier != null) {
//找到值
// supplier might be a Factory or a CacheValue<V> instance
//如果supplier不為空,則直接取出supplier中的值返回
V value = supplier.get();
if (value != null) {
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue)
//準備創(chuàng)建
// lazily construct a Factory
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
Invocationhandler接口類
//每一個代理類實例有一個相對應的InvocationHandler句柄,一旦代理類實例調用了其中一個method方法都會觸發(fā)該句柄的invoke方法,并將相關信息返回
//1 proxy 代理類實例
//2 method ,調用的方法,
//3 args 該用法的參數
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
ProxyClassFactory 最終類通過反射來生成代理類
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
/*
* Verify that the Class object actually represents an
* interface.
*/
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
*/
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
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");
}
}
}
if (proxyPkg == null) {
// if no non-public proxy interfaces, use the default package.
proxyPkg = "";
}
{
// Android-changed: Generate the proxy directly instead of calling
// through to ProxyGenerator.
List<Method> methods = getMethods(interfaces);
Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
validateReturnTypes(methods);
List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods);
Method[] methodsArray = methods.toArray(new Method[methods.size()]);
Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]);
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
return generateProxy(proxyName, interfaces, loader, methodsArray,
exceptionsArray);
}
}
}
說了半天的動態(tài)代理,那么動態(tài)代理到底生成的類長啥樣呢,我們如何才可以看到呢?
查詢動態(tài)代理類
- 新建一個java module
- 將上述抽象接口和真實角色的class 考入java module中
- 新建一個ProxyUtils類
public static void generateClassFile(Class clazz,String proxyName)
{
byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
String path = clazz.getResource(".").getPath();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(path + proxyName + ".class");
fos.write(classFile);
fos.flush();
}catch(Exception e) {
e.printStackTrace();
}finally {
try {
fos.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Subject subject=new Subject();//此處為真實角色的對象
ProxyInterface proxy =(ProxyInterface) Proxy.newProxyInstance(subject.getClass().getClassLoader(),
new Class[]{ProxyInterface.class},
new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return null;
}
});
generateClassFile(Subject.class,"SubjectProxy");//第二個參數是生成的代理類名
proxy.confirmAction();
}
- 運行ProxyUtils類的Main函數,則會在build/classes/java/main/com/XXX/proxylib/目錄下生成 SubjecProxy.class文件
- 分析一下這個class文件
1.他是一個最終類,并且繼承Proxy ,實現了我們自己的抽象接口ProxyInterface
2.有一個public 修飾的構造函數,并且InvocationHandler作為參數
3.重寫了Object的equals()、toString()、hasCode()方法
4.實現了抽象接口ProxyInterface的方法,方法體是使用InvocationHandler實例來調用它的invoke方法,并將代理實例、方法、參數作為參數回調回去
5.靜態(tài)代碼區(qū):通過反射實現類名和方法的反射,并將反射的method存放到靜態(tài)變量中
實際運行生成的代碼如下:
public final class SubjectProxy extends Proxy implements ProxyInterface {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public SubjectProxy(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void confirmAction() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.leon.proxylib.ProxyInterface").getMethod("confirmAction");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
到此為止,已經將java的動態(tài)代理,代理模式包括相關源碼的剖析都已經介紹完了,有需要的同學的可以自己跟著上面的額內容實操一下加強記憶。
知識點總結:
1、設計模式---代理模式
2、調用處理器InvocationHandler
3、Java反射機制
4、Map緩存機制
今天就學習到這里了,歡迎來踩點
