Android-自定义注解-Java动态代理(Proxy)-基础

Android自定义注解从元注解开始,经过自定义注解,经过反射基本可以自己实现一个仿Butterknife那样使用效果的注解库。你还可以假装发布到github上面,自己implementation, 哈哈~~~

接着我们再研究下动态代理,然后继续完善下我们的自定义注解。这样一来,也能针对注解反射动态代理的知识进行研究学习,之后就可以开始研究butterknife的源码呢???

Java动态代理,我们就从Proxy类说起吧,之前有了解过代理设计模式的童鞋,理解起来要容易一些。这个类在java.lang.reflect下面,包括我们之前的Method, Field都在这个包下面。

官方英文文档说明:

href="Java Platform SE 6">Java Platform SE 6

英文有时候看着还是老火,来个中文的:

href="在线文档-jdk-zh">在线文档-jdk-zh

Let's start

我们先过一篇这个相关概念,照着文档过了一遍解释,一年懵逼,看懂一些。好多看不懂????然后继续多看几遍试试吧~~again...

1.先来了个总体介绍和简单实用方式

public class Proxy
extends Object
implements Serializable
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.

To create a proxy for some interface Foo:

     InvocationHandler handler = new MyInvocationHandler(...);
     Class proxyClass = Proxy.getProxyClass(
         Foo.class.getClassLoader(), new Class[] { Foo.class });
     Foo f = (Foo) proxyClass.
         getConstructor(new Class[] { InvocationHandler.class }).
         newInstance(new Object[] { handler });

or more simply:
     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                          new Class[] { Foo.class },
                                          handler);

A dynamic proxy class (simply referred to as a proxy class below) is a class that implements a list of interfaces specified at runtime when the class is created, with behavior as described below. A proxy interface is such an interface that is implemented by a proxy class. A proxy instance is an instance of a proxy class. Each proxy instance has an associated invocation handler object, which implements the interface InvocationHandler. A method invocation on a proxy instance through one of its proxy interfaces will be dispatched to the invoke method of the instance's invocation handler, passing the proxy instance, a java.lang.reflect.Method object identifying the method that was invoked, and an array of type Object containing the arguments. The invocation handler processes the encoded method invocation as appropriate and the result that it returns will be returned as the result of the method invocation on the proxy instance.

Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。(同时说了)如何去创建某一接口的代理!

动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 是代理类实现的一个接口。 代理实例 是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口 InvocationHandler。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke 方法,并传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。

2.先看这一部分吧,然后强行理解下,搞点demo来实践一下,到底什么个意思、什么个用法、什么个好处!

2.1 创建一个接口 Foo.class

package com.example.mylibrary;

public interface Foo {
    public void fuckBad(int fuckNumber);
}

2.2 搞一个测试类FooTest.java,重点是下面这段我们使用下,看看有什么可以探究的

InvocationHandler handler = new MyInvocationHandler(...);

Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),

new Class[] { Foo.class },

handler);

先看下InvocationHandler接口,有一个invoke方法public Object invoke(Object proxy, Method method, Object[] args),其中有一个Method和参数,我们可以获取方法名称。这样的话,我们打印一下这个方法名称和相关参数。这样我们生成代理实例以后就运行代理实例的方法,看看发生什么

package com.example.mylibrary;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class FooTest {
    public static void main(String[] args){
        InvocationHandler invocationHandler = new MyInvocationHandler();
        Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[]{Foo.class}, invocationHandler);
        foo.fuckBad(111);
    }

    public static class MyInvocationHandler implements InvocationHandler{
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("method=" + method.getName());
            for (int i = 0; i < (null == args ? 0 : args.length); ++i){
                System.out.println("arg" + i + "=" + args[i]);
            }
            return null;
        }
    }
}

看结果,应该能明白点什么了...

image

强行解释一波:我简单演示来看,通过Proxy.newProxyInstance,我们产生了一个Foo的代理实例对象,然后当我们调用Foo的fuckBad(int fuckNumber)的时候就相当于调用了MyInvocationHandler的invoke方法,此时方法名称和参数通过invoke传递过去了,所以打印时我们能看到相关调用的方法名称和参数都是对应上的。文档一脸懵逼就一脸懵逼吧,我们先知道文档告诉这样做吧,然后慢慢理解!!!

2.3 本来我想打印一下proxy这个Object的(System.out.println("proxy=" + (null == proxy ? "" : proxy.toString()));),但是发现无法打印,并且死循环。然后搜了一篇帖子:$Proxy0.toString从帖子来看,简单不知道正确与否的理解就是说:这个object应该就是代理对象了,然后我们本来就是再代理实例里面去打印这个代理对象,只是说调用了toString()方法,然后代理又会对toString进行代理,就这样不停的代理不停的调用,就成死循环了! 另外就是说invoke里面这个参数目前来讲没有什么用处,先不理它!

2.4 有时候往往不要去随意修改原有的代码,尤其是涉及到大型项目,为了兼容旧版(像Android系统),往往我们会保留原有实现,重新定义新的接口。比如我们既要用到原有的实现,还需要新增处理,那此时比如我们可以用动态代理,除了调用原有的方法,我们还可以中间插入一些处理,像我们上面实例代码,我们在返回invoke对象前,可以做一些日志打印调试等工作或者别的处理(当然这里我们还没有去做invoke返回,目前还是return null).

从设计模式的角度讲,大家以后编程中,尽量要面向接口,更通俗一点就是,一个类中使用的别的对象成员变量,最好定义成接口的变量而不是实际实现类的变量! 有空再深入理解下设计模式,有些模式都没怎么去理解和使用(另外可能也是看的源码少太少了)~~~

3 我们现在来补全一下这个invoke方法,返回method.invoke的对象结果吧

package com.example.mylibrary;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class FooTest {
    public static void main(String[] args){
        FuckFoo fuckFoo = new FuckFoo();
        ///< 通过代理类来执行我们的fuckFoo的方法
        InvocationHandler invocationHandler = new MyInvocationHandler(fuckFoo);
        Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[]{Foo.class}, invocationHandler);
        foo.fuckBad(111);
    }
    private static class FuckFoo implements Foo{
        @Override
        public void fuckBad(int fuckNumber) {
            System.out.println("fuckNumber=" + fuckNumber);
        }
    }
    public static class MyInvocationHandler implements InvocationHandler{
        private Object object;
        MyInvocationHandler(Object object){
            this.object = object;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            ///< 相当于执行了object(fuckFoo).fuckBad(...)方法
            return method.invoke(object, args);
        }
    }
}

3.1 结果显而易见。这就是从文档出发,最简单的动态代理的实例哟!文档后面还有一堆的解释和相关方法,我看着懵懵的,想先放一放吧,先把基本的理解了再说。然后试着去利用动态代理把Android注解里面的setOnClickListener替换一下好不好~~~

不行不行,下篇我们先说下代理模式这个Proxy模式吧...

你可能感兴趣的:(Android-自定义注解-Java动态代理(Proxy)-基础)