UndeclaredThrowableException原因
UndeclaredThrowableException 原因
RPC 请求的时候抛出该异常,异常点是 RPC 调用的地方抛出的该异常,除此之外没有其他的异常信息。仔细排查,实际的异常应该是网络IO的TIMEOUT导致的。 那么,就有2个问题需要探讨:
- 为啥抛出的是UndeclaredThrowableException,而不是 TimeOut 的 Exception
- 如何抛出 TimeOut 异常
为啥抛出的是UndeclaredThrowableException
先说结论,之所以抛出这个异常,是因为在RPC调用的实现中,使用了 JDK 动态代理的原因。在 JDK Proxy 的调用中,如果实际运行时(InvocationHandler#invoke) 抛出了某个**受检异常(checked exception)**,但该受检异常并未在被代理对象接口定义中进行声明,那么这个异常就会被 JVM包装成 UndeclaredThrowableException 进行抛出。
这里面有个受检异常的概念,简单解释一下,Java 中所有异常,都继承自 java.lang.Throwable 类。
其实setDefault 方法就是设置了一个静态变量,而这个变量被使用的地方在:
(三个同名函数,相同的处理)这个静态变量被全局的网络请求所使用,而不是当前连接独占的配置,一般来说,当前网络使用一个http代理的时候没有问题(比如我们就是通过elb代理多个IP出口),但是当我们有多个代理的时候,在多线程环境下就会出现问题,如果代理服务器的账号密码不同,请求的服务球对cookie和ip进行校验的时候,就会比较麻烦,所以需要想办法来让每一个HttpURLConnection独占这个代理配置,直接的方法似乎没有,但是可以折中,同步网络请求过程中,HttpURLConnection是和唯一线程绑定的,我们可以用ThreadLocal,让每个线程独占一个代理配置,从而间接的保证每个HttpURLConnection始终使用一个代理配置。 可以定一个类:

其中,非静态数据成员,被放在对象的内部,而虚函数会放在对象的一个虚表中,对象在编译的时候会形成一个vptr的指针置于对象的内部,其指针指向这张虚表(考虑类的继承和多态,指向这张虚表的vptr的设置和重置会在构造函数、析构函数和拷贝函数中自动完成)。 对象在图对象表中的位置,是按照对象的申明顺序来排列的。比如a,b的申明,因为a先申明的,那么a就被先压栈,占据高地址。 而如图所见,不论虚函数是多少个,对象内部只有一个指针指向它,所以始终占一个指针大小的空间(32位机器下是4byte). 而对这个vptr在对象中的位置,不同的编译器的处理是不一样的,vc为代表的是将其放在了头部,而gcc等则是将其放在了对象的尾部,放在尾部是为了综合考虑与C的struct的兼容问题,而在头部,则是考虑继承之后的子类在调用vptr的方便性。(我个人更偏向于放在头部,因为这样在继承的时候更好理解也更方便自然),本文中的代码和模型是基于g++编译器做的实验,都是放在头部的。 还有一个问题,《深度探索c++对象模型》中,对这个1byte的类的type_info位置,他是说放在虚表的第一个位置,而其实g++中,下面这个实验,并不是放在虚表中的: