设计模式之代理模式(二)——动态代理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Back_Light_F/article/details/82993445

动态代理:在程序运行时,通过反射机制动态的创建一个代理类

先来一个小Demo,逐步理解动态代理

  1.声明一个接口,里面有一个move的方法

public interface Moveable {
    void move();
}

2.创建一个Tank类,实现上面的接口,重写方法:

public class Tank implements Moveable{
    @Override
    public void move() {
        System.out.println("Tank Moving");
        try {
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

问题1:想知道这个方法运行了多少时间?

简单啊,在方法前后加个currentTimeMills()就行了。

  @Override
    public void move() {
        long start = System.currentTimeMillis();
          //中间代码略过
        long end = System.currentTimeMillis();
        System.out.println("Time:"+(end-start));
    }

问题2:假如无法更改move方法,我们没法在原来的源码上进行修改,而这时我们想知道这个方法运行了多长时间,该怎么做?

            方法一:新建一个类继承Tank,既然能继承就能重写Tank的方法:也就是用继承来实现把原来的方法前后添加一些逻辑:

public class Tank2 extends Tank {

    @Override
    public void move() {
        long start = System.currentTimeMillis();
        super.move();
        long end = System.currentTimeMillis();
        System.out.println("Time:"+(end-start));
    }

}

             方法二:新建一个Tank3类,类中添加一个Tank的引用,这种方式是用聚合的方式实现的:

public class Tank3 implements Moveable{
    private Tank t;

    public Tank getT() {
        return t;
    }

    public void setT(Tank t) {
        this.t = t;
    }
    public Tank3(Tank t){
        this.t = t;
    }

    @Override
    public void move() {
        long start = System.currentTimeMillis();
        t.move();
        long end = System.currentTimeMillis();
        System.out.println("Time:"+(end-start));
    }
}

上面两种方式:聚合的实现方式是比继承方式好的,为什么呢?

先对代码进行修改:

记录时间的代理类:
 

public class TankTimeProxy implements Moveable{
    private Tank t;

    public Tank getT() {
        return t;
    }

    public void setT(Tank t) {
        this.t = t;
    }
    public TankTimeProxy(Tank t){
        this.t = t;
    }

    @Override
    public void move() {
        long start = System.currentTimeMillis();
        t.move();
        long end = System.currentTimeMillis();
        System.out.println("Time:"+(end-start));
    }
}

记录日志的代理类:

public class TankLogProxy implements Moveable{
    private Tank t;

    public Tank getT() {
        return t;
    }

    public void setT(Tank t) {
        this.t = t;
    }
    public TankLogProxy(Tank t){
        this.t = t;
    }

    @Override
    public void move() {
        System.out.println("Tank start");
        t.move();
        System.out.println("tank end");
    }
}

如果现在要实现记录时间和记录日志功能的叠加,应该怎么做?

       现在如果使用继承的方式实现代理,就会变得十分笨重,类会无限的增加下去,而且各种各样的代理的功能要实现叠加的话,这个类的继承的层次会变得非常复杂。

       如果用聚合的方式来实现:

public class TankLogProxy implements Moveable{
    Moveable t;

    public TankLogProxy(Moveable t){
        this.t = t;
    }
    @Override
    public void move() {
        System.out.println("Tank start");
        t.move();
        System.out.println("tank end");
    }
}
public class TankTimeProxy implements Moveable{
     Moveable t;

    public TankTimeProxy(Tank t){
        this.t = t;
    }

    @Override
    public void move() {
        long start = System.currentTimeMillis();
        t.move();
        long end = System.currentTimeMillis();
        System.out.println("Time:"+(end-start));
    }
}

测试:

public class Client {
    public static void main(String[] args) {
        Tank t = new Tank();
        TankTimeProxy ttp = new TankTimeProxy(t);
        TankLogProxy tlp = new TankLogProxy(ttp);
        Moveable m = tlp;
        m.move();
    }
}

上面是日志里面包裹着时间,那么我们想让时间包着日志呢?

public class Client {
    public static void main(String[] args) {
        Tank t = new Tank();
        TankLogProxy tlp = new TankLogProxy(t);
        TankTimeProxy ttp = new TankTimeProxy(tlp);
        Moveable m = ttp;
        m.move();
    }
}

这种聚合方式可以让代理类之间灵活的组合,只要实现统一接口。

上面只是介绍了静态代理。

现在:如果Movable中增加了一个方法,那么他的实现类也要增加相应的方法。而在TankTimeProxy中想要知道新的方法的执行时间,还要将currentTimeMills()重新写一遍,如下所示

public interface Moveable {
    void move();
    void stop();
}
public class TankTimeProxy implements Moveable{
     Moveable t;

    public TankTimeProxy(Moveable t){
        this.t = t;
    }

    @Override
    public void move() {
        long start = System.currentTimeMillis();
        t.move();
        long end = System.currentTimeMillis();
        System.out.println("Time:"+(end-start));
    }

    @Override
    public void stop() {
        long start = System.currentTimeMillis();
        t.stop();
        long end = System.currentTimeMillis();
        System.out.println("Time:"+(end-start));
    }
}
public class Tank implements Moveable{
    @Override
    public void move() {
        long start = System.currentTimeMillis();
        System.out.println("Tank Moving");
        try {
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
       /* long end = System.currentTimeMillis();
        System.out.println("Time:"+(end-start));*/
    }

    @Override
    public void stop() {
        System.out.println("Tank Stoping..");
    }
}

当在写代码的时候,发现有些代码总是反复的写,这时候就要考虑将他们封装起来。

现在,如果想再加一个Car类上的时间的代理,如果用上的方式,还需要新建一个CarTimeProxy。如果有很多类,就需要新建很多代理类。这时,如果搞一个通用的时间代理类,可以代理任意的对象就好了。

新建一个Proxy类:

public class Proxy {
    //用来产生新的代理类
    public static Object newProxyInstance(){
        return null;
    }
}

现在我们假设上面类已经能产生代理了,客户端就可以这样写:

public class Client {
    public static void main(String[] args) {
        Tank t = new Tank();
        Moveable m = (Moveable)Proxy.newProxyInstance();
        m.move();
    }
}

但是Proxy类是如何代理的呢?

这就是动态代理了。动态代理的意思就是:我们不需要知道TankTimeProxy这个类的名字,我们需要的那个代理对象直接产生,

public class Proxy {
    //用来产生新的代理类
    public static Object newProxyInstance(){

        String src = "package com.yuanben.msbproxy;"+
        "public class TankTimeProxy implements Moveable{"+
            "public TankTimeProxy(Moveable t){"+
                "super();"+
                "this.t = t;"+
            "}"+

            "Moveable t;"+

            "@Override"+
            "public void move() {"+
                "long start = System.currentTimeMillis();"+
                "t.move();"+
                "long end = System.currentTimeMillis();"+
                "System.out.println(\"Time:\"+(end-start));"+
            "}"+
        "}";
        return null;
    }
}

在Proxy的newProxyInstance方法内部会自动的返回一个具体的代理,而这个代理是怎么实现的呢?实际上是内部自己生成一段代码,这段代码编译完成之后生成一个具体的对象。现在的问题是如果我们能动态编译这段代码的话,就能生成动态的代理类。

实现动态代理的方式:JDK、CGlib、ASM。

如何编译:

public class Test1 {
    public static void main(String[] args) throws Exception{

        String rt = "\r\n";

        String src = "package com.yuanben.msbproxy;"+rt+
                "public class TankTimeProxy implements Moveable{"+rt+
                "public TankTimeProxy(Moveable t){"+rt+
                "super();"+rt+
                "this.t = t;"+rt+
                "}"+rt+

                "Moveable t;"+rt+

                "@Override"+rt+
                "public void move() {"+rt+
                "long start = System.currentTimeMillis();"+rt+
                "t.move();"+rt+
                "long end = System.currentTimeMillis();"+rt+
                "System.out.println(\"Time:\"+(end-start));"+rt+
                "}"+rt+
                "}";

        String fileName = System.getProperty("user.dir")+
"/spring_aop/src/com/yuanben/msbproxy/TankTimeProxy.java";


        File f = new File(fileName);
        FileWriter fw = new FileWriter(f);
        fw.write(src);
        fw.flush();
        fw.close();

    }

}

运行代码:发现生生成了TankTimeProxy类:

Test1类中加如下代码:

 //得到编译器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
        Iterable units =  fileManager.getJavaFileObjects(fileName);
        JavaCompiler.CompilationTask t = compiler.getTask(null,fileManager,null,null,null,units);
        t.call();
        fileManager.close();

运行:编译成功

生成代理类:

public class Test1 {
    public static void main(String[] args) throws Exception{

        String rt = "\r\n";

        String src = "package com.yuanben.msbproxy;"+rt+
                "     public class TankTimeProxy implements Moveable{"+rt+
                "          public TankTimeProxy(Moveable t){"+rt+
                "               super();"+rt+
                "               this.t = t;"+rt+
                "          }"+rt+

                "           Moveable t;"+rt+

                "     @Override"+rt+
                "     public void move() {"+rt+
                "          long start = System.currentTimeMillis();"+rt+
                "          t.move();"+rt+
                "          long end = System.currentTimeMillis();"+rt+
                "          System.out.println(\"Time:\"+(end-start));"+rt+
                "    }"+rt+
                "}";

        String fileName = System.getProperty("user.dir")+"/spring_aop/src/com/yuanben/msbproxy/TankTimeProxy.java";


//        File f = new File(fileName);
//        FileWriter fw = new FileWriter(f);
//        fw.write(src);
//        fw.flush();
//        fw.close();

        //得到编译器
       JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
        Iterable units =  fileManager.getJavaFileObjects(fileName);
        JavaCompiler.CompilationTask t = compiler.getTask(null,fileManager,null,null,null,units);
        t.call();
        fileManager.close();

        //将编译好的class文件加载进内存并生成一个对象
        URL[]  urls = new URL[]{new URL("file:/"+System.getProperty("user.dir")+"/spring_aop/src")};
        URLClassLoader ul = new URLClassLoader(urls);
        Class c = ul.loadClass("com.yuanben.msbproxy.TankTimeProxy");
        System.out.println(c);
        //生成一个对象:反射
        Constructor constructor =    c.getConstructor(Moveable.class);
        Moveable  m  =  (Moveable)constructor.newInstance(new Tank());
        m.move();
    }

}

运行:

到此为止,Proxy只能产生实现了Moveable接口的类的代理,如果现在要实现别的类的动态代理,应该怎么做?

方案:把接口传进去,对Proxy进行改造:

public class Proxy {
    //用来产生新的代理类
    public static Object newProxyInstance(Class infce) throws Exception{

        String rt = "\r\n";

        String src = "package com.yuanben.msbproxy;"+rt+
                "     public class TankTimeProxy implements "+infce.getName()+"{"+rt+
                "          public TankTimeProxy(Moveable t){"+rt+
                "               super();"+rt+
                "               this.t = t;"+rt+
                "          }"+rt+

                "           Moveable t;"+rt+

                "     @Override"+rt+
                "     public void move() {"+rt+
                "          long start = System.currentTimeMillis();"+rt+
                "          t.move();"+rt+
                "          long end = System.currentTimeMillis();"+rt+
                "          System.out.println(\"Time:\"+(end-start));"+rt+
                "    }"+rt+
                "}";

        String fileName = System.getProperty("user.dir")+"/spring_aop/src/com/yuanben/msbproxy/TankTimeProxy.java";


        File f = new File(fileName);
        FileWriter fw = new FileWriter(f);
        fw.write(src);
        fw.flush();
        fw.close();

        //得到编译器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
        Iterable units =  fileManager.getJavaFileObjects(fileName);
        JavaCompiler.CompilationTask t = compiler.getTask(null,fileManager,null,null,null,units);
        t.call();
        fileManager.close();

        //将编译好的class文件加载进内存并生成一个对象
        URL[]  urls = new URL[]{new URL("file:/"+System.getProperty("user.dir")+"/spring_aop/src")};
        URLClassLoader ul = new URLClassLoader(urls);
        Class c = ul.loadClass("com.yuanben.msbproxy.TankTimeProxy");
        System.out.println(c);
        //生成一个对象:反射
        Constructor constructor =    c.getConstructor(Moveable.class);
        Moveable  m  =  (Moveable)constructor.newInstance(new Tank());
        m.move();

        return null;
    }
}

直接传递接口即可:

现在要获取传进入的接口中有多少方法:还是用反射的知识:

public class Test2 {
    public static void main(String[] args) {
        Method[] methods = com.yuanben.msbproxy.Moveable.class.getMethods();
        Arrays.stream(methods).forEach(method -> System.out.println(method));
    }
}

再做改进:生成实现方法:

public class Proxy {
    //用来产生新的代理类
    public static Object newProxyInstance(Class infce) throws Exception{

        String rt = "\r\n";
        String methodStr = "";
        Method[] methods = infce.getMethods();
        for (Method m:methods
             ) {
            methodStr += "@Override" + rt +
                                    "public void "+m.getName()+"() {"+rt+
                                    "          long start = System.currentTimeMillis();"+rt+
                                    "          t."+m.getName()+"();"+rt+
                                    "          long end = System.currentTimeMillis();"+rt+
                                    "          System.out.println(\"Time:\"+(end-start));"+rt+
                                "}";

        }



        String src = "package com.yuanben.msbproxy;"+rt+
                "     public class TankTimeProxy implements "+infce.getName()+"{"+rt+
                "          public TankTimeProxy(Moveable t){"+rt+
                "               super();"+rt+
                "               this.t = t;"+rt+
                "          }"+rt+

                "           Moveable t;"+rt+

               methodStr+
                "}";

        String fileName = System.getProperty("user.dir")+"/spring_aop/src/com/yuanben/msbproxy/TankTimeProxy.java";


        File f = new File(fileName);
        FileWriter fw = new FileWriter(f);
        fw.write(src);
        fw.flush();
        fw.close();

        //得到编译器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
        Iterable units =  fileManager.getJavaFileObjects(fileName);
        JavaCompiler.CompilationTask t = compiler.getTask(null,fileManager,null,null,null,units);
        t.call();
        fileManager.close();

        //将编译好的class文件加载进内存并生成一个对象
        URL[]  urls = new URL[]{new URL("file:/"+System.getProperty("user.dir")+"/spring_aop/src")};
        URLClassLoader ul = new URLClassLoader(urls);
        Class c = ul.loadClass("com.yuanben.msbproxy.TankTimeProxy");
        System.out.println(c);
        //生成一个对象:反射
        Constructor constructor =    c.getConstructor(Moveable.class);
       /* Moveable  m  =  (Moveable)constructor.newInstance(new Tank());
        m.move();*/

        return null;
    }
}

测试:已经帮我们成功生成

如果换成别的接口:

public class Client {
    public static void main(String[] args) throws Exception{
        Tank t = new Tank();
        Moveable m = (Moveable)Proxy.newProxyInstance(Comparable.class);

    }
}

 会帮我们生成Comparable接口中的方法

那好,现在又有新的问题了。现在我们生成的代理的中间逻辑是固定的,只能生成运行时间的代理功能,如果要生成日志代理,这个方法就不行了,我们就需要写一个新的方法newProxyInstence2用来生成日志代理。。。。这时候我们应该怎么办?让中间的业务逻辑让用户来指定。也就是我们需要对一个任意的方法进行自定义的处理。思路如下:

声明一个接口,含一个方法:

public interface InvocationHandler {
     void invoke(Method method);
}

写一个实现类,加上自己想要的处理逻辑:

public class TimeHandler implements InvocationHandler {

    //将想要调用的方法传入进来
    @Override
    public void invoke(Method m) {
        long start = System.currentTimeMillis();
        System.out.println("startTime:"+start);
        m.getName();
        long end = System.currentTimeMillis();
        System.out.println("Time:"+(end-start));

    }
}

现在,对方法的处理就变得更灵活了。那里面的方法是如何调用的呢?往下看:

在接口方法中添加一个Object参数,表示那个对象去调用这个方法:

public interface InvocationHandler {
     void invoke(Object o,Method method);
}

实现类做如下修改:

public class TimeHandler implements InvocationHandler {

    //将想要调用的方法传入进来
    @Override
    public void invoke(Object o,Method m) {
        long start = System.currentTimeMillis();
        System.out.println("startTime:"+start);
        try {
            m.invoke(o,new Object[]{ });
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("Time:"+(end-start));

    }
}

Proxy类:

public class Proxy {
    //用来产生新的代理类
    public static Object newProxyInstance(Class infce,InvocationHandler h) throws Exception{

        String rt = "\r\n";
        String methodStr = "";
        Method[] methods = infce.getMethods();
        for (Method m:methods) {
            methodStr += "@Override" + rt +
                                    "public void "+m.getName()+"() {"+rt+
                                    "     try{"+rt+
                                    "      Method md =    "+infce.getName()+".class.getMethod(\""+m.getName()+"\");"+rt+
                                    "      h.invoke(this,md);"+rt+
                                    "      }catch(Exception e){"+rt+
                                    "     e.printStackTrace();  }"+rt+

                                "}";

        }



        String src = "package com.yuanben.msbproxy;"+rt+
                "     import java.lang.reflect.Method;"+rt+
                "     public class TankTimeProxy implements "+infce.getName()+"{"+rt+
                "          public TankTimeProxy(InvocationHandler h){"+rt+
                "               super();"+rt+
                "               this.h = h;"+rt+
                "          }"+rt+

                "           com.yuanben.msbproxy.InvocationHandler h;"+rt+

               methodStr+
                "}";

        String fileName = System.getProperty("user.dir")+"/spring_aop/src/com/yuanben/msbproxy/TankTimeProxy.java";


        File f = new File(fileName);
        FileWriter fw = new FileWriter(f);
        fw.write(src);
        fw.flush();
        fw.close();

        //得到编译器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
        Iterable units =  fileManager.getJavaFileObjects(fileName);
        JavaCompiler.CompilationTask t = compiler.getTask(null,fileManager,null,null,null,units);
        t.call();
        fileManager.close();

        //将编译好的class文件加载进内存并生成一个对象
        URL[]  urls = new URL[]{new URL("file:/"+System.getProperty("user.dir")+"/spring_aop/src")};
        URLClassLoader ul = new URLClassLoader(urls);
        Class c = ul.loadClass("com.yuanben.msbproxy.TankTimeProxy");
        System.out.println(c);
        //生成一个对象:反射
        Constructor constructor =    c.getConstructor(InvocationHandler.class);
        Object  m  =  constructor.newInstance(h);

        //将对象返回出去
        return m;
    }
}

运行,生成需要的代理类:

TimeHandler:

public class TimeHandler implements InvocationHandler {

    //被代理的对象
    private Object target;

    public Object getT() {
        return target;
    }

    public void setT(Object t) {
        this.target = t;
    }

    public TimeHandler(Object target){
        super();
        this.target = target;
    }


    //将想要调用的方法传入进来
    @Override
    public void invoke(Object o,Method m) {
        long start = System.currentTimeMillis();
        System.out.println("startTime:"+start);
        try {
            m.invoke(target);
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("Time:"+(end-start));

    }
}

Client类:

public class Client {
    public static void main(String[] args) throws Exception{
        Tank t = new Tank();
        InvocationHandler h =  new TimeHandler(t);
        Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class,h);
        m.move();
    }
}

结果:

其实JDK实现的动态代理的思路也和上面的步骤类似。下面分析一下JDK实现动态代理的源码:解析都在代码注释中:

/**
 * {@code Proxy}代理类:为创建动态代理类和实例提供静态方法,同样也是所有通过那些方法创建动态代理的超类
 */
public class Proxy implements java.io.Serializable {

    private static final long serialVersionUID = -2222568056686623797L;

    /** 代理构造函数的参数类型 */
    private static final Class<?>[] constructorParams =
            { InvocationHandler.class };

    /**
     *代理类缓存
     */
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
            proxyClassCache = new WeakCache<>(new java.lang.reflect.Proxy.KeyFactory(), new java.lang.reflect.Proxy.ProxyClassFactory());

    /**
     * 此代理实例的调用处理程序。
     * @serial
     */
    protected InvocationHandler h;

    /**
     * Prohibits instantiation.
     */
    private Proxy() {
    }

    /**
构造器,
     */
    protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }

    //获取目标代理类的Class对象,需传入类加载器对象和被代理类实现接口数组
    @CallerSensitive
    public static Class<?> getProxyClass(ClassLoader loader,
                                         Class<?>... interfaces)
            throws IllegalArgumentException
    {
        //克隆接口数组
        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            //校验代理类的访问权限
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }
        //获取代理类的Class对象
        return getProxyClass0(loader, intfs);
    }

    /*
        校验代理类的访问权限
     */
    private static void checkProxyAccess(Class<?> caller,
                                         ClassLoader loader,
                                         Class<?>... interfaces)
    {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            //获取调用者的类加载器
            ClassLoader ccl = caller.getClassLoader();
            if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
            }
            ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
        }
    }

    /**
     * 生成一个代理类.  在调用此方法之前,必须调用checkProxyAccess方法来执行权限检查。
     */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 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
        /*
        如果当前这个接口数组已经存在就返回缓存中的副本,否则的话,就会通过ProxyClassFactory去创建一个Class对象
         */

        return proxyClassCache.get(loader, interfaces);
    }

