Java动态代理(实现类似Retrofit+okhttp网络请求的基础使用)

1、角色

抽象接口、真实类处理业务逻辑、代理类

03、01JAVA代理模式角色.png
2、静态代理:在编译期间确定代理类、被代理类,由程序员创建生成代理类

代理模式: 代理类持有具体类的实例对象,代为执行具体类实例的方法。代理模式实际是在访问具体对象时引入了一定程度的间接性,而这种间接性可以附加额外的用途,一般是想在方法执行前后添加逻辑判断。如:取钱业务,需要先判断账户是否有钱等。

场景:AOP面向切面编程:在一个切点之前执行一些操作,在一个切点之后执行一些操作,其中这些切点就是一个个的方法,而这些方法就是所在类被代理,在代理过程中切入一些其他的操作。

缺点:造成接口增多,一个代理会实现多个接口,不变维护修改;

如下例子:班级学生需要向老师上交班费,需要先将班费交给班长,再由班长代理班级同学上交班费;

public interface OnPersonSerivce {

    void classFreeAction();//上交班费行为

}

/**
 * 学生,接口的具体实现类
 */
public class StudentServiceImpl implements OnPersonSerivce {
    String name; //名字
    int classFree; //班费

    public StudentServiceImpl(String name, int classFree) {
        this.name = name;
        this.classFree = classFree;
    }

    /**
     * 交班费
     */
    @Override
    public void classFreeAction() {
        System.out.println(name + " 上交班费 " + classFree + "元");
    }
}

/**
 * 代理类,班长
 */
public class StudentServiceProxy implements OnPersonSerivce {
    OnPersonSerivce mOnPersonSerivce; //具体的实现类

    public StudentServiceProxy(OnPersonSerivce onUserSerivce) {
//        if (onUserSerivce.getClass() == StudentServiceImpl.class) {
//            //只代理 StudentServiceImpl学生对象
//        }
        mOnPersonSerivce = onUserSerivce;
    }

    @Override
    public void classFreeAction() {
        System.out.println("-- 代理类中classFreeAction start --");

        mOnPersonSerivce.classFreeAction();

        System.out.println("-- 代理类中classFreeAction end(班长收到班费) --");
    }
}

//调用静态代理
public class MyMainClass {
    public static void main(String[] args) {

        //被代理类 (班级同学)
        StudentServiceImpl student = new StudentServiceImpl("张三",30);
        //代理类 (班长)
        StudentServiceProxy proxy = new StudentServiceProxy(student);
        //代理类执行 (班长上交班费)
        proxy.classFreeAction();

    }
}

输出打印:
-- 代理类中classFreeAction start --
张三 上交班费 30元
-- 代理类中classFreeAction end(班长收到班费) --
3、动态代理:在程序运行时创建的代理方式,代理类是在运行时动态生成的

优点:可以方便对代理类的方法统一进行管理,而不用修改代理类中的方法;

涉及的类:java.lang.reflect.Proxy、InvocationHandler接口类(监听回调);通过这个Proxy类和InvocationHandler接口可以生成JDK的动态代理类和动态代理对象。

//创建一个与代理对象相关联的InvocationHandler
 InvocationHandler InvocationHandler = new MyInvocationHandler(stu);
  
//创建一个代理对象stuProxy,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
  OnPersonSerivce stuProxy= (OnPersonSerivce) Proxy.newProxyInstance(OnPersonSerivce.class.getClassLoader(), new Class[]{OnPersonSerivce.class}, InvocationHandler);
  
  stuProxy.classFreeAction();

其中可以通过以下代码,获取打印内存中的类文件;

try {
            String name = StudentServiceImpl.class.getName() + "$Proxy0";
            byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{StudentServiceImpl.class});
            FileOutputStream fos = new FileOutputStream("lib/" + name + ".class");
            fos.write(bytes);
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("write file error");
        }

动态生成的代理类文件如下:其中 Method m3 是 classFreeAction方法,自己写的方法。

public final class StudentServiceImpl$Proxy0 extends Proxy implements StudentServiceImpl {
    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;

