Android代理模式(静态代理,动态代理,Retrofit代理模式分析)

Posted qfh-coder

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android代理模式(静态代理,动态代理,Retrofit代理模式分析)相关的知识,希望对你有一定的参考价值。

文章目录

代理模式

前言:AOP编程(面向切面编程)

一. 由来

概念:面向切面编程是对面向对象继承体系的一个补充,它可以在水平方向上面做一些事情,从而完善整个java代码的设计体系。

我们看看下面这个图的分析:

上面这幅图抛出AOP,也就是水平方向上面做事情。下面我们就通过几个类写代码简单模拟一下这个过程。

声明一个A接口,B,C分别实现了A接口并且复写了test方法,所以B,C是在水平方向上的同级别的类,我们现在解决的问题就是在B,C的test的方法中加多一句代码System.out.println(“JAVA”);,但是前提是B,C的代码不能动,我们用过通过外部的一个方式来统一添加这句代码,为什么呢,因为假设不只是B,C实现了A接口,而是有很多个类都实现了A,那么同一水平方向上面的类数量很多,如果我们一个个去修改实现类里面的代码,那么工作量是很繁重的,所以我们应该通过外界封装一个类来完成这个需求。


public interface A 
    void test();


public class B implements A
    @Override
    public void test() 
        System.out.println("B");
    


public class C implements A
    @Override
    public void test() 
        System.out.println("C");
    



这是我们根据上面的分析定义的额外的一个Uils类,来看看怎么搞。

public class Utils 
    //定义了一个接口变量的引用
    A a;
	//通过构造方法赋值给引用,这里是多态的性质,传入的是A的实现类对象
    public Utils(A a) 
        this.a = a;
    
	//在这里我们实现上面的需求,通过这个方法我们就可以统一的在B或者C或者其他实现类中增加代码而不用手动单独去到某个实现类里面去修改代码。
    void abc() 
        System.out.println("JAVA");
        a.test();
    



class Test 
    public static void main(String[] args) 
        //这里我们调用测试C类,
        C c = new C();
        //传入c对象,赋值给引用A a,所以此时a对象指向c对象的地址
        Utils utils = new Utils(c);
        utils.a = c;
        
        //调用方法测试, 里面a.test();就会调用到c的test方法中,同理我们也可以实例化出B对象给A a引用赋值。
        utils.abc();
    


//输出 这样就可以打印出字符串JAVA并且在没有修改C类代码的情况下,B类实现也是如此。
JAVA
C

小结:从上面的代码和现象可以看出,Utils这个类持有一个A a的引用,那么我们就可以对A接口下面的水平方向的对象进行插入或者植入代码,如果我们仔细观察,其实发现Utils和A毫无关系,只是持有A的引用罢了。

接下来我们抛出一个问题,

假设我们现在又有一个X类,里面有个specialX方法,里面再调用a.test(),传入不同的A的子类对象进来,那么它所完成的功能是不一样的。那么假设我又希望在调用a.test()的之前输出一句System.out.println(“JAVA”);跟上面我们说的一样的需求

public class X 
    //X类里面独有的方法
    void specialX(A a) 
        a.test();
    


//原本我们写好的Utils类是没办法满足我们的需求的,因为Utils和A接口没有任何的继承关系,所以无法传到specialX(A a)中。
public class Utils 
    A a;

    public Utils(A a) 
        this.a = a;
    

    void abc() 
        System.out.println("JAVA");
        a.test();
    




class Test 
    public static void main(String[] args) 
        C c = new C();
        Utils utils = new Utils(c);
        utils.a = c;
        utils.abc();
    


接下来我们改写一下Utils类看看,

//我们这里也让Utils实现A接口,复写test方法
public class Utils implements A 
    A a;

    @Override
    public void test() 
        System.out.println("JAVA");
        a.test();
    


class Test 
    public static void main(String[] args) 
        C c = new C();
        Utils utils = new Utils(c);
        utils.a = c;
		
        //此时我们已经可以把Utils的对象传进去了,specialX的 a.test();就会根据传入的A的子类去执行对应子类的test方法,同时可以扩展一些新的业务功能
        X x = new X();
        x.specialX(utils);
    



那么这里我们就引出代理思想,Utils是代理类,它所生成的utils就是代理对象。

一. 代理思想

为真实对象提供代理,然后供其他对象通过代理访问真实对象,真正做事情的还是代理对象去执行对应的代码。

1. 静态代理

其实我们上面的例子就是一个简单的静态代理的模型,再回顾一下我们上面的知识,如果我们要代理A接口中水平方向上的对象。步骤:写一个类,实现A接口,复写A接口抽象方法,在这个类中写一个接口类型的变量引用,然后利用这个引用去调用接口中的方法,那么对应执行的就是其传进来的实现子类的方法。