    /*
     * 用于带有0个实现接口的代理类的key值
     */
    private static final Object key0 = new Object();

    /*
     * Key1 and Key2 are optimized for the common use of dynamic proxies
     * that implement 1 or 2 interfaces.
     */

    /*
     * 用于带有1个实现接口的代理类的key值
     */
    private static final class Key1 extends WeakReference<Class<?>> {
        private final int hash;

        Key1(Class<?> intf) {
            super(intf);
            this.hash = intf.hashCode();
        }

        @Override
        public int hashCode() {
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            Class<?> intf;
            return this == obj ||
                    obj != null &&
                            obj.getClass() == java.lang.reflect.Proxy.Key1.class &&
                            (intf = get()) != null &&
                            intf == ((java.lang.reflect.Proxy.Key1) obj).get();
        }
    }

    /*
     *用于带有2个实现接口的代理类的key值
     */
    private static final class Key2 extends WeakReference<Class<?>> {
        private final int hash;
        //弱引用对象:存放第二个接口类对象
        private final WeakReference<Class<?>> ref2;

        Key2(Class<?> intf1, Class<?> intf2) {
            super(intf1);
            hash = 31 * intf1.hashCode() + intf2.hashCode();
            ref2 = new WeakReference<Class<?>>(intf2);
        }

