动态代理
- 静态代理:在代码运行之前代理类的class文件就存在了
- 动态代理:刚刚相反,通过反射来动态生成代理对象,也就是说编码的时候不知道代理谁,只有执行的时候才知道。
我们还用上个月静态代理的例子来说明
地址:https://livesun.github.io/2017/06/19/Proxy_Mode/
/**
 * Created by 29028 on 2017/6/19.
 *
 * 自己的接口
 */
public interface ISlef {
    //我能干什么
    //吃
    public void eat();
    //工作
    public void doWork();
}
创建被代理类,我们自己。
/**
 * Created by 29028 on 2017/6/19.
 * 真的自己
 */
public class TrueSelf implements ISlef {
    private ISlef slef;
    //默认让一号来
    public TrueSelf(){
        slef =new ProxyRobot1();
    }
    //设置替身 我想谁几号替我就让几号来
    public void setProxy(ISlef slef){
        this.slef = slef;
    }
    //吃东西这事还是我们自己来比较好
    public void eat() {
        Log.d("AAA","我悠哉悠哉的吃肉");
    }
    public void doWork() {
        slef.doWork();
    }
}
如果按照静态代理,我们必须写这个替身一号的代理类
/**
 * Created by 29028 on 2017/6/19.
 * 机器人替身1号 我会的他也会
 */
public class ProxyRobot1 implements ISlef {
    public void eat() {
        Log.d("AAA","机器人替身1号吃电");
    }
    public void doWork() {
        Log.d("AAA","机器人替身1号帮我做工作");
    }
}
然后这样,让代理类帮我们做事情
private void doThings() {
       TrueSelf self=new TrueSelf();
       self.doWork();
       self.eat();
   }
这里面可以看到,其实我们必须要创建ProxyRobot1机器人一号,来代理我们做事情,如果有很多方法,那会很麻烦,尤其是如果运用在MVP架构中,我们每个方法基本都要判断ISlef为不为空,基于如此,所以动态代理应运而生。
Java其实已经帮我们封装了动态代理的方法,我们只需要Proxy这个类,以及实现InvocationHandler接口,并调用invoke即可。
代码如下
/**
 * 真的自己
 */
public class TrueSelf implements ISlef {
    //吃东西这事还是我们自己来比较好
    public void eat() {
        Log.d("AAA","我悠哉悠哉的吃肉");
    }
    public void doWork() {
        Log.d("AAA","我的工作做完了");
    }
}
private void doThings() {
       TrueSelf self=new TrueSelf();
       ISlef proxy = (ISlef) Proxy.newProxyInstance(
                self.getClass().getClassLoader(),
                self.getClass().getInterfaces(),
                new MyInvocationHandler(self)
        );
        proxy.eat();
        proxy.doWork();
   }
public  class  MyInvocationHandler implements InvocationHandler{
        private ISlef man;
        public MyInvocationHandler(ISlef man) {
            this.man = man;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
             Log.d("AAA","机器人帮我干货");
            Object obj=method.invoke(man,args);
            return obj;
        }
    }
可以看到,我们并没有创建ProxyRobot1代理类,但同样完成了之前的工作。
使用是非常简单的
接着粗略的看下Proxy的源码是如何实现动态代理的。
 public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interface,InvocationHandler h)
        throws IllegalArgumentException
    {
        Class<?> cl = getProxyClass0(loader, interfaces);
        //调用InvocationHandler的构造函数,其实就是每次调用newProxyInstance,就去执行了InvocationHandler里面的那个invoke方法。
       final Constructor<?> cons = cl.getConstructor(constructorParams);
            return newInstance(cons, h);
    }
 private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        Class<?> proxyClass = null;
        String[] interfaceNames = new String[interfaces.length];
        Set<Class<?>> interfaceSet = new HashSet<>();
        for (int i = 0; i < interfaces.length; i++) {
            //获取所有接口的名字
            String interfaceName = interfaces[i].getName();
            Class<?> interfaceClass = null;
            try {
            //获取所有接口
                interfaceClass = Class.forName(interfaceName, false, loader);
            } catch (ClassNotFoundException e) {
            }
            interfaceSet.add(interfaceClass);
            interfaceNames[i] = interfaceName;
        }
          try {
            String proxyPkg = null;     
            for (int i = 0; i < interfaces.length; i++) {
                int flags = interfaces[i].getModifiers();
                if (!Modifier.isPublic(flags)) {
                //获取完整的比如 livesun.proxy.test.Iself
                    String name = interfaces[i].getName();
                    int n = name.lastIndexOf('.');
                    //pak=livesun.proxy.test. 获取包名
                    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");
                    }
                }
            }
           //获取接口里面所有的方法
                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()][]);
                final long num;
                synchronized (nextUniqueNumberLock) {
                    num = nextUniqueNumber++;
                }
//private final static String proxyClassNamePrefix = "$Proxy"; 解析interface所有的方法,新建一个class,这个类的名字为,包名+$Proxy。livesun.proxy.test.$Proxy
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
                proxyClass = generateProxy(proxyName, interfaces, loader, methodsArray,
                        exceptionsArray);
        }
        //proxyClass类
        return proxyClass;
    }
//native方法,其实就是生成proxyClass类(具体内部的实现,其实并不懂。。。)
private static native Class<?> generateProxy(String name, Class<?>[] interfaces,
                                                 ClassLoader loader, Method[] methods,
                                                 Class<?>[][] exceptions);
