jdk动态代理原理分析

1.什么是代理模式?

  • 例子

在了解Java动态代理技术之前,先了解一下什么是代理模式,其实代理模式在生活中很常见,比如房东与中介其实就是一个代理的过程,房东有自己的房子,在代理模式中扮演角色是被代理对象,中介扮演角色是代理对象,此时有租客想租房子,由于中介已经代理了房东的房子,所以租客(客户端)可以直接通过中介(代理对象)询问自己需要的房子类型(忽略租客直接找房东),中介由于代理了房东的房子(被代理对象),当然中介可以代理多个房东的房子,以应对不同的租客(客户端).这 个过程其实就是代理模式

  • 结论

代理模式的角色:代理对象、被代理对象、公共抽象类(租客要找的房子类型在中介中要有) 代理对象可以代理一个或者多个对象(其实都是代理一个,多个对象的概念从接口维度出发,一个对象实现多个接口) 代理模式可以起到一个隔离的作用 代理模式可以统一为被代理对象做处理

  • 代理模式的几种实现方式
    1. 静态代理

静态代理实现起来相对简单,首先从从上面我们知道代理对象的几个角色,一个公共抽象接口、一个代理对象、一个被代理对象,所以只需要在代理对象里记录被代理对象的引用即可

public class StudentProxy implements Person {
    private Person person;

    public StudentProxy(Person person) {
        this.person = person;
    }

    @Override
    public void queryScore(String courseName) {
        person.queryScore(courseName);
    }
}
public class Student implements Person{
    private String userName;

    public Student(String userName) {
        this.userName = userName;
    }
    @Override
    public void queryScore(String courseName) {
        System.out.println(this.userName+"查"+courseName+"的成绩");
    }
}
public interface Person {
    void queryScore(String courseName);
}
复制代码

总结: 1.静态代理,实现简单,但如果存在多个类要被代理,则需要为每个被代理类建立一个代理类,并且每个方法都要重写,然后在方法中调用被代理对象对于的方法。2.代理对象是我们人为编写的。) 2. 动态代理

  • JDK动态代理

实现原理以及技术,首先jdk动态代理的实现是基于Java反射技术以及字节码生成技术来实现的,它是先通过反射获取到被代理类的方法然后生成一个包含了被代理类所有方法的Proxy子类来实现代理。 jdk动态代理的代理对象是动态生成的,并非手动编写 实现代码

public interface Good {
    void produce();
}

public interface Person {
    void queryScore(String courseName);
}
public class Student implements Person{
    private String userName;

    public Student(String userName) {
        this.userName = userName;
    }
    @Override
    public void queryScore(String courseName) {
        System.out.println(this.userName+"查"+courseName+"的成绩");
    }
}

public class PersonInvocation<T> implements InvocationHandler {
    private T target;
    private Object target2;
    public PersonInvocation(T target) {
        this.target = target;
    }

    public PersonInvocation(T target, Object target2) {
        this.target = target;
        this.target2 = target2;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理前置处理....");
        System.out.println(proxy.getClass().getName());
        Object result = method.invoke(target, args);
        System.out.println("代理后置处理.....");
        return result;
    }
}
public class Test {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException {
        Person stu1 = new Student("zs");
        PersonInvocation personInvocation = new PersonInvocation<>(stu1);
        //获取根据类加载器以及接口集生成的代理类
        Class<?> proxyClass = Proxy.getProxyClass(Student.class.getClassLoader(),Person.class,Good.class);
        //根据代理类和构造器参数获取类构造器
        Constructor<?> constructor = proxyClass.getConstructor(InvocationHandler.class);
        //执行被代理后的被代理对象
        Person o = (Person) constructor.newInstance(personInvocation);
        Good good = (Good) constructor.newInstance(personInvocation);
        good.produce();
        //上面代码等同与下面这一条语句
        Good proxyInstance = (Good) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{Person.class,Good.class}, personInvocation);
        byte[] proxyClassArr = ProxyGenerator.generateProxyClass(proxyInstance.getClass()
                .getSimpleName(), proxyInstance.getClass().getInterfaces());
        //将字节码文件保存到D盘,文件名为$Proxy0.class
        FileOutputStream outputStream = new FileOutputStream(new File(
                "proxyInstance.class"));
        outputStream.write(proxyClassArr);
        outputStream.flush();
        outputStream.close();
        proxyInstance.produce();
    }
}
//代理类
public final class $Proxy0 extends Proxy implements Person, Good {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;
    private static Method m4;
//省略.....
    public final void gaiveMoney() 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 produce() 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"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("learning.proxy.Person").getMethod("gaiveMoney");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m4 = Class.forName("learning.proxy.Good").getMethod("produce");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
复制代码

总结: 从代码反编译后的代理类实现可以看到,如果从接口维度出发确实可以代理多个对象,另外可以看出jdk动态代理是在运行时动态生成字节码技术以及反射技术来实现的. 源码分析

Proxy类中
@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);
    }
    //根据类加载器和接口数组获取代理类或者生成代理的方法
    return getProxyClass0(loader, intfs);
}
@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);
    }

    /*
     * Look up or generate the designated proxy class.
     */
    Class<?> cl = getProxyClass0(loader, intfs);
