GeXiangDong

精通Java、SQL、Spring的拼写,擅长Linux、Windows的开关机

0%

java8中提供了类似javascript Promise方式的写法:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import java.util.concurrent.*;
import java.util.*;
import java.util.stream.*;

public class TestPromise{

public static void main(String[] argvs) throws Exception{
// 简单的lambda表达式的例子
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
list.forEach(n -> System.out.println(n));
System.out.println("-------");
list.forEach(System.out::println);
System.out.println("-------");

//下面是2个异步执行,执行完毕后使用结果的例子
String s = CompletableFuture.supplyAsync(() -> {
System.out.println("enter s1");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("s1");
return "hello";
}).thenCombine(CompletableFuture.supplyAsync(() -> {
System.out.println("enter s2");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("s2");
return "world";
}), (s1, s2) -> {return s1 + " " + s2;} ).join();
System.out.println(s);
System.out.println("-------");

// 多个方法异步执行,结果通过操纵一个共有的Map来保存,待全部执行完毕后显示结果
Map<String, String> result = new HashMap<String, String>();
CompletableFuture.allOf(
CompletableFuture.supplyAsync(() -> {
System.out.println("enter s1");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("s1");
result.put("k1", "11111");
return "11";
}),
CompletableFuture.supplyAsync(() -> {
System.out.println("enter s2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("s2");
result.put("k2", "22222");
return "22";
}),
CompletableFuture.supplyAsync(() -> {
System.out.println("enter s3");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("s3");
result.put("k3", "33333");
return "33";
})
).get();
//.get()方法会等待allOf中所有参数方法执行完毕
System.out.println(result.get("k1") + " " + result.get("k2") + " " + result.get("k3"));


System.out.println("\r\n-------------------\r\n");
// 改进一下第一个方法,使其更易读;
CompletableFuture<Map<String, Object>> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println("enter s1");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("s1");
Map<String, Object> map = new HashMap<String, Object>();
map.put("s1", "11111");
return map;
});
CompletableFuture<Map<String, Object>> cf2 = CompletableFuture.supplyAsync(() -> {
System.out.println("enter s2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("s2");
Map<String, Object> map = new HashMap<String, Object>();
map.put("s2", "22222");
return map;
});
CompletableFuture<Map<String, Object>> cf3 = CompletableFuture.supplyAsync(() -> {
System.out.println("enter s3");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
Map<String, Object> map = new HashMap<String, Object>();
map.put("s3", "33333");
return map;
});
// 注释掉的这2行和上一个例子相同,不处理cf1,cf2,cf3的返回值
// CompletableFuture<Void> cf = CompletableFuture.allOf(cf1, cf2, cf3);
// cf.get();
// 把各个CompletableFuture的执行结果放到一起

// 把结果合并成一个List
//List<Map<String, Object>> resultList = Stream.of(cf1, cf2, cf3).map(CompletableFuture::join).collect(Collectors.toList());
//resultList.forEach(n -> System.out.println("\t---" + n));

// 把结果合并到一个map里
Map<String, Object> resultMap = new HashMap<String, Object>();
Stream.of(cf1, cf2, cf3).map(CompletableFuture::join).forEach(v -> resultMap.putAll(v));
System.out.println(resultMap);
}
}

参考:

CompletableFurure 可参考javadoc https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/CompletableFuture.html

java的Lambda表达式介绍 http://blog.oneapm.com/apm-tech/226.html

http://www.baeldung.com/java-completablefuture

javax.net.ssl.SSLHandshakeException

自制ssl证书,报错:javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: Certificate signature algorithm disabled

原因是jre里信任的CA不包含自制CA,可以用keytools加入自制ca:

1
keytool -import -noprompt -trustcacerts -alias YOURALIS -file 自制CA的PEM文件 -keystore %JAVA_HOME%/jre/lib/security/cacerts -storepass changeit

changeit 是默认密码

查看所有信任的CA可以用命令:

