我有一个java应用程序,我需要使用登录凭据对API进行休息调用以获取令牌。令牌有一个到期日期,距离请求时间为10小时。需要使用该令牌调用其API的所有其他调用。
我需要保存令牌,以便登录电话只在10个小时内完成一次,我该如何实现? 我试过创建一个单例类。但是,我认为多个线程可能会在到期时间内尝试刷新令牌。
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class CredentialsHolder {
private static CredentialsHolder instance = null;
private String loginToken;
private Date loginTokenExpiry;
private static final String API_BASE_URL_V1 = "https://api.com/rest";
private static final String API_LOGIN_TOKEN_PATH = "token";
private static final String API_USER_NAME = "userName";
private static final String API_PASSWORD = "password";
public static synchronized CredentialsHolder getInstance() {
if(instance == null)
instance = new CredentialsHolder();
return instance;
}
private CredentialsHolder() {
setAPICredentials();
}
private void refreshToken() {
setAPICredentials();
}
private void setAPICredentials() {
if (Calendar.getInstance().after(toCalendar(loginTokenExpiry))) {
Map headers = new HashMap();
headers.put("userName", API_USER_NAME);
headers.put("password", API_PASSWORD);
Map criteria = new HashMap();
criteria.put("headers", headers);
criteria.put("url", API_BASE_URL_V1 + API_LOGIN_TOKEN_PATH);
Map response = new ExternalAPICaller().httpGet(criteria);
Map responseHeaders = ((Map) response.get("headers"));
System.out.println(responseHeaders);
loginToken = (String) (responseHeaders.get("Token"));
try {
loginTokenExpiry = new SimpleDateFormat("MM/dd/yyyy h:mm:ss a").parse((String) (responseHeaders.get("TokenExpiry")));
} catch (ParseException e) {
e.printStackTrace();
loginTokenExpiry = null;
}
}
}
public String getAccessToken() {
if (Calendar.getInstance().after(toCalendar(loginTokenExpiry)))
refreshToken();
return loginToken;
}
public static Calendar toCalendar(Date date){
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.HOUR, -1);
return cal;
}
}
答案 0 :(得分:3)
您可以使用ScheduledExecutorService
。来自示例文档:
import static java.util.concurrent.TimeUnit.*;
class BeeperControl {
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1);
public void beepForAnHour() {
final Runnable beeper = new Runnable() {
public void run() { System.out.println("beep"); }
};
final ScheduledFuture<?> beeperHandle =
scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
scheduler.schedule(new Runnable() {
public void run() { beeperHandle.cancel(true); }
}, 60 * 60, SECONDS);
}
}
您可以创建此ExecutorService
的实例,并告诉它以某个时间间隔刷新令牌。
但也许更简单的解决方案是使用线程同步来确保当多个线程争用它时只发生一次令牌刷新。 ReentrantLock
或Semaphore
可用于确保只有一个线程刷新令牌。