0%

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 类。

阅读全文 »

去年在做内容库的时候,涉及到了多系统多数据源互相查询的情景,当时就想要将内容库的所有数据,增加统一的数据接入层,通过graphql的方式提供给上层业务使用,后面受限于人力没有实施。目前从头开始做站群相关的业务,顺带着浅尝了一下graphql,感觉还不错。

GraphQL 是什么

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

背景

参看: https://www.youtube.com/watch?v=Ah6GSCK5Rfs

graphql 和 rest api 是同一层的东西,都是一种基于 http 之上的数据接口协议,两者设计理念完全不同。目前来说 graphql 在很多大小厂也都开始使用,确实会方便很多。 但是 rest api 还是最广泛应用的协议,比如 AMP (T T)。 事实上任何东西都有2面性,对于graphql 来说,优缺点都有

阅读全文 »

工程中的网络请求,有时会需要使用http代理,比较简单的方法是使用apache的httpclient 直接设置代理,但有的时候使用java自带的HttpURLConnection的时候,就需要注意多线程的问题了。 使用HttpURLConnection 实现代理的方法也很简单,在建立连接之前先设置代理:

Authenticator.setDefault(authenticator);

需要注意的是,设置代理的方法并不是使用HttpURLConnection的一个方法,而在建立请求的时候,也没有任何调用和使用 Authenticator的地方,可以猜测这里设置了代理是使用了全局量,跟进Authenticator中去,会发现: 1 2 其实setDefault 方法就是设置了一个静态变量,而这个变量被使用的地方在: 3 (三个同名函数,相同的处理)这个静态变量被全局的网络请求所使用,而不是当前连接独占的配置,一般来说,当前网络使用一个http代理的时候没有问题(比如我们就是通过elb代理多个IP出口),但是当我们有多个代理的时候,在多线程环境下就会出现问题,如果代理服务器的账号密码不同,请求的服务球对cookie和ip进行校验的时候,就会比较麻烦,所以需要想办法来让每一个HttpURLConnection独占这个代理配置,直接的方法似乎没有,但是可以折中,同步网络请求过程中,HttpURLConnection是和唯一线程绑定的,我们可以用ThreadLocal,让每个线程独占一个代理配置,从而间接的保证每个HttpURLConnection始终使用一个代理配置。 可以定一个类:

阅读全文 »

前段时间,因为一年前篡改了一个sdk的包,导致了一系列不可预知的损失,这也充分说明了技术的正确性,需要决策的正确性来支撑的。作为技术人员,不仅仅要考虑技术的可行性,也要考虑实施后的风险和结果的预期假设。 从工程角度,简单记录一下篡改sdk包的技术。

  1. 解压jar或者apk的包
  2. JD-GUI 反编译查看class的相关代码,找到修改点
  3. 自己编写相应的方法或者类,使用 javaassist 注入到class文件
  4. 重新打包