1
keytool -list  -keystore %JAVA_HOME%/jre/lib/security/cacerts

java.security.cert.CertPathValidatorException

在高版本jdk,访问某些老网站时,可能出错:java.security.cert.CertPathValidatorException: Usage constraint TLSServer check failed: SHA1 used with certificate: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US. Usage was tls server

这是由于网站使用了SHA1的签名证书,而此版本JDK已经把SHA1证书列为禁止导致,如果要打开支持,可以编辑 %JAVA_HOME%/jre/lib/security/java.security文件,找到jdk.certpath.disabledAlgorithms=这行(后面值内容可能不同):

jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA &amp; usage TLSServer, \
RSA keySize &lt; 1024, DSA keySize &lt; 1024, EC keySize &lt; 224

把里面SHA1部分删除掉改成

jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize &lt; 1024, \
DSA keySize &lt; 1024, EC keySize &lt; 224

另外jdk.tls.disabledAlgorithms 也是类似禁止某些tls算法的。

mybatis调用存储过程和调用普通的sql略有区别:

  • 首先xml文件中要增加参数 `statementType=”CALLABLE”
  • 调用存储过程的语句用大括号包含起来,并写上call关键字

例如:

1
2
3
<select id="loginByWxOpenId" resultType="cn.devmgr.exam.domain.Token" statementType="CALLABLE">
{ call wxLogin(#{wxOpenId}, #{ipAddr}) }
</select>

传递的参数还是和普通sql一样,可以直接 #{} 来引用参数。

postgresql server提供了查询慢sql的方法,不过默认没有启动。

安装插件 pg_stat_statements

1
create extension pg_stat_statements;

安装插件就这一句sql,但pg_stat_statements还需要修改postgresql.conf,加入这句

1
shared_preload_libraries = 'pg_stat_statements'

默认的是有注释的shared_preload_libraries

更改完配置文件需要重启postgresql server

重置计数器

可以使用如下sql重置计数器

1
2
select pg_stat_reset();
select pg_stat_statements_reset();

查询慢sql

可以使用下面的sql查出来哪些sql执行的比较慢:

1
select * from pg_stat_statements order by total_time desc limit 5;

参考

https://help.aliyun.com/knowledge_detail/43562.html

Java的异常默认都有堆栈信息,详细显示出来调用层次,这对查找错误原因很有帮助。今日遇到一个无堆栈信息的java.lang.NullPointerException
经查询原来是HotSpot VM提供的一种叫fast throw的优化导致的。

Fast Throw

有些特定的隐式异常类型(NullPointerException、ArithmeticException( / 0)之类)如果在代码里某个特定位置被抛出过多次的话,HotSpot Server Compiler(C2)会透明的决定用fast throw来优化这个抛出异常的地方——直接抛出一个事先分配好的、类型匹配的异常对象。这个对象的message和stack trace都被清空。抛出这个异常的速度是非常快,不但不用额外分配内存,而且也不用爬栈;但反面就是可能正好是需要知道哪里出问题的时候看不到stack trace了。从Sun JDK5开始要避免C2做这个优化还得额外传个VM参数:-XX:-OmitStackTraceInFastThrow

既然这种异常速度比较快,那么我们自定义的一些业务异常,有些是不会使用堆栈信息的,是不是也可这样做呢?是的。可以通过继承Throwable,使用构造函数Throwable(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace)来实现。

如果不是继承的Throwable,其它异常也有类似的protected方法,例如RuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace)

禁用 Fast Throw

ubuntu 16.x 可以修改/etc/systemd/system/tomcat 配置文件

1
Environment=’CATALINA_OPTS=-Xms512M -Xmx2048M -server -XX:+UseParallelGC -XX:-OmitStackTraceInFastThrow‘

重现 Fast Throw

可以用下面的这段代码重现没有堆栈的异常:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class NpeThief {
public void callManyNPEInLoop() {
int preLen = -1;
for (int i = 0; i < 10000000; i++) {
try {
((Object)null).getClass();
} catch (Exception e) {
if(e.getStackTrace().length != preLen){
System.out.println("#" + i + " " + e.getStackTrace().length);
preLen = e.getStackTrace().length;
}
}
}
}
public static void main(String[] args) {
NpeThief thief = new NpeThief();
thief.callManyNPEInLoop();
}
}

用java NpeThief运行,会输出2、0两行
用java -XX:-OmitStackTraceInFastThrow NpeTHief运行,则只会有2一行,也能直接感觉到Fast Throw优化带来的运行速度的提升。

使用命令

1
2
crontab -e
virsh edit ubuntu

等时,会出现选择编辑器

no crontab for developer - using an empty one

Select an editor. To change later, run 'select-editor'.
1. /bin/ed
2. /bin/nano <---- easiest
3. /usr/bin/vim.basic
4. /usr/bin/vim.tiny

Choose 1-4 [2]:

这里没有vi,如果要使用vi,可以修改/etc/enviroment文件,增加一行

1
EDITOR=vi

也可以修改 /etc/profile增加一行

1
export EDITOR=vi

这样下次使用crontab -e就自动使用vi了

遇到的问题

Java Exception :
java aes 256 java.security.InvalidKeyException: Illegal key size after installation the policy

解决方法

这是由于jdk里不包含256位加密算法导致的

  1. download JCE at http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
  2. unzip and copy two jars to JAVA_HOME/jre/lib/security and override the old ones.
  3. restart tomcat

公司内部开发用的redmine, wiki等服务,计划在公司内网IP访问时可以直接访问,因为偶尔需要在家等远程访问需求,需要开放外网访问,计划在外网访问时增加一个基本认证机制,以限制外部人员获取信息。

首先使用htpasswd创建了一个用户密码文件

htpasswd -c /etc/nginx/.htpasswd developer

如果没有htpasswd命令可以通过 apt-get install apache2-utils 安装。

修改nginx的配置文件,加入以下内容

1
2
3
4
if ($remote_addr ~ "^(192.168.1.|192.168.2.)" ) {
auth_basic "Restricted Content";
auth_basic_user_file /etc/nginx/.htpasswd;
}

测试(nginx -t)会出错:

nginx: [emerg] "auth_basic" directive is not allowed here in /etc/nginx/sites-enabled/default:31

改成

1
2
3
4
5
6
set $realm "Restricted Content";
if ($remote_addr ~ "^(192.168.1.|192.168.2.)" ) {
set $realm "off";
}
auth_basic $realm;
auth_basic_user_file /etc/nginx/.htpasswd;

可解决。

如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.test.websocket;

import javax.websocket.server.ServerEndpointConfig.Configurator;

public class ChatServerEndPointConfigurator extends Configurator {

private ChatServerEndPoint chatServer = new ChatServerEndPoint();

@Override
public <T> T getEndpointInstance(Class<T> endpointClass)
throws InstantiationException {
return (T) chatServer;
}
}

第12行会有警告 Class Type safety: Unchecked cast from ChatServerEndPoint to T
修改为:

1
2
3
4
5
6
7
8
if(endpointClass.isAssignableFrom(chatServer.getClass())){
return endpointClass.cast(chatServer);
}else{
AssertionError ae = new AssertionError("Cannot cast to " + endpointClass.getName() +
" from " + chatServer.getClass().getName());
log.error("类型不匹配", ae);
throw ae;
}

可消除警告。

遇到的问题

后端服务返回HTTP状态码401时,没有Header “WWW-Authenticate”,某些版本Android客户端会出错,错误信息为no authentication challenges found。

解决办法

可修改服务器的返回,在401的返回增加 Header WWW-Authenticate, Basic realm=”fake” 来避免此问题。

android(4.x) 的DELETE方法问题

另外某些Android版本(4.x)在调用DELETE方法(RESTFul中会用到)如果HTTP BODY中有内容会出错,服务器收不到请求。