这里我们思考一个问题,假设我们要代理不同接口的对象呢,那我们该怎么办, 假设我们现在又有一个O接口,这样我们也可以在O接口的水平方向的子类去进行代理了。

public interface O 
    void testO();

//还是拿我们上面的Utils,再实现一个O接口
public class Utils implements A, O 
    A a;
	//o的变量
    O o;

    public Utils(A a) 
        this.a = a;
    

    @Override
    public void test() 
        System.out.println("JAVA");
        a.test();
    

    @Override
    public void testO() 
        //这里写我们需要添加的前置代码
        //调接口方法, 
		o.test();
        //这里写我们需要添加的后置代码
    


class Test 
    public static void main(String[] args) 
        C c = new C();
        Utils utils = new Utils(c);
        utils.a = c;

        X x = new X();
        x.specialX(utils);
    


缺点:这么做法还是有一定的局限性的,Utils是我们的代理类,当我们需要代理某个接口的水平方向上的子类对象时候,就需要去实现对应的接口,而且还要复写很多的方法和代码,对于编程的设计思想来说尽量不要去动已经定义好的类,不要试图去修改一个类,可以添加类,但尽量不要修改一个类。

我们上面的Utils实现了两个接口,显示这是不好的,我们代理A用一个代理类,如果还需要代理O,那么我们再新建一个O的代理类即可,如下

public class UtilsO implements O 
    O o;

    @Override
    public void testO() 

    

所以呢静态代理,我们想要代理哪个接口就去新建一个对应的类,实现对应的接口,持有一个代理接口类型的变量,重写接口中需要代理的方法,将需要插入的代码写在里面。

2. 动态代理

静态代理我们也看到了它的缺点,每代理一个接口就要额外定义一个类,导致类的数目不断增加。

下面我们看看动态代理。我们先回顾一下java的知识,我们每新建一个类它都是.java类型的文件通过javac命令编译成了.class文件,通过IO流的操作,从硬盘中把.class文件加载到内存中,变成一个Class对象,动态代理其实就是JDK给我们提供好的。

3. 动态代理的实现

– 我要代理哪个接口

– 被代理对象是谁

– 插入的代码是什么

public class Student implements Person
    @Override
    public void test() 
        System.out.println("Student");
    


public class Teacher implements Person
    @Override
    public void test() 
        System.out.println("Teacher");
    


public class A implements InvocationHandler 
    //这个引用会和静态代理一样指向我们的要代理的真实对象
    Object object;

    //这个地方写我们需要额外插入的代码
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
        System.out.println("java前");
        //首先我们要先调用一下被代理对象的被代理方法。
        method.invoke(object, args);
        System.out.println("java后");
        return null;
    



public interface Person 
    void test();


class Test 
    public static void main(String[] args) 
        //第一步先生成我们想代理的对象,我们想代理的这个对象是Student
        Student student = new Student();
        //A是我们的代理类,生成我们的代理对象
        A a = new A();
        //引用指向我们的被代理对象student
        a.object = student;
        //第一个参数写被代理对象的Classloader
        //p指向Proxy.newProxyInstance所生成的对象,它是代理的接口所生成的对象
        Person p = (Person) Proxy.newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(), a);
       //访问的是代理接口的那个test方法
        p.test();
    


输出
java前
Student
java后



代理的方法一定要属于某个接口的。

二. Retrofit代理模式分析

Retrofit其实就是对Okhttp的一次封装,先回顾一下Okhttp的用法。

public class MainActivity extends AppCompatActivity 
    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = findViewById(R.id.tv_view);
        OkHttpClient okHttpClient = new OkHttpClient();
        RequestBody body = new FormBody.Builder().add("InfoOne", textView.getText().toString()).build();
        final Request request = new Request.Builder().url("https//www.baidu.com/").post(body).build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() 
            @Override
            public void onFailure(Call call, IOException e) 

            

            @Override
            public void onResponse(Call call, Response response) throws IOException 
                if (response.isSuccessful())
                    String string = response.body().toString();

                
            
        );
    

接下来我们看Retrofit,其实它最终也是通过Okhttp来发送网络请求,只不过在外面加多了一层封装,更好的提升了代码的复用性,扩展性。

Retrofit的流程

  1. 首先会定义好一个接口层,代理前统一处理:把接口解析成okhttprequest,这个解析的过程就用到了我们的动态代理,通过invoke方法将它们解析成不同的call,可以访问网络,然后就丢给Okhttp的网络请求类,