    public StudentServiceImpl$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 void notify() throws  {
        try {
            super.h.invoke(this, m8, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    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 classFreeAction() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void wait(long var1) throws InterruptedException {
        try {
            super.h.invoke(this, m5, new Object[]{var1});
        } catch (RuntimeException | InterruptedException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final void wait(long var1, int var3) throws InterruptedException {
        try {
            super.h.invoke(this, m4, new Object[]{var1, var3});
        } catch (RuntimeException | InterruptedException | Error var5) {
            throw var5;
        } catch (Throwable var6) {
            throw new UndeclaredThrowableException(var6);
        }
    }

    public final Class getClass() throws  {
        try {
            return (Class)super.h.invoke(this, m7, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void notifyAll() throws  {
        try {
            super.h.invoke(this, m9, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    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);
        }
    }

    public final void wait() throws InterruptedException {
        try {
            super.h.invoke(this, m6, (Object[])null);
        } catch (RuntimeException | InterruptedException | 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"));
            m8 = Class.forName("com.izheer.lib.proxys.StudentServiceImpl").getMethod("notify");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.izheer.lib.proxys.StudentServiceImpl").getMethod("classFreeAction");//自己定义的方法
            m5 = Class.forName("com.izheer.lib.proxys.StudentServiceImpl").getMethod("wait", Long.TYPE);
            m4 = Class.forName("com.izheer.lib.proxys.StudentServiceImpl").getMethod("wait", Long.TYPE, Integer.TYPE);
            m7 = Class.forName("com.izheer.lib.proxys.StudentServiceImpl").getMethod("getClass");
            m9 = Class.forName("com.izheer.lib.proxys.StudentServiceImpl").getMethod("notifyAll");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m6 = Class.forName("com.izheer.lib.proxys.StudentServiceImpl").getMethod("wait");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
4、Proxy.java newProxyInstance的源码分析
@CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class[] intfs = interfaces.clone();//拷贝代理接口class对象集合
        // Android-removed: SecurityManager calls
        /*
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }
        */

        /*
         * Look up or generate the designated proxy class.
         */
        Class cl = getProxyClass0(loader, intfs); //获取到Class对象

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            // Android-removed: SecurityManager / permission checks.
            /*
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            */

            final Constructor cons = cl.getConstructor(constructorParams); //通过反射获取class的对象的构造器
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                // BEGIN Android-removed: Excluded AccessController.doPrivileged call.
                /*
                AccessController.doPrivileged(new PrivilegedAction() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
                */

                cons.setAccessible(true);
                // END Android-removed: Excluded AccessController.doPrivileged call.
            }
            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);
        }
    }

从newProxyInstance方法看出生成动态代理类的步骤

//拷贝代理接口class对象集合
1、final Class[] intfs = interfaces.clone(); 
2、 Class cl = getProxyClass0(loader, intfs);//获取到Class对象
//通过反射获取class的对象的构造方法
3、final Constructor cons = cl.getConstructor(constructorParams);
//对构造方法进行实例化,实际返回的是  第2点中的Class对象
//(类加载器在内存中生成的Class对象,见底部类加载流程图中的 Class对象节点)
4、return cons.newInstance(new Object[]{h}); 

总结步骤
创建动态代理类对象的步骤,如下:对应newProxyInstance的源码

1、使用Proxy类的getProxyClass静态方法生成一个动态代理类

 Class proxyClass = Proxy.getProxyClass(OnPersonSerivce.class.getClassLoader(), new Class[]{OnPersonSerivce.class});

2、利用反射,获取代理类Class(proxyClass)对象的构造器Constructor(带有一个InvocationHandler参数的构造器)

 Constructor constructor = proxyClass.getConstructor(InvocationHandler.class);

3、通过构造器Constructor 创建一个动态实例

StudentServiceImpl o = (StudentServiceImpl) constructor.newInstance(new InvocationHandler() {
                @Override
                public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                    return null;
                }
            });
通过实现类似Retrofit的基本使用demo,加深对动态代理、注解、发射的理解与使用

Retrofit接口的使用流程:

A、当api接口被调用时,Retrofit会被动态代理拦截然后调用代理中的InvocationHandler对象,在invoke方法中传入参数;

B、然后利用反射获取接口方法的注解信息,子路径地址,请求方式类型;请求参数key值;

C、最后获取到的注解信息配合args参数,创建一个ServiceMethod对象,在ServiceMethod中组合成一个request,最后由Okhttp发送Request;

具体demo:ProxyRetrofit上传github
其中,click包中实现onClick的注入,类似ButterKnife 的 OnClick点击事件注入

JAVA类的完整生命周期

java源文件 —编译—> 字节码(.class文件)—类加载器—> Class对象(jvm中可识别的对象)—实例—>实例对象 ——>卸载

java类加载流程

java类加载流程.png

你可能感兴趣的:(Java动态代理(实现类似Retrofit+okhttp网络请求的基础使用))