javassist 使用方法参考: https://jboss-javassist.github.io/javassist/tutorial/tutorial.html 附上测试代码,修改一个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static void main(String[] args) {
try {
javassist.tools.reflect.Loader cl = new javassist.tools.reflect.Loader();
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath("/tmp/aa/");
CtClass cc = pool.get("com.facebook.ads.internal.d.g");
CtMethod ctmethod = cc.getDeclaredMethod("c");
cc.getDeclaredField("c");
// getCode()即为需要替换的的代码
ctmethod.setBody(getCode());
cc.writeFile("/tmp/aa/");
} catch (CannotCompileException e) {
e.printStackTrace();
} catch (NotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

最近的论文用到了RSA相关的东西,做一个整理。

流程图

  • 密钥生成过程: RSA
  • 加密解密过程: RSA

选取2个质数p、q

\(RSA\)算法的主要就是基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难。 同时为了增强强度,\(p-1\)和\(q-1\)的最大公因子要小 质数的选取方法:

  • 随机搜索法随机产生一个奇数 \(p_1\) 进行素数测试,若是素数,则结束;否则,重新随机产生一个奇数 \(p_2\) 进行素性测试,直至找到一个素数 \(p_t\)。
  • 随机递增搜索法随机产生一个奇数,对以该数为起点的奇数依次进行测试,直至找到一个素数。这种方法相对于随机搜索法,在速度上有一定的提高,但是并没有本质上的区别
阅读全文 »

最近在看《深度探索c++对象模型》对于对象模型有了一点了解,做一个总结。以下的一些结论的实验见:https://github.com/xtestw/CPPObjModelTest

单个对象模型

对于一个单个对象而言,对象的内部结构是类似于一张表结构,依次存储着c++的对象内部数据,我们都知道,一个c++的类内部一般会包含下面的几个部分:

  • 非静态成员变量
  • 非静态成员函数
  • 静态成员变量
  • 静态成员函数
  • 虚函数
  • 友元函数
  • 构造函数、析构函数、拷贝构造函数

对于一个简单的对象,将设我们定义类如下:

1
2
3
4
5
6
7
8
9
10
class base{
public:
base();
virtual ~base();
int a,b;
void f();
static int c,d;
static void f2();
virtual void f3();
};

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

阅读全文 »

转自:http://www.ibm.com/developerworks/cn/linux/l-cn-nohup/ 我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务, 结果却由于网络的不稳定导致任务中途失败。如何让命令提交后不受本地关闭终端窗口/网络断开连接的干扰呢?下面举了一些例子, 您可以针对不同的场景选择不同的方式来处理这个问题。

nohup/setsid/&

场景:

如果只是临时有一个命令需要长时间运行,什么方法能最简便的保证它在后台稳定运行呢?

hangup 名称的来由

在 Unix 的早期版本中,每个终端都会通过 modem 和系统通讯。当用户 logout 时,modem 就会挂断(hang up)电话。 同理,当 modem 断开连接时,就会给终端发送 hangup 信号来通知其关闭所有子进程。

阅读全文 »

http://xtestw.site/?p=29

##x&(-x)取x的最后一个1的证明##
明天要给新队员讲树状数组,避不开的一个证明,之前教主讲过,当时没听明白给忘了- -,只有自己想了一种证明方法。

#####证明#####
大家都知道,计算机是用补码来存储一个数的,在这种编码情况下,整数是自然状态编码,假设我们是一个5位的机器(只是假设),那么1,编码就为00001, 而-1的编码则是11111(并不是10001),在这种情况下,我们会有下面的结论:

             -x=11111 – x +1 (x 假设为正数二进制)  -----------------结论一
              x=00000 + x (x 假设为正数二进制) ----------------------结论二

我们还会有以下2个结论:

结论三:11111 - x 不会出现借位的情况(二进制下 ,对应位只会是两种情况 1-0 和 1-1)
结论四:00000 + x 不会出现进位的情况(二进制下,对应位只会是 0+1,0+0)

假设 x的二进制编码为 x1 x2 x3 x4 x5

那么我们就会发现 对于任何一位(以x1为例) 0+x1 和 1-x1 两个 必然是一个为1 一个为0,因为:

X1的值 0+x1 1-x1
0 0 1
1 1 0
阅读全文 »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class base{
public:
int i,j;
base(){
i=j=0;
}

base(int a,int b){
i=a;j=b;
}
};

class derived:public base{
public:
derived(int a,int b){
base(a,b);
}
};

int main(){
  derived d(3,1);
  cout<<d.i<<" "<<d.j<<endl;
  return 0;
}

上面的这段代码会输出什么呢?!正确的答案是输出了”0 0”. 我的理解是,虽然其中调用了base(a,b) 但是其实操作的a和b不是当前d的a,b,其实是定义了一个新的base的对象。正确的写法应该是下面这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class base{
public:
int i,j;
base(){
i=j=0;
}
base(int a,int b){
i=a;j=b;
}
};



class dervied:public base{

public:
derived(int a,int b):base(a,b){
}
};

int main(){
  derived d(3,1);
  cout<<d.i<<" "<<d.j<<endl;
  return 0;
}

关于c++构造函数两个误解

  1. 任何class只要没有定义构造函数,就会被编译器自动合成一个。 有些构造函数在实际中有和没有是没有任何用处的,所以无用的构造函数是不会被构建出来

  2. 编译器合成的构造函数,会为每个成员变量设定初始值 在我看来,编译器合成的构造函数,是为了调用成员类或者父类的构造函数,而这个成员类的构造函数的调用顺序则是按照申明的顺序来调用。

×