代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。 举个例子来说明:张三想买场演唱会门票,虽然他可以自己去抢,但是这确实太浪费时间和精力了,或者说根本抢不到。于是张三就通过黄牛来买,黄牛来帮张三,张三只是负责选择自己喜欢的的位置,然后付钱就可以了。
- 目的:
- 通过引入代理对象的方式来间接访问目标对象,防止直接访问目标对象给系统带来的不必要
- 复杂;通过代理对象对原有的业务增强;
- 代理模式一般会有三个角色:
- 抽象角色:指代理角色和真实角色对外提供的公共方法,一般为一个接口
- 真实角色:需要实现抽象角色接口,定义了真实角色所要实现的业务逻辑,以便供代理角色调用。也就是真正的业务逻辑在此。
- 代理角色:需要实现抽象角色接口,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。将统一的流程控制都放到代理角色中处理! 而访问者不再访问真实角色,而是去访问代理角色。
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。一般来说,被代理对象和代理对象是一对一的关系,当然一个代理对象对应多个被代理对象也是可以的。 静态代理,一对一则会出现时静态代理对象量多、代码量大,从而导致代码复杂,可维护性差的问题,一对多则代理对象会出现扩展能力差的问题。
动态代理
是指在使用时再创建代理类和实例
- 优点
- 只需要1个动态代理类就可以解决创建多个静态代理的问题,避免重复、多余代码
- 更强的灵活性
- 缺点
- 效率低,相比静态代理中 直接调用目标对象方法,动态代理则需要先通过Java反射机制 从而 间接调用目标对象方法。
- 应用场景局限,因为 Java 的单继承特性(每个代理类都继承了 Proxy 类),即只能针对接口 创建 代理类,不能针对类创建代理类。
- 在java的动态代理机制中,有两个重要的类或接口,一个是InvocationHandler接口、另一个则是 Proxy类,这个类和接口是实现我们动态代理所必须用到的。
- InvocationHandler接口是给动态代理类实现的,负责处理被代理对象的操作的,而Proxy是用来创建动态代理类实例对象的,因为只有得到了这个对象我们才能调用那些需要代理的方法。
动态代理实现原理
通过调试模式我们发现,动态代理里,代理类的类名是这样的:
{$Proxy@517}"com.kanshu.testlibrary.agent.AaFactory@2f410acf"
这个代理类为何是这个名字?它是如何执行被代理对象的相关方法呢?我们在java文件编译后的目录里其实找不到这个名为$Proxy0的class文件的。 观察Proxy.newProxyInstance方法,与创建对象有关的代码主要有:
public static Object newProxyInstance(ClassLoader var0, Class<?>[] var1, InvocationHandler var2) throws IllegalArgumentException {
Objects.requireNonNull(var2);
Class[] var3 = (Class[])var1.clone();
SecurityManager var4 = System.getSecurityManager();
if (var4 != null) {
checkProxyAccess(Reflection.getCallerClass(), var0, var3);
}
// 获得代理类的class对象:
Class var5 = getProxyClass0(var0, var3);
try {
if (var4 != null) {
checkNewProxyPermission(Reflection.getCallerClass(), var5);
}
// 获得代理类的构造器:
final Constructor var6 = var5.getConstructor(constructorParams);
if (!Modifier.isPublic(var5.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
var6.setAccessible(true);
return null;
}
});
}
// 创建代理类的实例
return var6.newInstance(var2);
} catch (InstantiationException | IllegalAccessException var8) {
throw new InternalError(var8.toString(), var8);
} catch (InvocationTargetException var9) {
Throwable var7 = var9.getCause();
if (var7 instanceof RuntimeException) {
throw (RuntimeException)var7;
} else {
throw new InternalError(var7.toString(), var7);
}
} catch (NoSuchMethodException var10) {
throw new InternalError(var10.toString(), var10);
}
}
看来其中的关键点就是如何获得代理类的class对象,我们进入getProxyClass0方法,进而进入proxyClassCache.get方法,通过这个这个方法所在的类名,我们可以推测,JDK内部使用了某种机制缓存了我们的代理类的class对象,同时get方法接受的参数是被代理类的类加载器和类实现的的接口。
public V get(K var1, P var2) {
Objects.requireNonNull(var2);
this.expungeStaleEntries();
Object var3 = WeakCache.CacheKey.valueOf(var1, this.refQueue);
Object var4 = (ConcurrentMap)this.map.get(var3);
if (var4 == null) {
ConcurrentMap var5 = (ConcurrentMap)this.map.putIfAbsent(var3, var4 = new ConcurrentHashMap());
if (var5 != null) {
var4 = var5;
}
}
// 在这个get方法中,除去和缓存相关的操作,同时用到了被代理类的类加载器和类实现的的接口这两个参数
Object var9 = Objects.requireNonNull(this.subKeyFactory.apply(var1, var2));
Object var6 = (Supplier)((ConcurrentMap)var4).get(var9);
WeakCache.Factory var7 = null;
while(true) {
if (var6 != null) {
Object var8 = ((Supplier)var6).get();
if (var8 != null) {
return var8;
}
}
if (var7 == null) {
var7 = new WeakCache.Factory(var1, var2, var9, (ConcurrentMap)var4);
}
if (var6 == null) {
var6 = (Supplier)((ConcurrentMap)var4).putIfAbsent(var9, var7);
if (var6 == null) {
var6 = var7;
}
} else if (((ConcurrentMap)var4).replace(var9, var6, var7)) {
var6 = var7;
} else {
var6 = (Supplier)((ConcurrentMap)var4).get(var9);
}
}
}
我们再进入这个apply(var1, var2)方法的实现
public Class<?> apply(ClassLoader var1, Class<?>[] var2) {
IdentityHashMap var3 = new IdentityHashMap(var2.length);
Class[] var4 = var2;
int var5 = var2.length;
for(int var6 = 0; var6 < var5; ++var6) {
Class var7 = var4[var6];
Class var8 = null;
try {
var8 = Class.forName(var7.getName(), false, var1);
} catch (ClassNotFoundException var15) {
}
if (var8 != var7) {
throw new IllegalArgumentException(var7 + " is not visible from class loader");
}
if (!var8.isInterface()) {
throw new IllegalArgumentException(var8.getName() + " is not an interface");
}
if (var3.put(var8, Boolean.TRUE) != null) {
throw new IllegalArgumentException("repeated interface: " + var8.getName());
}
}
String var16 = null;
byte var17 = 17;
Class[] var18 = var2;
int var20 = var2.length;
for(int var21 = 0; var21 < var20; ++var21) {
Class var9 = var18[var21];
int var10 = var9.getModifiers();
if (!Modifier.isPublic(var10)) {
var17 = 16;
String var11 = var9.getName();
int var12 = var11.lastIndexOf(46);
String var13 = var12 == -1 ? "" : var11.substring(0, var12 + 1);
if (var16 == null) {
var16 = var13;
} else if (!var13.equals(var16)) {
throw new IllegalArgumentException("non-public interfaces from different packages");
}
}
}
if (var16 == null) {
var16 = "com.sun.proxy.";
}
long var19 = nextUniqueNumber.getAndIncrement();
// var23 代理类的类名
String var23 = var16 + "$Proxy" + var19;
// 代理类的字节码 所以是个byte数组
byte[] var22 = ProxyGenerator.generateProxyClass(var23, var2, var17);
try {
return Proxy.defineClass0(var1, var23, var22, 0, var22.length);
} catch (ClassFormatError var14) {
throw new IllegalArgumentException(var14.toString());
}
}
最终生成代理类的class对象是defineClass0方法,但是这个方法是个native方法,所以我们不去也无法深究它,但是通过这个方法的参数我们可以明显看到它接收了上面所生成的byte数组。 而我们通过ProxyUtils,这个自己写的工具类,将这个byte数组写入文件,我们并反编译,我们将会看到
import com.kanshu.testlibrary.agent.AaFactory;
import java.lang.reflect.*;
// 我们还会看到其中实现了业务接口的方法
public final class $Proxy0 extends Proxy
implements AaFactory
{
public $Proxy0(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
public final boolean equals(Object obj)
{
try
{
return ((Boolean)super.h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final void notify()
{
try
{
super.h.invoke(this, m8, null);
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString()
{
try
{
return (String)super.h.invoke(this, m2, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final void saleMan(String s)
{
try
{
// 而h则来自派生类Proxy中
// 这个h的实例来自哪里?不就是我们在创建代理类的实例时传入的吗?
super.h.invoke(this, m3, new Object[] {
s
});
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final void wait(long l)
throws InterruptedException
{
try
{
super.h.invoke(this, m5, new Object[] {
Long.valueOf(l)
});
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final void wait(long l, int i)
throws InterruptedException
{
try
{
super.h.invoke(this, m4, new Object[] {
Long.valueOf(l), Integer.valueOf(i)
});
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final Class getClass()
{
try
{
return (Class)super.h.invoke(this, m7, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final void notifyAll()
{
try
{
super.h.invoke(this, m9, null);
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
try
{
return ((Integer)super.h.invoke(this, m0, null)).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final void wait()
throws InterruptedException
{
try
{
super.h.invoke(this, m6, null);
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
private static Method m1;
private static Method m8;
private static Method m2;
private static Method m3;
private static Method m5;
private static Method m4;
private static Method m7;
private static Method m9;
private static Method m0;
private static Method m6;
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m8 = Class.forName("com.kanshu.testlibrary.agent.AaFactory").getMethod("notify", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
// 我们定义的方法
m3 = Class.forName("com.kanshu.testlibrary.agent.AaFactory").getMethod("saleMan", new Class[] {
Class.forName("java.lang.String")
});
m5 = Class.forName("com.kanshu.testlibrary.agent.AaFactory").getMethod("wait", new Class[] {
Long.TYPE
});
m4 = Class.forName("com.kanshu.testlibrary.agent.AaFactory").getMethod("wait", new Class[] {
Long.TYPE, Integer.TYPE
});
m7 = Class.forName("com.kanshu.testlibrary.agent.AaFactory").getMethod("getClass", new Class[0]);
m9 = Class.forName("com.kanshu.testlibrary.agent.AaFactory").getMethod("notifyAll", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m6 = Class.forName("com.kanshu.testlibrary.agent.AaFactory").getMethod("wait", new Class[0]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
使用了动态代理的Retrofit Retrofit简单的说就是一个网络请求的适配器,它将一个基本的Java接口通过动态代理的方式翻译成一个HTTP请求,并通过OkHttp去发送请求。此外它还具有强大的可扩展性,支持各种格式转换以及RxJava。我们基于Retrofit2解析。 先定义一个名为X的java接口,当然里面有各种注解。 @FormUrlEncoded注解表示from表单,另外还有@Multipart等注解。@POST表示post请求,此外还可以使用@GET请求
public interface XService {
@FormUrlEncoded
@POST("user/bonuspools/userinfo")
Observable<BaseResult<UserResult>> getUserInfo(@FieldMap Map<String, String> map);
}
然后如何使用的呢?
首先将域名传入构造一个Retrofit,然后通过retrofit中的create方法传入一个Java接口并得到一个x(当然x这个对象是经过处理了的)调用getPersonalListInfo(12)然后返回一个Call,最后这个Call调用了enqueue方法去异步请求http,这就是一个基本的Retrofit的网络请求。Retrofit2中Call接口的默认实现是OkHttpCall,它默认使用OkHttp3作为底层http请求client。
RetrofitHelper.getInstance()
.createService(XService.class)
.getUserInfo(map)
.compose(asyncRequestData())
.subscribe(data -> {
// 数据请求成功
}, error -> {
// 数据请求失败
});
我们只定义了一个接口XService,并没有实现这个接口,那么它是如何工作的呢?我们看看create方法的实现。 create()方法是个泛型方法,调用它时会返回一个范型T的对象,我们这里类型是XService接口,在内部实现上,很明显了使用了动态代理返回了一个XService的代理类。当调用XService内部方法的时候,会调用invoke方法。invoke方法内则通过内部一系列的封装最后返回一个Call对象。
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(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.adapt(okHttpCall);
}
});
}