共计 18713 个字符,预计需要花费 47 分钟才能阅读完成。
代理模式
代理模式给某一个对象提供一个代理对象,并由代理对象管制对原对象的援用。
动态代理
代理类 HelloProxy
public class HelloProxy implements HelloInterface{private HelloInterface helloInterface = new Hello();
@Override
public void sayHello() {System.out.println("Before invoke sayHello");
helloInterface.sayHello();
System.out.println("After invoke sayHello");
}
}
接口 HelloInterface
public interface HelloInterface {void sayHello();
}
继承接口的办法 Hello
public class Hello implements HelloInterface{
@Override
public void sayHello() {System.out.println("Hello Zero!");
}
}
主函数
public class Main {public static void main(String[] args) {HelloProxy helloProxy = new HelloProxy();
helloProxy.sayHello();}
}
运行后果
Before invoke sayHello
Hello Zero!
After invoke sayHello
应用动态代理实现了对一个类的代理操作。然而动态代理也有毛病:因为代理只能为一个类服务,如果须要代理的类很多,那么就须要编写大量的代理类,比拟繁琐。
动静代理
利用反射机制在运行时创立代理类。
接口和继承接口的办法不变。
代理类 ProxyHandler
创立代理类,继承自 InvocationHandler,InvocationHandler 接口是 proxy 代理实例的调用处理程序实现的一个接口,每一个 proxy 代理实例都有一个关联的调用处理程序;在代理实例调用办法时,办法调用被编码分派到调用处理程序的 invoke 办法。
每一个动静代理类的调用处理程序都必须实现 InvocationHandler 接口,并且每个代理类的实例都关联到了实现该接口的动静代理类调用处理程序中,当咱们通过动静代理对象调用一个办法时候,这个办法的调用就会被转发到实现 InvocationHandler 接口类的 invoke 办法来调用。
public class ProxyHandler implements InvocationHandler {
private Object object;
public ProxyHandler(Object object) {this.object = object;}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before invoke" + method.getName());
method.invoke(object, args);
System.out.println("After invoke" + method.getName());
return null;
}
}
主函数
public class Main {public static void main(String[] args) {
// 将 JDK 动静代理生成的 class 文件保留到本地
System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
HelloInterface hello = new Hello();
InvocationHandler handler = new ProxyHandler(hello);
HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler);
proxyHello.sayHello();}
}
运行后果
Before invoke sayHello
Hello Zero!
After invoke sayHello
咱们能够看到办法失常执行了,主函数中通过 Proxy 类的静态方法 newProxyInstance 返回一个接口的代理实例,针对不同的代理类,传入相应的代理程序控制器 InvocationHandler,就能够返回相应的代理实例。
比方:新建几个办法
public class Cat implements CatInterface {
@Override
public void say() {System.out.println("I'm Cat");
}
}
public interface CatInterface {void say();
}
public class Mouse implements MouseInterface {
@Override
public void say() {System.out.println("I'm mouse");
}
}
public interface MouseInterface {void say();
}
再执行主函数
public class Main {public static void main(String[] args) {
// 将 JDK 动静代理生成的 class 文件保留到本地
System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
HelloInterface hello = new Hello();
InvocationHandler handler = new ProxyHandler(hello);
HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler);
proxyHello.sayHello();
MouseInterface mouse = new Mouse();
CatInterface cat = new Cat();
InvocationHandler handlerMouse = new ProxyHandler(mouse);
InvocationHandler handlerCat = new ProxyHandler(cat);
MouseInterface proxyMouse = (MouseInterface) Proxy.newProxyInstance(mouse.getClass().getClassLoader(), mouse.getClass().getInterfaces(), handlerMouse);
CatInterface proxyCat = (CatInterface) Proxy.newProxyInstance(cat.getClass().getClassLoader(), cat.getClass().getInterfaces(), handlerCat);
proxyMouse.say();
proxyCat.say();}
}
后果如下,所有办法失常执行
Before invoke sayHello
Hello Zero!
After invoke sayHello
Before invoke say
I'm mouse
After invoke say
Before invoke say
I'm Cat
After invoke say
动静代理的实现
- 通过实现 InvocationHandler 接口创立本人的调用处理器;
- 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创立动静代理类;
- 通过反射机制取得动静代理类的构造函数,其惟一参数类型是调用处理器接口类型;
- 通过构造函数创立动静代理类实例,结构时调用处理器对象作为参数被传入;
Proxy.newProxyInstance
package java.lang.reflect;
public class Proxy implements java.io.Serializable {
/**
* Returns an instance of a proxy class for the specified interfaces 返回指定接口的代理类的实例,该实例将办法调用分派到指定的调用处理程序。* that dispatches method invocations to the specified invocation
* handler.
*
* <p>{@code Proxy.newProxyInstance} throws
* {@code IllegalArgumentException} for the same reasons that
* {@code Proxy.getProxyClass} does.
*
* @param loader the class loader to define the proxy class @param loader 类加载器,用于定义代理类
* @param interfaces the list of interfaces for the proxy class @param interfaces 代理类要实现的接口列表
* to implement
* @param h the invocation handler to dispatch method invocations to @param h 调用处理程序,以分派办法调用以应用指定类加载器定义并实现指定接口的代理类的指定调用处理程序来返回代理实例。* @return a proxy instance with the specified invocation handler of a
* proxy class that is defined by the specified class loader
* and that implements the specified interfaces
* @throws IllegalArgumentException if any of the restrictions on the @throws IllegalArgumentException,如果对可能传递给 {@code getProxyClass} 的参数被违反
* parameters that may be passed to {@code getProxyClass}
* are violated
* @throws SecurityException if a security manager, <em>s</em>, is present 如果存在平安管理器 <em> s </ em> 并且满足以下任何条件,则 @throws SecurityException:* and any of the following conditions is met:
* <ul>
* <li> the given {@code loader} is {@code null} and 给定的 {@code loader} 为{@code null},而调用者的类加载器不是{@code null},并应用{@code RuntimePermission(“getClassLoader”)调用
* the caller's class loader is not {@code null} and the {@link SecurityManager#checkPermission s.checkPermission}“)}权限回绝拜访;* invocation of {@link SecurityManager#checkPermission
* s.checkPermission} with
* {@code RuntimePermission("getClassLoader")} permission
* denies access;</li>
* <li> for each proxy interface, {@code intf}, 对于每个代理接口 {@code intf},调用者的类加载器与{@code intf} 和调用{@link SecurityManager#checkPackageAccess
* the caller's class loader is not the same as or an s.checkPackageAccess()的类加载器都不雷同或不雷同}回绝拜访{@code intf};* ancestor of the class loader for {@code intf} and
* invocation of {@link SecurityManager#checkPackageAccess
* s.checkPackageAccess()} denies access to {@code intf};</li>
* <li> any of the given proxy interfaces is non-public and the 任何给定的代理接口都是非公共的,并且调用方类与非公共接口不在同一个 {@linkplain 软件包运行时软件包} 中,并且应用以下命令调用{@link
* caller class is not in the same {@linkplain Package runtime package} SecurityManager#checkPermission s.checkPermission} {@code ReflectPermission(“newProxyInPackage。{package name}”)}权
* as the non-public interface and the invocation of 限回绝拜访。* {@link SecurityManager#checkPermission s.checkPermission} with
* {@code ReflectPermission("newProxyInPackage.{package name}")}
* permission denies access.</li>
* </ul>
* @throws NullPointerException if the {@code interfaces} array
* argument or any of its elements are {@code null}, or
* if the invocation handler, {@code h}, is
* {@code null}
*/
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
// 判断 InvocationHandler 是否为空,若为空,抛出空指针异样
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;
// 如果 Class 作用域为公有,通过反射 setAccessible 反对拜访
if (!Modifier.isPublic(cl.getModifiers())) {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {cons.setAccessible(true);
return null;
}
});
}
// 获取 Proxy Class 构造函数,创立 Proxy 代理实例。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.getProxyClass0
利用 getProxyClass0(loader, intfs)生成代理类 Proxy 的 Class 对象
package java.lang.reflect;
public class Proxy implements java.io.Serializable {
/**
* a cache of proxy classes 在此初始化 WeakCache
*/
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
/**
* Generate a proxy class. Must call the checkProxyAccess method 生成代理类。在调用此办法之前,必须调用 checkProxyAccess 办法执行权限查看。* to perform permission checks before calling this.
*/
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {if (interfaces.length > 65535) {
// 如果接口数量大于 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 创立代理类。return proxyClassCache.get(loader, interfaces);
}
WeakCache.get(K key, P parameter)
其中缓存应用 WeakCache 实现,应用 ProxyClassFactory 创立代理,ProxyClassFactory 是 Proxy 类的动态外部类,实现了 BiFunction 接口中的 apply 办法,当 WeakCache 中没有缓存相应接口的代理类,则会调用 ProxyClassFactory 类的 apply 办法来创立代理类。
package java.lang.reflect;
final class WeakCache<K, P, V> {
/**
* Look-up the value through the cache. This always evaluates the 通过缓存查找值。如果缓存中没有给定的条目或者实体曾经被革除,这总是评估 {@code subKeyFactory} 函数,并有选择地评估 {@code valueFactory} 函数
* {@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 键可能为空键
* @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.
*/
public V get(K key, P parameter) {Objects.requireNonNull(parameter);
expungeStaleEntries();
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
// 懒加载 为特定的 cacheKey 设置第二级 valuesMap
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
// 如果 valuesMap 为 null, 就新建一个,如果不为 null,就取 oldValue
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 并从 valuesMap 中检索该 subKey 存储的可能的 Supplier<V>
// subKey from valuesMap
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
// 获取 supplier
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
// 自旋,期待 supplier 不为空
while (true) {if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
// 如果缓存中没有,就调用 ProxyClassFactory 办法创立 此时 supplier 是 WeakCache$Factory,调用 WeakCache 中 Factory 的 get 办法
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 工厂懒加载,在此初始化并结构 factory 为 WeakCache$Factory
if (factory == null) {factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
// 从 valuesMap 中加载
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
// 从 valuesMap 中还是得不到,就应用 factory 赋值 supplier,赋值后 supplier 不为 null,while 自旋将失效
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);
}
}
}
}
WeakCache.Factory
package java.lang.reflect;
final class WeakCache<K, P, V> {
/**
* A factory {@link Supplier} that implements the lazy synchronized 工厂 {@link Supplier} 实现了值的惰性同步结构并将其装置到缓存中。* construction of the value and installment of it into the cache.
*/
private final class Factory implements Supplier<V> {
private final K key;
private final P parameter;
private final Object subKey;
private final ConcurrentMap<Object, Supplier<V>> valuesMap;
Factory(K key, P parameter, Object subKey,
ConcurrentMap<Object, Supplier<V>> valuesMap) {
this.key = key;
this.parameter = parameter;
this.subKey = subKey;
this.valuesMap = valuesMap;
}
@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 {
// 调用 Proxy 类中动态外部类 ProxyClassFactory 的 apply 创立代理类 valueFactory 此时是 Proxy.ProxyClassFactory
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);
// try replacing us with CacheValue (this should always succeed)
if (valuesMap.replace(subKey, this, cacheValue)) {
// put also in reverseMap
reverseMap.put(cacheValue, Boolean.TRUE);
} else {throw new AssertionError("Should not reach here");
}
// successfully replaced us with new CacheValue -> return the value
// wrapped by it
return value;
}
}
Proxy.ProxyClassFactory
package java.lang.reflect;
public class Proxy implements java.io.Serializable {
/**
* A factory function that generates, defines and returns the proxy class given
* the ClassLoader and array of interfaces.
*/
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) {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.
* 校验该类是否是接口类型 JAVA 是单继承的,代理类曾经继承了 Proxy 类了,不能再继承其余的类
*/
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 代理类包名
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
// public 代理接口,应用 com.sun.proxy 包名
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 这里的 ClassFormatError 示意(排除代理类生成代码中的谬误)提供给代理类创立的参数还有其余一些有效方面(例如,超出了虚拟机限度)* 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());
}
}
}
// 用户和本地 C 代码进行互操作的 API, 称为 Java Native Interface (Java 本地接口)
private static native Class<?> defineClass0(ClassLoader loader, String name,
byte[] b, int off, int len);
ProxyGenerator.generateProxyClass
咱们能够看到在 ProxyClassFactory 类的 apply 办法中可看出真正生成代理类字节码的中央是 ProxyGenerator 类中的 generateProxyClass
package sun.misc;
public class ProxyGenerator
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;
}
代理类
在 Main 函数中减少,将 JDK 动静代理生成的 class 文件保留到本地,保留门路 com.sun.proxy
System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
关上生成的代理类
- 继承了 Proxy 类,实现了代理的接口,因为 java 不能多继承,这里曾经继承了 Proxy 类了,不能再继承其余的类,所以 JDK 的动静代理不反对对实现类的代理,只反对接口的代理。
- 提供了一个应用 InvocationHandler 作为参数的构造方法。
- 生成动态代码块来初始化接口中办法的 Method 对象,以及 Object 类的 equals、hashCode、toString 办法。
- 重写了 Object 类的 equals、hashCode、toString,它们都只是简略的调用了 InvocationHandler 的 invoke 办法,即能够对其进行非凡的操作,也就是说 JDK 的动静代理还能够代理上述三个办法。
- 代理类实现代理接口的 sayHello 办法中,只是简略的调用了 InvocationHandler 的 invoke 办法,咱们能够在 invoke 办法中进行一些非凡操作,甚至不调用实现的办法,间接返回。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import com.example.offer.designmode.proxy.dynamicproxy.CatInterface;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy2 extends Proxy implements CatInterface {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy2(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 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 say() throws {
try {super.h.invoke(this, m3, (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);
}
}
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("com.example.offer.designmode.proxy.dynamicproxy.CatInterface").getMethod("say");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());
}
}
}