动态代理JDK和CGLib剖析


基本知识

提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、JDK动态代理

代码例子

public class JDKProxyDemo {
    public static void main(String[] args) {
       System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        JDKProxyHandler<ProxyService> jdkProxyHandler = new JDKProxyHandler(new ProxyServiceImpl());
        ProxyService proxy = jdkProxyHandler.createProxy();
        // 调用a函数
        String res = proxy.a();
        System.out.println("proxyService.a() return " + res);
    }
}

/**
 * 接口定义
 */
interface ProxyService {
    String a();
    void b();
}

/**
 * 接口实现类定义
 */
class ProxyServiceImpl implements ProxyService {

    @Override
    public String a() {
        System.out.println("this is a, and will call b(), then return 'a'");
        b();
        return "a";
    }

    @Override
    public void b() {
        System.out.println("this is b");
    }
}

class JDKProxyHandler<T> implements InvocationHandler {
    private T target;

    public JDKProxyHandler(T target) {
        this.target = target;
    }

    public T createProxy() {
        return (T)Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("----jdk.proxy.before----");
        Object res = method.invoke(target, args);
        System.out.println("----jdk.proxy.after, return = " + res + "----");
        return res;
    }
}

运行后:

----jdk.proxy.before----
this is a, and will call b(), then return 'a'
this is b                                                    
----jdk.proxy.after, return = a----
proxyService.a() return a

内部a调用b方法时,b方法不会走代理;
同时因为加了下面,项目会生成代理类:

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

在这里插入图片描述

public final String a() throws  {
        try {
        // h即JDKProxyHandler对象,会直接调用其invoke方法
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

源码分析-newProxyInstance

// 代理类的构造函数的参数列表,其实就只有一个
private static final Class<?>[] constructorParams =
        { InvocationHandler.class };
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
    // h不能为空
        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);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        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;
                    }
                });
            }
            /** 构造函数的参数只有一个h,在前面生成的代理类,可以看出只有一个参数
             public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    } 
**/
           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);
        }
    }
// Proxy.java
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
// WeakCache.java
// 由上面所知valueFactory是Proxy.ProxyClassFactory类
public WeakCache(BiFunction<K, P, ?> subKeyFactory,
                     BiFunction<K, P, V> valueFactory) {
        this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
        this.valueFactory = Objects.requireNonNull(valueFactory);
    }

通过Proxy.ProxyClassFactory产生代理类

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) {

            ......
            // 代理类的名称,形如$Proxy0
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            // 生成代理类
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                // 加载类
                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.generateProxyClass怎么产生字节码

    private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
    public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        // 这里产生字节码
        final byte[] var4 = var3.generateClassFile();
        // sun.misc.ProxyGenerator.saveGeneratedFiles设置为true,会保存到文件
        if (saveGeneratedFiles) {
                ......
                        Files.write(var2, var4, new OpenOption[0]);
                 ......
        }

        return var4;
    }

可以看到:ProxyGenerator.generateClassFile()产生了字节码文件

自实现JDK动态代理

import org.junit.Test;
import sun.misc.ProxyGenerator;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Paths;

public class ProxyGeneratorTest {
    private static String CLASS_NAME = "org.example.proxy.UserServiceProxy";
    private static String DIR_PREX = ProxyService.class.getClassLoader().getResource("")
            .getPath()
            .replace("test-classes", "classes")
            .substring(1);
    private static String FILENAME = DIR_PREX + "org\\example\\proxy\\UserServiceProxy.class";
    private static String FILE_DIR = DIR_PREX + "org\\example\\proxy";
    // 产生文件
    @Test
    public void testGeneratorClass() throws IOException {
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                CLASS_NAME, new ProxyServiceImpl().getClass().getInterfaces(), Modifier.FINAL);
        Files.createDirectories(Paths.get(FILE_DIR));
        Files.write(Paths.get(FILENAME), proxyClassFile, new OpenOption[0]);
    }

    // 加载上面的类文件
    @Test
    public void testLoadMyProxyClass() throws Exception {
        ProxyService target = new ProxyServiceImpl();
        JDKProxyHandler handler = new JDKProxyHandler(target);

        URLClassLoader loader = new URLClassLoader(new URL[] { new URL("file:" + DIR_PREX) });
        Class<ProxyService> proxyClass = (Class<ProxyService>) loader.loadClass(CLASS_NAME);
        ProxyService proxyService = proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);

        proxyService.a();
    }

    @Test
    public void testClassBytes() throws Exception {
        // 生成代理类的二进制字节码
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                CLASS_NAME, new ProxyServiceImpl().getClass().getInterfaces(), Modifier.FINAL);


        ProxyService target = new ProxyServiceImpl();
        JDKProxyHandler handler = new JDKProxyHandler(target);

        // 类加载
        ByteClassLoader loader = new ByteClassLoader(proxyClassFile);
        Class<ProxyService> proxyClass = (Class<ProxyService>) loader.loadClass(CLASS_NAME);
        
        // 实例化
        ProxyService proxyService = proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);
        
        // 对象函数调用
        proxyService.a();
    }

    public static class ByteClassLoader extends ClassLoader {
        private byte[] cLassBytes;
        public ByteClassLoader(byte[] cLassBytes) {
            this.cLassBytes = cLassBytes;
        }

        @Override
        protected Class<?> findClass(String name) {
            Class clazz = defineClass(name, cLassBytes, 0, cLassBytes.length);
            return clazz;
        }
    }
}

知识点

  • 1.ProxyGenerator里若"sun.misc.ProxyGenerator.saveGeneratedFiles"为true,则保存到文件;
  • 2.ProxyGenerator的generateClassFile()函数负责产生字节码;-----ProxyGenerator.generateProxyClass(…)

二、使用步骤

1.引入库

代码如下(示例):

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import  ssl
ssl._create_default_https_context = ssl._create_unverified_context

2.读入数据

代码如下(示例):

data = pd.read_csv(
    'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())

该处使用的url网络请求的数据。


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
动态代理JDK和CGLib}

param:
map: “{}”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值