//前面这一部分和getProxyClass方法是一致的
//下面这部分主要是根据invocationHandler作为参数获取代理类的实例对象
    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});
    } 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 Class<?> getProxyClass0(ClassLoader loader,
                                       Class<?>... interfaces) {
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }
    //缓存获取
    return proxyClassCache.get(loader, interfaces);
    
}
//private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map= new ConcurrentHashMap<>();
//WeakCache类中获取代理对象的方法
//key 是类加载器,parameter是接口数组
public V get(K key, P parameter) {
    Objects.requireNonNull(parameter);

    expungeStaleEntries();
//根据类加载器生成缓存key
    Object cacheKey = CacheKey.valueOf(key, refQueue);

    // 从缓存map中根据key获取valeuMap,这个valuesMap也是一个Map,其中key是类加载器,而value是一个Supplier,supplier是Java中函数式接口的消费者
    //supplier其实就是Factory,Factory主要是查找到和生成对于代理类的处理类
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }

    // 根据类加载器和接口生成子key,根据子key中valuesMap中获取supplier
    // subKey from valuesMap
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;
    //自旋,如果supplier为空,则根据类加载器接口数组以及key\valuesMap生成Facotry,
    while (true) {
        //不为null的时候,从Facotory通过get方法获取value就是代理对象
        if (supplier != null) {
            // supplier might be a Factory or a CacheValue<V> instance
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        // 懒加载构建Factory
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                // successfully installed Factory
                supplier = factory;
            }
            // else retry with winning supplier
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                supplier = factory;
            } else {
                supplier = valuesMap.get(subKey);
            }
        }
    }
}
//而Facotry对象又是基于ProxyClassFactory 去生成代理类的
private static final class ProxyClassFactory
    implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
    //  代理类名前缀
    private static final String proxyClassNamePrefix = "$Proxy";

    // 生成代理类的编号$proxy0/ $proxy1
    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) {
           //根据类加载器,接口名称获取接口类
            Class<?> interfaceClass = null;
            try {
                interfaceClass = Class.forName(intf.getName(), false, loader);
            } catch (ClassNotFoundException e) {
            }
            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");
            }
         //校验是否重复接口
            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接口是否在同一个包里,不同包的非public接口不能代理
        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
            proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
        }
        long num = nextUniqueNumber.getAndIncrement();
        String proxyName = proxyPkg + proxyClassNamePrefix + num;
//生成代理类,根据代理类包名、接口数组生成代理类字节码
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
            proxyName, interfaces, accessFlags);
        try {
            //使用类加载器把生成好的代理类在运行过程中调用jvm中
            return defineClass0(loader, proxyName,
                                proxyClassFile, 0, proxyClassFile.length);
        } catch (ClassFormatError e) {
            throw new IllegalArgumentException(e.toString());
        }
    }
}
//代理类生成、写入文件中
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) {
        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;
}
复制代码

总结: 1.jdk动态代理其实就是通过Java反射把被代理类的接口方法获取到然后生成一个新的代理类,通过类加载器把生成的代理类字节码动态调入jvm中从而实现动态代理。 2.jdk动态代理只能代理基于接口的被代理对象,非接口是不支持的)

2.cglib代理(支持非接口被代理对象) 待续....

猜你喜欢

转载自juejin.im/post/7035671615157305380
今日推荐