目录
- 1.什么是代理
- 2.代理的作用
- 3.代理的构成
- 4.静态代理
- 5.动态代理
- 6.动态代理的原理
1.什么是代理
百科的介绍:
代理是一个汉语词汇,拼音是dài lǐ,指以他人的名义,在授权范围内进行对被代理人直接发生法律效力的法律行为。
在编程语言中,代理是一种编程思想;和上面的定义类似,代理是一种"中间人"完成指定功能的过程,发起人提出具体的需求,但需求并不是本身完成,而是通过中间者的形式去完成。有点类似于我们的中介,我们找房的时候并不是直接去找房东,而是通过中介去完成,中介帮我们筛选房子并和房东进行租赁
2.代理的作用
通过中介者也就是代理的方式,我们会引入代理对象去访问具体的目标或功能,可以防止直接访问目标可能带来的问题,减少了操作的复杂度也同时进行了一定程度的解耦
代理最终代理的是接口方法,可以很好的和核心代码隔离,当业务需求变更时我们只需修改具体的实现细节,而不用修改整体结构
代理可以方便我们在所代理的方法前后进行一系列方法的拓展,而不用在每个实现中去一一处理,可以很好的统一进行管理
3.代理的构成
抽象角色
指代理角色和真实角色对外提供的方法,一般是一个接口真实角色
需要实现抽象角色的接口,定义了真实角色所需要实现的业务逻辑,以便供代理角色调用代理角色
需要实现抽象角色接口,是真实的角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以在方法执行过程中进行额外的操作。所有代理的统一流程控制都在这里处理。
4.静态代理
通过真实角色和代理角色的绑定实现的最基础的代理方案
private interface Worker{
void work();
}
private static class ProxyAgent implements Worker{
private Worker worker;
public ProxyAgent(Worker worker){
this.worker = worker;
}
@Override
public void work() {
System.out.println("start do something");
worker.work();
System.out.println("end do something");
}
}
private static class Worker1 implements Worker{
@Override
public void work() {
System.out.println("work1 done");
}
}
private static class Worker2 implements Worker{
@Override
public void work() {
System.out.println("work2 done");
}
}
public static void main(String[] args) {
Worker worker1 = new ProxyAgent(new Worker1());
Worker worker2 = new ProxyAgent(new Worker2());
worker1.work();
worker2.work();
}
上面是一个简单的静态代理的方式,业务接口也就是抽象角色
是Worker
接口,代理角色
是ProxyAgent
,真实角色
是具体的实现类Worker1
和Worker2
。可以看出,代理角色
持有了抽象角色
,在创建的时候会把抽象角色
的实现类,也就是真实角色
传入;当调用代理角色
实现的抽象方法时,实际会调用到真实角色
所实现的抽象角色
的方法。
这种传入方式和装饰器模式
很相似,区分主要看具体的业务处理或理解,如果是通过包装增强被包装角色的功能,比如输入输出流,这种是装饰器模式,可以一层层包装下去。而如果是通过包装实现业务的隔离或者说并我们并不关心的逻辑,这是代理模式,一般并不会多次包装。这里是我个人的理解,可能会有些差异。
5.动态代理
当有很多相似的业务,处理方式和静态代理一致,如果以静态代理方式处理也不是不可以,但会有很多多余的操作,或者说不够灵活,不能适应多变的场景,所以便引入了动态代理的方式
简单的动态的代理实现为
private interface Worker {
void work(String jobName);
}
private static class ProxyInvokeHandler implements InvocationHandler {
private Object worker;
public ProxyInvokeHandler(Object worker) {
this.worker = worker;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("start do something");
Object object = method.invoke(worker, args);
System.out.println("end do something");
return object;
}
}
private static class Worker1 implements Worker {
@Override
public void work(String job) {
System.out.println("work1 done " + job);
}
}
private static class Worker2 implements Worker {
@Override
public void work(String job) {
System.out.println("work2 done " + job);
}
}
public static void main(String[] args) {
ProxyInvokeHandler workInvoke1 = new ProxyInvokeHandler(new Worker1());
ProxyInvokeHandler workInvoke2 = new ProxyInvokeHandler(new Worker2());
Worker worker1 = (Worker) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), Worker1.class.getInterfaces(), workInvoke1);
Worker worker2 = (Worker) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), Worker2.class.getInterfaces(), workInvoke2);
worker1.work("job1");
System.out.println("-------- 分割线 --------");
worker2.work("job2");
}
输出结果是
start do something
work1 done job1
end do something
-------- 分割线 --------
start do something
work2 done job2
end do something
这里引入了一个InvocationHandler
,这是一个接口
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
这也是代理方法所回传的入口,这里有三个参数Object
即Proxy类对象,动态代理自动生成的字节码类会继承Proxy类,这里回传的即这个本身,后面会讲Method
动态代理最终一般都会把代理生成的类转成抽象角色
的接口形式来使用,当这些接口被调用时,所有的方法都会反馈到这里,这个是这时被调用的方法,这个是通过反射获取到的,而代理则正是通过反射去回调这些方法并回传参数的Object[]
这个是方法反馈时此时方法中所传递的参数信息
返回参数Object
这是方法的返回值,也就是方法所要return
的东西
然后再看一下动态代理生成的方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
这里也有三个参数ClassLoader
类加载器,加载类都会用到,一般我们用默认的就可以Class<?>[]
接口集,这个是我们所要代理的真实角色所实现的所有接口,也就是上面的Work1
和Worker2
所实现的接口,这里是一个数组,也就是说代理是可以同时代理一个实现多接口的真实类的InvocationHandler
这个就是上面我们所创建出的对象
这里代理的是两个真实的对象,那么有没有不使用真实对象,直接代理接口回调的呢?答案也是有的,代理的生成方法实际上是会创建一个实现该接口的实现类,如果我们不关心回调的返回值,有时候可以直接把代理当成实现类来使用,常见的OnClickListener
就可以使用这种方式代理,看下面的例子
public static void main(String[] args) {
ProxyInvokeHandler proxy = new ProxyInvokeHandler();
Worker worker = (Worker) Proxy.newProxyInstance(Worker.class.getClassLoader(), new Class[]{Worker.class}, proxy);
new Dothing(worker).work();
}
class Dothing {
private Worker worker;
public Dothing(Worker worker) {
this.worker = worker;
}
public void work() {
this.worker.work("work executed !!!");
}
}
interface Worker {
void work(String jobName);
}
class ProxyInvokeHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("start do something");
System.out.println(args[0]);
System.out.println("end do something");
return null;
}
}
可以看出,我这里直接把代理生成的类当做一个实现了Worker
接口的实现类来使用也是可以的,输出结果是
start do something
work executed !!!
end do something
这种是用于回调匿名内部类相关的操作
6.动态代理的原理
动态代理的书写格式比较固定,我们下面看下具体是怎么生成的动态代理
首先从newProxyInstance
入手
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumentException{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
Class<?> cl = getProxyClass0(loader, intfs);
try {
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
cons.setAccessible(true);
}
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);
}
}
这里代码很简单,就是通过getProxyClass0
生成一个Class类,然后通过反射调用其构造方法返回相应的实例
下面是getProxyClass0
方法
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
return proxyClassCache.get(loader, interfaces);
}
这个方法会从缓存中去取匹配的Class类
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>{
private static final String proxyClassNamePrefix = "$Proxy";
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
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");
}
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
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;
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) {
proxyPkg = "";
}
{
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()]
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
return generateProxy(proxyName, interfaces, loader, methodsArray,
exceptionsArray);
}
}
}
而获取类方法最终会走到ProxyClassFactory
的apply
方法中,通过generateProxy
方法获取最终的值,但这个方法是native
方法,我们无法查看详细,我们可以查看一下JDK中的具体class的实现
下面是JDK的细节,位于Proxy.class
字节码文件中
private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
private static final String proxyClassNamePrefix = "$Proxy";
private static final AtomicLong nextUniqueNumber = new AtomicLong();
private ProxyClassFactory() {
}
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();
String var23 = var16 + "$Proxy" + var19;
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());
}
}
}
可以看出,会先通过ProxyGenerator.generateProxyClass
生成字节码的byte
数组,然后通过Proxy.defineClass0
的方法生成具体的代理类,整个过程都是在内存
操作中完成的,也就是说并不会生成具体的字节码文件代码
我们可以通过ProxyGenerator.generateProxyClass
方法把生成的字节码写入磁盘查看细节,或者修改配置开关,同样可以获取到详细的字节码文件
比如我们可以在执行代理方法之前调用
System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
这个配置默认是关闭的,打开后可以把内存
中生成的代理文件保存到当前根目录下,方便我们查看
比如上面的例子中生成的文件是
final class $Proxy0 extends Proxy implements Worker {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(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 work(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
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("cn.enjoyedu.proxy.ProxyTest$Worker").getMethod("work", Class.forName("java.lang.String"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
public class Proxy implements Serializable {
protected InvocationHandler h;
......
private Proxy() {
}
protected Proxy(InvocationHandler var1) {
Objects.requireNonNull(var1);
this.h = var1;
}
.....
可以看出,这个代理类继承Proxy
并实现了我们所代理的真实角色
的接口
在静态代码块中,通过反射方法列出了改类所拥有的所有方法,并定义为成员变量,比如这里就列出了接口的方法以及超类Object的三大基础方法
在构造方法中传入了一个InvocationHandler
, 这个就是我们所创建的那个实例对象,然后这个对象会保存到父类Proxy
的成员变量中h
中
然后方法被调用时,会执行h.invoke
方法,把当前的Proxy
类也就是本身,当前的方法method
,以及方法的参数args
,传递到h.invoke
方法中,也就是我们所重写的那个方法中,可以看出这个本身就是一种静态代理的实现,但JDK帮我们处理各种细节,我们只需要每次代理的时候创建InvocationHandler
并实现里面的invoke
方法即可
动态代理的用处十分广泛,对于需要统一集中处理和管理的常见很契合;比如我们自定义一些耗时的操作接口,而这些方法调用时候页面可能已经销毁,我们想在所有方法调用前进行页面状态的判断,一个个写会比较麻烦,用动态代理方式就可以集中起来一起管理。当然页面状态的用LifeData处理会更好,这里只是举一个例子
注意动态代理代理的是接口不是类,创建的时候传参也要注意传的是被代理的真实对象的接口,而不是接口这个类。
我们在android中的接口也是可以被代理的,比如点击事件的监听;而不一定必须是我们新定义的,也就是说只要是接口,都是可以使用代理的功能的