        @Override
        public int hashCode() {
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            Class<?> intf1, intf2;
            return this == obj ||
                    obj != null &&
                            obj.getClass() == java.lang.reflect.Proxy.Key2.class &&
                            (intf1 = get()) != null &&
                            intf1 == ((java.lang.reflect.Proxy.Key2) obj).get() &&
                            (intf2 = ref2.get()) != null &&
                            intf2 == ((java.lang.reflect.Proxy.Key2) obj).ref2.get();
        }
    }

    /*
   这里用于带有>=3个接口的代理类的key键值
     */
    private static final class KeyX {
        //接口数组对象的hash值
        private final int hash;
        //弱引用对象数组:存放表示接口的类对象数组
        private final WeakReference<Class<?>>[] refs;

        @SuppressWarnings("unchecked")
        KeyX(Class<?>[] interfaces) {
            hash = Arrays.hashCode(interfaces);
            //构造一个弱引用对象数组
            refs = (WeakReference<Class<?>>[])new WeakReference<?>[interfaces.length];
            for (int i = 0; i < interfaces.length; i++) {
                refs[i] = new WeakReference<>(interfaces[i]);
            }
        }

        @Override
        public int hashCode() {
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            return this == obj ||
                    obj != null &&
                            obj.getClass() == java.lang.reflect.Proxy.KeyX.class &&
                            equals(refs, ((java.lang.reflect.Proxy.KeyX) obj).refs);
        }