我们进入到retrofit.create方法里面,

//这里其实就用到了我们的动态代理模式,
public <T> T create(final Class<T> service) 
  Utils.validateServiceInterface(service);
  if (validateEagerly) 
    eagerlyValidateMethods(service);
  
   //这里就构建出了一个动态的代理类,在我们的代码运行之前是不存在的,调用之前.class字节码文件是未生成的,通过JDK动态生成
  return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]  service ,
      new InvocationHandler() 
        private final Platform platform = Platform.get();
        private final Object[] emptyArgs = new Object[0];

        @Override public @Nullable Object invoke(Object proxy, Method method,
            @Nullable Object[] args) throws Throwable 
          // If the method is a method from Object then defer to normal invocation.
          if (method.getDeclaringClass() == Object.class) 
            return method.invoke(this, args);
          
          if (platform.isDefaultMethod(method)) 
            return platform.invokeDefaultMethod(method, service, proxy, args);
          
          return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
        
      );



//这个接口是我们自定义的,不是源码,在调用creat的时候就会将这个接口里面的参数进行收集,然后通过一个统一的方式去构建出一个okhttp的request,最终构建出我们的Call对象
public interface Github 
    @GET("/repos/owner/repo/contributor")
    Call<List<Contributor>> contributors(@Path("owner") String owner, @Path("repo") String repo);



public class MainActivity extends AppCompatActivity 
    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = findViewById(R.id.tv_view);
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://www.baidu.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        Github github = retrofit.create(Github.class);
        //这里构建出call对象
        Call<List<Contributor>> call = github.contributors("Square", "retrofit");
        try 
            List<Contributor> contributors = call.execute().body();
            for (Contributor contributor : contributors) 
                
            
         catch (IOException e) 
            e.printStackTrace();
        
    

小结:为什么它用到代理模式呢,因为retrofit自己本身是不做什么事情的,最后的请求网络还是由okhttp完成,okhttp这里可以看成是委托类,所以它是一个代理类。为什么它不用静态代理而用动态代理呢,因为请求网络会有各种各样的接口,如果一个个的去写对应接口的代理类,那么数量就会很多,代码量就会很大,

优点:

• 可以配置不同HTTP client来实现网络请求,如okhttp、httpclient等;

• 请求的方法参数注解都可以定制;

• 支持同步、异步和RxJava;

• 超级解耦;

• 可以配置不同的反序列化工具来解析数据,如json、xml等;

   
     catch (IOException e) 
        e.printStackTrace();
    


小结:为什么它用到代理模式呢,因为retrofit自己本身是不做什么事情的,最后的请求网络还是由okhttp完成,okhttp这里可以看成是委托类,所以它是一个代理类。为什么它不用静态代理而用动态代理呢,因为请求网络会有各种各样的接口,如果一个个的去写对应接口的代理类,那么数量就会很多,代码量就会很大,

优点:

•  可以配置不同HTTP client来实现网络请求,如okhttp、httpclient等;

•  请求的方法参数注解都可以定制;

•  支持同步、异步和RxJava;

•  超级解耦;

•  可以配置不同的反序列化工具来解析数据,如json、xml等;

•  使用非常方便灵活;

代理模式(静态代理,JDK动态代理,JDK动态代理原理分析)

代理模式

静态代理

代理类和被代理类在编译期间就已经确定了。

package org.westos.demo4;

/**
 * @author lwj
 * @date 2020/6/14 15:42
 */
public interface UserDao {
    void add();

    void delete();

    void update();

    void query();
}
package org.westos.demo4;

/**
 * @author lwj
 * @date 2020/6/14 15:42
 */
public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("添加一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除一个用户");
    }

    @Override
    public void update() {
        System.out.println("更新用户信息");
    }

    @Override
    public void query() {
        System.out.println("查询用户信息");
    }
}

静态代理类

package org.westos.demo4;

/**
 * @author lwj
 * @date 2020/6/14 15:43
 */
public class UserDaoStaticProxy implements UserDao {
    private UserDao userDao;

