标签:oca 重写 super 结构 copy other air dynamic htc
目录
本文我们思路主要分三点:
本环节的知识比较基础,如果对代理比较了解的朋友可以跳过
不管是静态代理还是动态代理目的都是为了给方法增强,静态代理主要实现方式有继承和聚合两种,在了解这两种之前我们先来了解一下代理中的几个比较重要的名词
只要代理类实现目标类,重写目标方法就可以了
/**
* 目标类
*/
public class Target {
public void targetMethod(){
System.out.println("targetMethod...");
}
}
/**
* 静态代理 继承 代理类
*/
public class ExtendsTargetProxy extends Target {
@Override
public void targetMethod() {
System.out.println("before ExtendsTargetProxy...");
super.targetMethod();
System.out.println("end ExtendsTargetProxy...");
}
}
/**
* 测试
*/
public class Client {
public static void main(String[] args) {
ExtendsTargetProxy proxy = new ExtendsTargetProxy();
proxy.targetMethod();
}
}
运行结果:
代理类和目标类要实现同一个接口
/**
* 代理接口
*/
public interface Target {
void targetMethod();
}
/**
* 目标类
*/
public class TargetImpl implements Target {
@Override
public void targetMethod() {
System.out.println("TargetImpl...");
}
}
/**
* 代理类
*/
public class TargetImplProxy implements Target {
private Target target;
public TargetImplProxy (Target target){
this.target = target;
}
@Override
public void targetMethod() {
System.out.println("before");
target.targetMethod();
System.out.println("end");
}
}
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
TargetImpl target = new TargetImpl();
Target proxy = new TargetImplProxy(target);
proxy.targetMethod();
}
}
因为现实项目中,我们同一个目标类,在不同的情况下我们需要增强不同的功能,所以不管是使用继承还是聚合都会使我们项目中产生类爆炸。
/**
* 代理接口
*/
public interface Target {
String targetMethod(String s,int i);
}
/**
* 目标类
*/
public class TargetImpl implements Target {
@Override
public String targetMethod(String a,int i) {
System.out.println("TargetImpl...");
return "OK";
}
}
/**
* 类似于 InvocationHandler
*/
public interface MyInvocationHandler {
Object invoke(Object obj,Method method,Object[] args) throws Throwable;
}
import java.lang.reflect.Method;
public class TargetInvocationHandler implements MyInvocationHandler{
private Object obj;
/**
* 接受一个代理类
* @param obj
*/
public TargetInvocationHandler(Object obj){
this.obj = obj;
}
/**
* 代理增强
* @param o 代理类
* @param method 目标方法
* @param args 目标方法参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object o,Method method, Object[] args) throws Throwable {
System.out.println("before");
Object res = method.invoke(obj,args);
System.out.println("end");
return res;
}
}
import java.lang.reflect.Method;
/**
* 代理类
*/
public class TargetImplProxy implements Target {
private Target target;
private MyInvocationHandler h;
public TargetImplProxy (Target target,MyInvocationHandler h){
this.target = target;
this.h = h;
}
@Override
public String targetMethod(String s,int i) {
try {
Method method = Class.forName(target.getClass().getName()).getMethod("targetMethod",String.class,int.class);
return (String) h.invoke(this,method,new Object[]{s,i});
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
}
/**
* 测试类
*/
public class Client {
public static void main(String[] args) throws Exception {
TargetImpl target = new TargetImpl();
Target proxy = new TargetImplProxy(target,new TargetInvocationHandler(target));
proxy.targetMethod("",1);
}
}
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
public class ProxyUtil {
private static final String tab = "\t";
private static final String line = "\n";
public static Object newProxyInstance(Object target,MyInvocationHandler myInvocationHandler) throws Exception {
//拼接class内容
// 包名
String packageName = "package com.proxy.myproxy;" + line;
// 导入的包
String importContent = "import com.proxy.learn.dynamicproxy.MyInvocationHandler;\n"
+ "import java.lang.reflect.Method;"
+ "import "+target.getClass().getInterfaces()[0].getName()+";"
+ line;
// 类开头
Class<?>[] interfaces = target.getClass().getInterfaces();
String interfaceName = interfaces[0].getSimpleName();
String classContent = "public class $Proxy implements "+interfaceName+" {" + line;
// 属性
String attributeContent = tab + "private Target target;" + line
+ tab + "private MyInvocationHandler h;" + line;
// 构造方法
String constructContent = tab + "public $Proxy ("+interfaceName+" target,MyInvocationHandler h){\n" +
" this.target = target;\n" +
" this.h = h;\n" +
"}" +line;
// 方法
String methodContent = "";
Method[] methods = target.getClass().getMethods();
// 循环所有方法
for(int i = 0 ; i < methods.length; i++){
if(Modifier.isFinal(methods[i].getModifiers())){
continue;
}
Class<?>[] parameterTypes = methods[i].getParameterTypes();
// 参数
// String p1,Integer p2
String parameterTypeNames = "";
// p1,p2
String parameterNames = "new Object[]{";
// String.class int.class
String parameterClassNames = "";
for(int j = 0 ; j < parameterTypes.length ; j++){
parameterTypeNames += parameterTypes[j].getSimpleName() + " " + "p" + j + ",";
parameterClassNames += "," + parameterTypes[j].getSimpleName() + ".class";
parameterNames += "p" + j + ",";
}
if (parameterTypes.length > 0){
parameterTypeNames = parameterTypeNames.substring(0,parameterTypeNames.lastIndexOf(","));
parameterNames = parameterNames.substring(0,parameterNames.lastIndexOf(","));
}
parameterNames += "}";
if (parameterTypes.length <= 0){
parameterNames = "null";
}
String returnType = methods[i].getReturnType().getSimpleName();
String re = "";
String re1 = "";
String re2 = "";
if(!"void".equals(returnType)){
re = "return ";
re1 = "return null; ";
re2 = "("+returnType+")";
switch (returnType){
case "int":
re1 = "return 0; ";
break;
case "boolean":
re1 = "return false; ";
break;
default:
}
}
methodContent += tab + "public "+returnType+" "+methods[i].getName()+"("+parameterTypeNames+") {\n" +
" try {\n" +
" Method method = Class.forName(target.getClass().getName()).getMethod(\""+methods[i].getName()+"\" "+parameterClassNames+");\n" +
" "+re+""+re2+"h.invoke(this,method,"+parameterNames+");\n" +
" } catch (NoSuchMethodException e) {\n" +
" e.printStackTrace();\n" +
" } catch (ClassNotFoundException e) {\n" +
" e.printStackTrace();\n" +
" } catch (Throwable throwable) {\n" +
" throwable.printStackTrace();\n" +
" }\n" +
" "+re1+"" +
" }"+line;
}
String content = packageName + importContent + classContent + attributeContent + constructContent + methodContent + "}";
// 生成.java文件
File filpath = new File("");
//这里不判断文件夹了
File file = new File(filpath.getAbsoluteFile()+"/src/com/proxy/myproxy/$Proxy.java");
if(!file.exists()){
file.createNewFile();
}
FileWriter fw = new FileWriter(file);
fw.write(content);
fw.flush();
// 生成 .class 文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
Iterable units = fileManager.getJavaFileObjects(file);
JavaCompiler.CompilationTask task = compiler.getTask(null,fileManager,null,null,null,units);
task.call();
fileManager.close();
String path = "file:"+filpath.getAbsoluteFile()+"\\src\\com\\proxy\\myproxy\\";
URL newurl=new URL(path);
URLClassLoader classLoader=new URLClassLoader(new URL[]{newurl});
Class<?> methtClass = classLoader.loadClass("com.proxy.myproxy.$Proxy");
Constructor constructor = methtClass.getConstructor(Target.class, MyInvocationHandler.class);
return constructor.newInstance(target,myInvocationHandler);
}
}
/**
* 测试类
*/
public class Client {
public static void main(String[] args) throws Exception {
TargetImpl target = new TargetImpl();
// Target proxy = new TargetImplProxy(target,new TargetInvocationHandler(target));
Target proxy = (Target) ProxyUtil.newProxyInstance(target,new TargetInvocationHandler(target));
proxy.targetMethod("",1);
}
}
这样我们就自己实现了一个简单版本的动态代理。
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 详见 3.1.1
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;
}
});
}
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);
}
}
Class<?> cl = getProxyClass0(loader, intfs);
/**
* Generate a proxy class. Must call the checkProxyAccess method
* to perform permission checks before calling this.
*/
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·创建代理类
// proxyClassCache 详见3.1.1.1
// proxyClassCache.get(loader, interfaces) 详见 3.1.1.2
return proxyClassCache.get(loader, interfaces);
}
proxyClassCache
/**
* a cache of proxy classes
*/
// 调用 WeakCache 构造方法
// new KeyFactory() 详见 3.1.1.1.1
// new ProxyClassFactory() 详见 3.1.1.2.2
// new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); 详见3.1.1.1.2
//
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
new KeyFactory()
/**
* A function that maps an array of interfaces to an optimal key where
* Class objects representing interfaces are weakly referenced.
*/
// 我们只需要知道这个是根据classloader和接口生成subKey,subKey见3.1.1.1.2 WeakCache
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 Key1(interfaces[0]); // the most frequent
case 2: return new Key2(interfaces[0], interfaces[1]);
case 0: return key0;
default: return new KeyX(interfaces);
}
}
}
new WeakCache<>(new KeyFactory(), new ProxyClassFactory())
final class WeakCache<K, P, V> {
private final ReferenceQueue<K> refQueue
= new ReferenceQueue<>();
// the key type is Object for supporting null key
//这个map 就是缓存,结构是 (key,subKey)->value 格式
// key:传进来的classloader包装对象
// subKey: 上面 new KeyFactory() 生成的
// value: 生成的代理类对象
private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
= new ConcurrentHashMap<>();
private final ConcurrentMap<Supplier<V>, Boolean> reverseMap
= new ConcurrentHashMap<>();
private final BiFunction<K, P, ?> subKeyFactory;
private final BiFunction<K, P, V> valueFactory;
/**
* Construct an instance of {@code WeakCache}
*
* @param subKeyFactory a function mapping a pair of
* {@code (key, parameter) -> sub-key}
* @param valueFactory a function mapping a pair of
* {@code (key, parameter) -> value}
* @throws NullPointerException if {@code subKeyFactory} or
* {@code valueFactory} is null.
*/
public WeakCache(BiFunction<K, P, ?> subKeyFactory,
BiFunction<K, P, V> valueFactory) {
this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
this.valueFactory = Objects.requireNonNull(valueFactory);
}
...
}
proxyClassCache.get(loader, interfaces);
/**
* Look-up the value through the cache. This always evaluates the
* {@code subKeyFactory} function and optionally evaluates
* {@code valueFactory} function if there is no entry in the cache for given
* pair of (key, subKey) or the entry has already been cleared.
*
* @param key possibly null key
* @param parameter parameter used together with key to create sub-key and
* value (should not be null)
* @return the cached value (never null)
* @throws NullPointerException if {@code parameter} passed in or
* {@code sub-key} calculated by
* {@code subKeyFactory} or {@code value}
* calculated by {@code valueFactory} is null.
*/
// K:classloader P:interface数组
public V get(K key, P parameter) {
// 判断parameter是否为空
Objects.requireNonNull(parameter);
// 清除无效的缓存
expungeStaleEntries();
// 生成 (key,subKey)
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
// 从缓存map中获取
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
// 缓存中没有
if (valuesMap == null) {
// 创建一个空value放进map
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
// 生成subKey
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
// 获取 supplier
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
// 缓存里面要是有直接返回
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
// 详见 3.1.1.2.1
V value = supplier.get();
if (value != null) {
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue)
// lazily construct a Factory
// 如果缓存里面没有 生成supplier 放进map 然后while(ture)从前面get出来
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)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
supplier.get()
@Override
public synchronized V get() { // serialize access
// re-check
Supplier<V> supplier = valuesMap.get(subKey);
if (supplier != this) {
// something changed while we were waiting:
// might be that we were replaced by a CacheValue
// or were removed because of failure ->
// return null to signal WeakCache.get() to retry
// the loop
return null;
}
// else still us (supplier == this)
// create new value
V value = null;
try {
// valueFactory.apply(key, parameter):生成代理类详见下
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) { // remove us on failure
valuesMap.remove(subKey, this);
}
}
// the only path to reach here is with non-null value
assert value != null;
// wrap value with CacheValue (WeakReference)
CacheValue<V> cacheValue = new CacheValue<>(value);
// put into reverseMap
reverseMap.put(cacheValue, Boolean.TRUE);
// try replacing us with CacheValue (this should always succeed)
if (!valuesMap.replace(subKey, this, cacheValue)) {
throw new AssertionError("Should not reach here");
}
// successfully replaced us with new CacheValue -> return the value
// wrapped by it
return value;
}
valueFactory.apply(key, parameter)
用于生成代理类
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names
// class名字的前缀
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
// 计数器,用于生成class名字 $Proxy1 $Proxy2
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) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/
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");
}
/*
* Verify that the Class object actually represents an
* interface.
*/
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
*/
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
// 包名
String proxyPkg = null; // package to define proxy class in
// public final
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
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
*/
// 核心代码 生成代理类字节码
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 加载类到JVM中
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());
}
}
}
我们最后来看看核心代码
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags);
到底为我们生成了什么
public static void main(String[] args) throws Exception {
byte[] proxyClass = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{UserMapper.class});
FileOutputStream outputStream = new FileOutputStream(new File("/Users/chengpengfei/Desktop/$Proxy0.class"));
outputStream.write(proxyClass);
outputStream.flush();
outputStream.close();
}
生成的文件放进idea看一下,是不是觉得跟我们自己写的动态代理生成的文件很像
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import proxy.UserMapper;
public final class $Proxy0 extends Proxy implements UserMapper {
private static Method m1;
private static Method m8;
private static Method m2;
private static Method m3;
private static Method m5;
private static Method m4;
private static Method m7;
private static Method m9;
private static Method m0;
private static Method m6;
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 notify() throws {
try {
super.h.invoke(this, m8, (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 logic() 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 wait(long var1) throws InterruptedException {
try {
super.h.invoke(this, m5, new Object[]{var1});
} catch (RuntimeException | InterruptedException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final void wait(long var1, int var3) throws InterruptedException {
try {
super.h.invoke(this, m4, new Object[]{var1, var3});
} catch (RuntimeException | InterruptedException | Error var5) {
throw var5;
} catch (Throwable var6) {
throw new UndeclaredThrowableException(var6);
}
}
public final Class getClass() throws {
try {
return (Class)super.h.invoke(this, m7, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void notifyAll() throws {
try {
super.h.invoke(this, m9, (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 wait() throws InterruptedException {
try {
super.h.invoke(this, m6, (Object[])null);
} catch (RuntimeException | InterruptedException | 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"));
m8 = Class.forName("proxy.UserMapper").getMethod("notify");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("proxy.UserMapper").getMethod("logic");
m5 = Class.forName("proxy.UserMapper").getMethod("wait", Long.TYPE);
m4 = Class.forName("proxy.UserMapper").getMethod("wait", Long.TYPE, Integer.TYPE);
m7 = Class.forName("proxy.UserMapper").getMethod("getClass");
m9 = Class.forName("proxy.UserMapper").getMethod("notifyAll");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m6 = Class.forName("proxy.UserMapper").getMethod("wait");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
标签:oca 重写 super 结构 copy other air dynamic htc
原文地址:https://www.cnblogs.com/bigfly277/p/11990856.html