基本知识
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、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: “{}”