    public UserDaoStaticProxy(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void add() {
        System.out.println("权限校验");
        userDao.add();
        System.out.println("输出日志");
    }

    @Override
    public void delete() {
        System.out.println("权限校验");
        userDao.delete();
        System.out.println("输出日志");
    }

    @Override
    public void update() {
        System.out.println("权限校验");
        userDao.update();
        System.out.println("输出日志");
    }

    @Override
    public void query() {
        System.out.println("权限校验");
        userDao.query();
        System.out.println("输出日志");
    }
}

测试类

package org.westos.demo4;

/**
 * @author lwj
 * @date 2020/6/14 15:45
 */
public class MyTest {
    public static void main(String[] args) {
        UserDaoImpl impl = new UserDaoImpl();
        UserDaoStaticProxy userDaoStaticProxy = new UserDaoStaticProxy(impl);
        userDaoStaticProxy.add();
        //权限校验
        //添加一个用户
        //输出日志
    }
}

动态代理

package org.westos.demo5;

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

/**
 * @author lwj
 * @date 2020/6/14 15:53
 */
public class ProxyFactory {
    public static Object getProxyInstance(Object obj) {
        //obj被代理对象

        /*
        加载代理类,和被代理类的类加载器一致
        被代理类所实现的接口
        InvocationHandler:
         */
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //需要我们自己编写的增强的代码
                        //proxy:代理对象  Method:被代理类的方法对象  args:被代理类的方法需要的参数
                        System.out.println("权限校验");
                        Object invoke = method.invoke(obj, args);
                        //调用被代理类的方法执行
                        System.out.println("输出日志");
                        return invoke;
                    }
                });
    }
}

测试类

package org.westos.demo5;

import org.westos.demo4.UserDao;
import org.westos.demo4.UserDaoImpl;

/**
 * @author lwj
 * @date 2020/6/14 16:10
 */
public class MyTest {
    public static void main(String[] args) {
        UserDaoImpl impl = new UserDaoImpl();
        UserDao proxyInstance = (UserDao) ProxyFactory.getProxyInstance(impl);
        System.out.println(proxyInstance.getClass());
        //class com.sun.proxy.$Proxy0
        proxyInstance.add();
        //权限校验
        //添加一个用户
        //输出日志
    }
}

或者

package org.westos.proxy;

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

/**
 * @author lwj
 * @date 2020/6/14 17:51
 */
public class ProxyFactory {
    public static Object getProxyInstance(Object obj) {
        //obj 被代理对象
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(obj);
        /*
        代理类实现被代理类实现的接口
        用被代理类的类加载器加载代理类
         */
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
                myInvocationHandler);
    }
}

class MyInvocationHandler implements InvocationHandler {
    private Object obj;
    //被代理对象

    public MyInvocationHandler(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("权限校验");
        Object invoke = method.invoke(obj, args);
        System.out.println("输出日志");
        return invoke;
    }
}

测试类

package org.westos.proxy;

/**
 * @author lwj
 * @date 2020/6/14 17:52
 */
public class MyTest {
    public static void main(String[] args) {
        UserDaoImpl impl = new UserDaoImpl();
        UserDao proxyInstance = (UserDao) ProxyFactory.getProxyInstance(impl);
        System.out.println(proxyInstance.getClass());
        //class com.sun.proxy.$Proxy0
        proxyInstance.add();
    }
}

上述两种方式都可以。

动态代理原理分析

对于接口来说,使用JDK的动态代理来实现,就是上面的两种方式,而对于类的代理,使用CGLIB来实现。

JDK的动态代理,就是在程序运行的过程中,根据被代理的接口来动态生成代理类的class文件,并加载运行的过程。

JDK提供了java.lang.reflect.Proxy类来实现动态代理,可通过它的newProxyInstance()方法来获得代理实现类对象,同时对于代理的接口的实际处理,是一个java.lang.reflect.InvocationHandler,它提供了invoke()方法供实现者提供相应的代理逻辑,可以对实际的实现进行特殊处理。

首先来看newProxyInstance()方法,

@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        Class<?> cl = getProxyClass0(loader, intfs);
        //真正生成代理类class对象的地方

        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
            //将自定义的InvocationHandler对象作为代理类的构造方法的参数,创建代理类的实例对象
        } 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()方法,

private static Class<?> getProxyClass0(ClassLoader loader,
                                       Class<?>... interfaces) {
    if (interfaces.length > 65535) {
        //代理的接口数量不能大于65535
        throw new IllegalArgumentException("interface limit exceeded");
    }

    // If the proxy class defined by the given loader implementing
    // the given interfaces exists, this will simply return the cached copy;
    // otherwise, it will create the proxy class via the ProxyClassFactory
    
    //JDK对代理进行了缓存,如果已经存在相应的代理类,则直接返回,否则才会通过ProxyClassFactory来创建代理
    return proxyClassCache.get(loader, interfaces);
}

这里关心ProxyClassFactory是如何生成代理类的,ProxyClassFactory是Proxy的一个静态内部类,

