先说一下动态代理的用法:
IPerson是代理对象的开放接口。也就是说,被代理类中需要被代理的方法,就写在这个IPerson里面。
public interface IPerson {
void say();
void say(String content);
String say(int content);
}
Man是需要被代理的类。
public class Man implements IPerson{
@Override
public void say() {
Log.i("********", "Man, void say() ");
}
@Override
public void say(String content) {
Log.i("********", "Man, void say(String content), result: " + content);
}
@Override
public String say(int content) {
Log.i("********", "Man, String say(int content), result: " + content);
return "Man, String say(int content), result: " + content;
}
}
Woman也是需要被代理的类。
public class Woman implements IPerson{
@Override
public void say() {
Log.i("********", "Woman, void say() ");
}
@Override
public void say(String content) {
Log.i("********", "Woman, void say(String content), result: " + content);
}
@Override
public String say(int content) {
Log.i("********", "Woman, String say(int content), result: " + content);
return "Woman, String say(int content), result: " + content;
}
}
代理类调用被代理的方法时,会先到这个WomanInvocation类的invoke方法里面来。由开发者决定怎样触发这个方法调用,是不是要调用?调用之前或者之后要执行一些什么东西?
public class WomanInvocationHandler implements InvocationHandler {
private Woman woman;
public WomanInvocationHandler (Woman woman) {
this.woman = woman;
}
@RequiresApi(api = Build.VERSION_CODES.P)
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getGenericReturnType().toString().equalsIgnoreCase("void")) {
method.invoke(woman, args);
} else {
String o = (String) method.invoke(woman, args);
return o;
}
return null;
}
}
生成代理类,以及调用被代理类的方法。
IPerson woman = (IPerson) Proxy.newProxyInstance(Woman.class.getClassLoader(), Woman.class.getInterfaces(), new WomanInvocationHandler(new Woman()));
woman.say();
woman.say("alan gong");
String content = woman.say(100);
这里就有一个疑问了,系统到底做了什么事情? 怎么就可以实现这样的功能呢?
其实很简单,系统帮你在后面实现了一个类,这个类通过动态编译生成了一个.class文件,加载到内存,并且实例化后通过Proxy.newProxyInstance()方法返回给开发者。
那么这个类做了什么? 是什么样子? 下面展示一下我写的伪代码:
public class Proxy$1234 implements IPerson{
private InvocationHandler h;
public IPerson$1234(InvocationHandler h){
this.h = h;
}
@Override
public void say() {
try {
h.invoke(this, this.getClass().getMethod("say"), null);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
@Override
public void say(String content) {
try {
h.invoke(this, this.getClass().getMethod("say", new Class[]{Integer.class}), new Object[]{new Integer(content)});
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
@Override
public String say(int content) {
Object object = null;
try {
object = h.invoke(this, this.getClass().getMethod("say", new Class[]{Integer.class}), new Object[]{new Integer(content)});
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return (String) object;
}
}
看到了吧,这个自动生成的IPerson$1234类,在每一个被代理的方法里面调用了InvocationHandler 的invoke方法!
而这个InvocationHandler其实就是你在Proxy.newProxyInstance()里传进去的WomanInvocationHandler。
可能你还有疑问,newProxyInstance()方法里面为什么要传一个接口数组?如果一个被代理类,有多个被代理方法的接口。
比如还有一个被代理接口IAnimal 。
public interface IAnimal {
void run();
}
而Woman不仅实现了IPerson, 也实现了IAnimal 。那么同样系统生成的代理类也会实现IAnimal。
就像这样:
package com.nero.transfer;
import java.lang.reflect.InvocationHandler;
public class IPerson$1234 implements IPerson, IAnimal{
private InvocationHandler h;
public IPerson$1234(InvocationHandler h){
this.h = h;
}
@Override
public void say() {
try {
h.invoke(this, this.getClass().getMethod("say"), null);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
@Override
public void say(String content) {
try {
h.invoke(this, this.getClass().getMethod("say", new Class[]{Integer.class}), new Object[]{new Integer(content)});
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
@Override
public String say(int content) {
Object object = null;
try {
object = h.invoke(this, this.getClass().getMethod("say", new Class[]{Integer.class}), new Object[]{new Integer(content)});
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return (String) object;
}
@Override
public void run() {
try {
h.invoke(this, this.getClass().getMethod("run"), null);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
}
所以你也可以这样调用:
IAnimal animal = (IAnimal) Proxy.newProxyInstance(Woman.class.getClassLoader(), Woman.class.getInterfaces(), new WomanInvocation(new Woman()));
animal.run();
这样对动态代理就很好理解吧?
相对于静态代理的好处就是不用开发者手写代理类。
至于系统是如何生成.class文件的,就是另外的话题了,这篇文章写得不错,https://www.jianshu.com/p/fc285d669bc5
看懂了动态代理就需要明白一点:
面向对象可以解决业务上的抽象, 但是代码工具的抽象仅仅依靠面向对象的手段是远远不够的,还需要反射,注解处理,源代码生成编译,这三个“穿越”手段。静态代理用面向对象的手段,做到了对业务的抽象。动态代理用了“穿越”手段的反射 和 源代码生成编译。
静态代理以下两个局限性:
- 如果同时代理多个类,依然会导致类无限制扩展
- 如果类中有多个方法,同样的逻辑需要反复实现
上面两个局限性,想依靠面向对象的手段(继承,多态,封装),是不可能做到的。这样的需求已经脱离具体业务的需求。已经是代码工具级的需求。必须要用“穿越”手段。