目錄:
1.動態代理與靜態代理的使用區別
2.動態代理實現原理
3.動態代理的使用場景
1.靜態代理
代理模式給某一個對象提供一個代理對象,并由代理對象控制對原對象的引用。通俗的來講代理模式就是我們生活中常見的中介角色。
public interface Iinterface {
void dosomething();
}
public class RealMovie implements Iinterface {
@Override
public void dosomething() {
System.out.println("做一些事");
}
}
上面是具體的實現類,下面是代理類
public class ProxyA implements Iinterface {
ProxyA mo;
public ProxyA(ProxyA mo) {
super();
this.mo = mo;
}
@Override
public void dosomething() {
ganbiedeshi(true);
mo.play();
}
public void ganbiedeshi(boolean isStart){
System.out.println("做一些別的事!");
}
}
調用時候就直接使用代理類,不直接使用實現類,里面可以做一些額外的邏輯。
2.動態代理
使用代碼入下:
public interface IActionInterface{
void eat();
}
public static class Dog implements IActionInterface{
@Override
public void eat() {
Log.e("動態代理", "eat: 狗吃肉");
}
}
public void main(String[] args) {
Dog dog = new Dog();
IActionInterface action = (IActionInterface) Proxy.newProxyInstance(DynamicProxy.class.getClassLoader(), new Class[]{IActionInterface.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.e("動態代理", "method:" + method.getName());
return method.invoke(dog,args);
}
});
action.eat();
}
比起靜態代理,沒增加一個需要代理的對象都要增加代理類,而動態代理直接作用接口,在運行時候,動態創建代理類到內存數據分區中的方法區中,如果我們想看到,也可以通過下面代碼在java中生成。
String name = IActionInterface.class.getName()+"$Proxy0"; //生成代理指定接口的Class數據
byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{IActionInterface.class});
FileOutputStream fos = null;
try {
fos = new FileOutputStream("lib/" + name+".class");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
fos.write(bytes);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
3.動態代理實現原理
根據上面的生成代碼,我們把運行時生成的類寫出來后,代碼如下:
public final class $Proxy0 extends Proxy implements IActionInterface
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
/**
*注意這里是生成代理類的構造方法,方法參數為InvocationHandler類型,看到這,是不是就有點明白
*為何代理對象調用方法都是執行InvocationHandler中的invoke方法,而InvocationHandler又持有
*
*/
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
/**
*
*這里調用代理對象的giveMoney方法,直接就調用了InvocationHandler中的invoke方法,并把m3傳了進去。
*this.h.invoke(this, m3, null);這里簡單,明了。
*來,再想想,代理對象持有一個InvocationHandler對象,InvocationHandler對象持有一個被代理的對象,
*再聯系到InvacationHandler中的invoke方法。嗯,就是這樣。
*/
public final void eat()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("proxy. IActionInterface").getMethod("eat", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
1.首先執行
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
// 1.首先使用原型設計模式,保存傳入的接口
final Class<?>[] intfs = interfaces.clone();
// 2.主線!!!!
Class<?> cl = getProxyClass0(loader, intfs);
try {
// 3.獲取到上面類 通過反射創建并返回對象
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
cons.setAccessible(true);
}
return cons.newInstance(new Object[]{h});
//省略代碼
}
可以看到就簡單的幾步,首先保存了傳入的接口,然后獲取到類,再通過反射創建類的對象并返回
2.類如何生成的
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
//完成檢測接口數量后,調用代理緩存類中獲取
return proxyClassCache.get(loader, interfaces);
}
3.通過代碼proxyClassCache.get生成類
1.生成規則命名就是Proxy$0 0到N命名.生成的類繼承Proxy,實現我們要代理的接口
2.構造方法傳入了InvacationHandeler 給到super
3.默認靜態代碼塊中反射創建m1 ,m2 ....作為參數包含我們的方法和object的方法
4.具體的方法中調用this.h.invoke(this, m3, null); 也就是重寫的invoke方法
動態代理的使用場景
1.retrofit框架中調用create時候返回一個動態代理對象
public <T> T create(final Class<T> service) {
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
————————————————
版權聲明:本文為CSDN博主「Simple_ R 」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/M_sdn/article/details/84856273
2.ASM進程通信也使用到
3.可以做一些接口執行的統計,比如耗時,當然有網絡請求攔截器