private static final class ProxyClassFactory
    implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // prefix for all proxy class names 所有代理类的前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        // next number to use for generation of unique proxy class names
        // 用于生成代理类名字的计数器
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            //...省略验证接口的代码

            String proxyPkg = null;     // package to define proxy class in
            //生成的代理类的包名
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
             //对于非公共接口,代理类的包名和接口的包名相同
            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) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                // 公共接口的包名,默认为com.sum.proxy.
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;
			//默认情况下,代理类的完全限定名为:com.sun.proxy.$Proxy0,com.sun.proxy.$Proxy1……依次递增
			
            /*
             * Generate the specified proxy class.
             * 生成代理类的字节码文件
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
                
            try {
            	//根据二进制字节码返回相应的Class实例
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

ProxyGenerator类是sun.misc包中的类,

public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
    ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
    final byte[] var4 = var3.generateClassFile();
    if (saveGeneratedFiles) {
        //根据此boolean类型参数决定是否把生成的字节码保存在本地磁盘
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {
                try {
                    int var1 = var0.lastIndexOf(46);
                    Path var2;
                    if (var1 > 0) {
                        Path var3 = Paths.get(var0.substring(0, var1).replace(‘.‘, File.separatorChar));
                        Files.createDirectories(var3);
                        var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                    } else {
                        var2 = Paths.get(var0 + ".class");
                    }

                    Files.write(var2, var4, new OpenOption[0]);
                    return null;
                } catch (IOException var4x) {
                    throw new InternalError("I/O exception saving generated file: " + var4x);
                }
            }
        });
    }

    return var4;
}

那么这个参数为:

private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));

GetBooleanAction实际上是调用Boolean.getBoolean(propName)来获得的,

return Boolean.getBoolean(this.theProp)

Boolean.getBoolean(propName)调用了System.getProperty(name),

public static boolean getBoolean(String name) {
    boolean result = false;
    try {
        result = parseBoolean(System.getProperty(name));
    } catch (IllegalArgumentException | NullPointerException e) {
    }
    return result;
}

所以我们可以设置

sun.misc.ProxyGenerator.saveGeneratedFiles这个系统属性为true来把生成的class保存到本地文件来查看。

在之前的测试类中增加一条代码,设置系统属性,

package org.westos.demo5;

import org.westos.demo4.UserDao;
import org.westos.demo4.UserDaoImpl;

/**
 * @author lwj
 * @date 2020/6/14 16:10
 */
public class MyTest {
    public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        UserDaoImpl impl = new UserDaoImpl();
        UserDao proxyInstance = (UserDao) ProxyFactory.getProxyInstance(impl);
        System.out.println(proxyInstance.getClass());
        //class com.sun.proxy.$Proxy0
        proxyInstance.add();
        //权限校验
        //添加一个用户
        //输出日志
    }
}

该代理类的class字节码文件保存在com.sun.proxy目录下,

package com.sun.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import org.westos.demo4.UserDao;

public final class $Proxy0 extends Proxy implements UserDao {
    private static Method m1;
    private static Method m6;
    private static Method m2;
    private static Method m3;
    private static Method m5;
    private static Method m0;
    private static Method m4;

    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 void query() throws  {
        try {
            super.h.invoke(this, m6, (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 add() 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 delete() throws  {
        try {
            super.h.invoke(this, m5, (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 update() throws  {
        try {
            super.h.invoke(this, m4, (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"));
            m6 = Class.forName("org.westos.demo4.UserDao").getMethod("query");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("org.westos.demo4.UserDao").getMethod("add");
            m5 = Class.forName("org.westos.demo4.UserDao").getMethod("delete");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m4 = Class.forName("org.westos.demo4.UserDao").getMethod("update");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

JDK的动态代理类:

  • 继承了Proxy类,实现了接口,正是由于Java不支持多继承,所以动态代理类已经继承了Proxy类,则不能则继承其他类,所以JDK的动态代理只能代理接口,而不能代理类;
  • 提供了一个InvocationHandler类型参数的构造方法;
  • 提供静态代码块来初始化接口中方法的Method对象;
  • 可以看到在代理类实现接口的方法中,都调用了InvocationHandler对象的invoke()方法,所以在执行接口中的方法时,都会执行InvocationHandler的invoke()方法。

以上是关于Android代理模式(静态代理,动态代理,Retrofit代理模式分析)的主要内容,如果未能解决你的问题,请参考以下文章

Android知识体系梳理笔记三:动态代理模式---插件加载机制学习笔记

代理模式(静态代理jdk动态代理CGLib动态代理)

代理模式(静态代理,JDK动态代理,JDK动态代理原理分析)

代理模式(静态代理动态代理)代码实战(详细)

设计模式 结构型模式 -- 代理模式(代理模式概述结构静态代理动态代理)

Spring之静态/动态代理模式