引言

对接微信公众平台获取access_token接口时,access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
所以需要有个token池服务,假设单机运行。
CAS操作主要借鉴JDK的JUC源码,使用了Unsafe类,
源码:

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
@Component
public class TokenPool {
/**
* The constant LOGGER.
*/
private static final Logger LOGGER = LoggerFactory.getLogger("TokenPool");
/**
* The Token.
*/
private String token;

/**
* 凭证有效时间,单位:秒
*/
private long expiresTime;

/**
* The State.
* 0:token有效,默认为0;
* 1:正在请求腾讯,此时token无效,需线程空转等待。
*/
private AtomicInteger state = new AtomicInteger(0);

/**
* The Mp api.
*/
@Autowired
private MpApi mpApi;

/**
* Get token.
*
* @return the string
*/
public String get() {
//如果当前时间大于token过期时间,则请求腾讯,获取最新token
if (System.currentTimeMillis() >= expiresTime) {
return getToken();
} else {
return token;
}

}

/**
* 请求腾讯获取token
*
* @return the token
*/
private String getToken() {
//只有一个线程会进入此if代码块
if (state.compareAndSet(0, 1)) {
//HTTP请求获取token
token = mpApi.getToken();
//公众号token有效期
expiresTime = System.currentTimeMillis() + NumberConstant.NUMBER_7200;
//恢复state==0
state.set(0);
}
//空转,可以睡眠1秒
while (state.get() == 1) {
try {
Thread.sleep(NumberConstant.NUMBER_1000);
} catch (InterruptedException e) {
LOGGER.warn("tokenPool get token sleep interrupted");
}
}
//有个线程修改了state为0,现在的token是有效的了
return token;

}

}

优化方案,用一个线程专门检测当前时间是否达到token预期失效时间,将要达到是,请求微信公众平台获取token,之后更新原有Token。