        private static boolean equals(WeakReference<Class<?>>[] refs1,
                                      WeakReference<Class<?>>[] refs2) {
            //长度是否相等
            if (refs1.length != refs2.length) {
                return false;
            }
            //弱引用对象数组内接类是否相同
            for (int i = 0; i < refs1.length; i++) {
                Class<?> intf = refs1[i].get();
                if (intf == null || intf != refs2[i].get()) {
                    return false;
                }
            }
            return true;
        }
    }

    /**
     * 将接口数组映射到一个最佳键的函数,其中表示接口的类对象为弱引用
     */
    private static final class KeyFactory
            implements BiFunction<ClassLoader, Class<?>[], Object>
    {
        @Override
        public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
            switch (interfaces.length) {
                case 1: return new java.lang.reflect.Proxy.Key1(interfaces[0]); // the most frequent
                case 2: return new java.lang.reflect.Proxy.Key2(interfaces[0], interfaces[1]);
                case 0: return key0;
                default: return new java.lang.reflect.Proxy.KeyX(interfaces);
            }
        }
    }

    /**
     是Proxy中的一个静态内部类:主要用来根据ClassLoader和接口数组来生成Class对象的
     */
    private static final class ProxyClassFactory
            implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // 所有代理类名称的前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        // 用于生成唯一代理类名称的下一个数字
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

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

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                /*
                验证Intf接口类Class对象是否为给定的ClassLoader解析的
                 */
                Class<?> interfaceClass = null;
                try {
                    //根据接口的全限定名获取接口Class对象
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                //验证是否为同一个接口类对象,如果两次的Class对象不一致,直接抛出异常,
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                            intf + " is not visible from class loader");
                }
                /*
                判断父接口是否为接口类型,如果不是则抛出异常
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                            interfaceClass.getName() + " is not an interface");
                }
                /*
                 * 判断我们的set集合中是否已经有重复的接口
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                            "repeated interface: " + interfaceClass.getName());
                }
            }

            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
            判断非public接口是都在同一个包内
             */
            for (Class<?> intf : interfaces) {
                //获取修饰符
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {  //不是public修饰符
                    //则定义代理类的修饰符:final
                    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)) {//interface含有来自不同包的非公共接口
                        throw new IllegalArgumentException(
                                "non-public interfaces from different packages");
                    }
                }
            }


            if (proxyPkg == null) {
                // 如果没有非公共代理接口,请使用com.sun.proxy作为包名称
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * 选择要生成的代理类的名称
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * 真正生成指定代理类字节码的地方
             */
            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());
            }
        }
    }

    /**
        该方法流程:
                1.根据传进来的ClassLoader,以及我们的代理对象的父接口数组,来动态的出那个键二进制的Class文件,
            然后根据创建好的Class二进制文件,获取到创建的动态类的Class对象
                2.获取到动态创建的代理的构造方法,这个构造方法的参数是定好的,传进去的InvocationHandler,
            这个是动态代理约束好的,生成的字节码中,构造方法的参就是InvocationHandler
                3.判断构造方法的访问修饰符,如果不是Public,将其设置成可以访问的
                4.根据传递进来的具体的Handler对象和我们上面的构造方法对象,生成一个动态代理类的对象
     */
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
            throws IllegalArgumentException
    {
        //handler的非空判断
        Objects.requireNonNull(h);

        //将代理类的接口复制出来一份
        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * 根据classLoader和接口数组生成Class对象
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
            使用指定的调用处理程序调用其构造函数。
         */
        try {
            if (sm != null) {
                //校验新代理类的权限
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            //获取到动态生成的代理类的构造方法,参数类型必须为InvocationHandler
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            //判断构造方法的访问修饰符,如果不是Public,将其设置成可以访问的
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //根据构造方法创建出来动态生成的代理类对象
            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);
        }
    }

    private static void checkNewProxyPermission(Class<?> caller, Class<?> proxyClass) {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            if (ReflectUtil.isNonPublicProxyClass(proxyClass)) {
                //调用类加载器
                ClassLoader ccl = caller.getClassLoader();
                //代理类的类加载器
                ClassLoader pcl = proxyClass.getClassLoader();

                // do permission check if the caller is in a different runtime package
                // of the proxy class
                //获取代理类的包名
                int n = proxyClass.getName().lastIndexOf('.');
                String pkg = (n == -1) ? "" : proxyClass.getName().substring(0, n);

                //获取调用者包名
                n = caller.getName().lastIndexOf('.');
                String callerPkg = (n == -1) ? "" : caller.getName().substring(0, n);
                //类加载器不相同或包名不相同,校验权限
                if (pcl != ccl || !pkg.equals(callerPkg)) {
                    sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg));
                }
            }
        }
    }



    //用于判断指定类对象是否是一个动态代理类
    public static boolean isProxyClass(Class<?> cl) {
        return java.lang.reflect.Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
    }


    //该方法用于获取指定代理对象所关联的调用处理器
    @CallerSensitive
    public static InvocationHandler getInvocationHandler(Object proxy)
            throws IllegalArgumentException
    {
        /*
         * 验证该随心实际上是否为上一个代理实例
         */
        if (!isProxyClass(proxy.getClass())) {
            throw new IllegalArgumentException("not a proxy instance");
        }

        final java.lang.reflect.Proxy p = (java.lang.reflect.Proxy) proxy;
        final InvocationHandler ih = p.h;
        if (System.getSecurityManager() != null) {
            Class<?> ihClass = ih.getClass();
            Class<?> caller = Reflection.getCallerClass();
            if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(),
                    ihClass.getClassLoader()))
            {
                ReflectUtil.checkPackageAccess(ihClass);
            }
        }

        return ih;
    }

    private static native Class<?> defineClass0(ClassLoader loader, String name,
                                                byte[] b, int off, int len);
}

到这里,应该对JDK实现动态代理的理解又深入一点了。

猜你喜欢

转载自blog.csdn.net/Back_Light_F/article/details/82993445
今日推荐