Java中单例获取JWT Token——哪种方法更好

问题描述 投票:0回答:1

开发了一个java类,使用Singleton模式获取JWT Token。

以下是整体类模板:

import java.text.MessageFormat;
import java.time.Duration;
import java.time.Instant;

public class JWTSingleton {
    private static JWTSingleton _instance=null;
    private static String baseURLString=null;
    private static String authPartURLString = null;
    ...
    //Decalre the other static variables which are the input needed to call the authentication web service
    ...
    private JWTResponse _jwt;
    private StringBuilder sbErrMsg = new StringBuilder();
    private boolean isTimeoutException=false;
    private Instant dateTime=null;

    public static synchronized void injectDependencies(
            boolean doGetFresToken,
            String baseURLString, String authPartURLString, ...other parameters...) {
        if (doGetFresToken) {
            //Clear the saved parameters needed by the web service
            JWTSingleton.the_last_param_initilized = null;
        }
        injectDependencies(
            baseURLString, authPartURLString, ...other parameters...
        );
    }

    public static synchronized void injectDependencies(String baseURLString, String authPartURLString, ...other parameters) {
        if (JWTSingleton.the_last_param_initilized != null)
            return; //No need to initialize the static variables more than once
        JWTSingleton.baseURLString = baseURLString;
        JWTSingleton.authPartURLString = authPartURLString;
        ...
        //Other static initializations which are the input values needed for the web service like secret and username
        ...
        JWTSingleton.the_last_param_initilized = value_passed_for_the_last_parameter;
    }

    public synchronized static JWTSingleton getInstance(boolean doGetFreshToken) {
        long durMils;
        if ((_instance == null || doGetFreshToken) ||
              (_instance != null && 
                (_instance._jwt==null || _instance.sbErrMsg.length()>0)
              )
            ) {
            //Check if a fresh token is requested
            //Only create an instance if it is null
            if (_instance == null) {
                _instance = new JWTSingleton();
            }else {
                //Calculate the duration between now and the last time the token was processed
                //Only refresh the token if more that retryInterval seconds has passed
                try {
                    durMils = Duration.between(_instance.dateTime, Instant.now()).toMillis();
                } catch (Exception e) {
                    //An error occurred, just force to call the auth web service.
                    durMils = (retryInterval*2000)+1;
                }
                //If there was an error in the last run, and didn't pass more the retryInterval, then don't call the service to get a new token.
                //This is to avoid calling the auth service too quickly before giving the change for the errors to be resolved.
                //Using retryInterval is a reasonable delay needed between two attempts if there was an error in the last run.
                if (!doGetFreshToken && _instance.sbErrMsg.length()>0 && durMils < (retryInterval*1000)) {
                    return _instance; //If there was an error in the last run, and less than retryInterval has passed, then return the last instance
                }
                //Reset the saved instance
                if (_instance.sbErrMsg.length()>0) {
                    _instance.sbErrMsg.setLength(0);
                }
                _instance._jwt = null;
            }
            //Invoke the the method getToken() here to refresh the token
            _instance.getToken(baseURLString, authPartURLString, ...other parameters);
        } else {
        }
        return _instance;
    }
    
    public synchronized static JWTSingleton getInstance() {
        return getInstance(false);
    }

    private JWTSingleton() {}


    /**
     * This private method will get a fresh token every time it is invoked. It will call the authentication service to obtain a token.
     * <p>
     * TODO: Possible improvement is to implement the retry logic using Lambda Expressions and Command Pattern Implementation.
     */
    private void getToken(String baseURLString, String authPartURLString, ... other parameters) {
        Service authService = null;
        String errMsg = null;
        try {
            _jwt = null;
            authService = new Service(doDecodePasswords);
            ...
            ...
            //Init the web service needed to get the JWT Token
            ...
            ...
            int attempNo=0;
            for (int iRetyrCount = 0; iRetyrCount <= JWTSingleton.maxRetries; iRetyrCount++) {
                attempNo = iRetyrCount+1;
                if (attempNo > JWTSingleton.maxRetries) {
                    errMsg = "Obtain JWT Access Token will stop after attempts reached max retries: " + attempNo + ".";
                    errMsg = "Attempts to obtain JWT exceeded retry limit: " + attempNo + ".";
                    sbErrMsg.append(sbErrMsg.length()==0?errMsg:" - " + errMsg);
                    sbErrMsg.append(authService.getSbErrMsg().length()==0?"":" - " + authService.getSbErrMsg().toString());
                    break;
                }
                isTimeoutException = false;
                //Call the authentication web service and get the response
                _jwt = authService.callWSAuthGetJWTResponse();
                if (authService.isTimeoutException()) {
                    errMsg = "Timeout exception occurred in 'JWTSingleton()' after retry attempt: " + attempNo + ". Will NOT retry again ...";
                    isTimeoutException = true;
                    errMsg = "JWTSingleton()-Timeout error in auth service: " + authService.getSbErrMsg().toString();
                    sbErrMsg.append(sbErrMsg.length()==0?errMsg:" - " + errMsg);
                    break;
                }
                else if (_jwt == null) {
                    errMsg = "Error in 'JWTSingleton()' - JWT response is null and will stop before reaching max - retry attempt: " + attempNo + ".";
                    errMsg = "JWTSingleton(): Error; JWT response is null.";
                    sbErrMsg.append(sbErrMsg.length()==0?errMsg:" - " + errMsg);
                    sbErrMsg.append(authService.getSbErrMsg().length()==0?"":" - " + authService.getSbErrMsg().toString());
                    break;
                }
                if (_jwt != null && ATSUtils.isHttpURLConResponseOk(_jwt.getHttpResponseCode()) && _jwt.getAccess_token() != null) {
                    break; //This is what we want, the happy path
                }
                if (_jwt != null && (_jwt.getError() != null || !ATSUtils.isHttpURLConResponseOk(_jwt.getHttpResponseCode()))) {
                    errMsg = MessageFormat
                            .format(
                                    "An error occurred while obtaining JWT, will try again after attempt: {0}. JWT error = {1} - Response code ={2}.",
                                    attempNo,_jwt.getError(), _jwt.getHttpResponseCode()
                                );
                }
                try {
                    Thread.sleep(JWTSingleton.retryInterval * 1000);
                    continue;
                } catch (InterruptedException iex) {
                }
            }
        } catch (Exception e) {
            errMsg = "Unexpected error occurred in JWTSingleton(): " + e.toString();
            System.out.println(errMsg);
            e.printStackTrace();
            sbErrMsg.append(sbErrMsg.length()==0?errMsg:" - " + errMsg);
        }
        try {
            dateTime = Instant.now();
        } catch (Exception e) {
        }
    }

    public String getAccess_token() {
        return _jwt.getAccess_token();
    }
    
    public JWTResponse getJWT() {
        return _jwt;
    }

    public StringBuilder getSbErrMsg() {
        return sbErrMsg;
    }

    public boolean isTimeoutException() {
        return isTimeoutException;
    }
    
    public Instant getDateTime() {
        return dateTime;
    }

}

客户端代码将简单地获取令牌,如下所示:

JWTSingleton.injectDependencies(...parameters needed for the web service...);
String theToken = JWTSingleton.getInstance().getAccess_token()

问题:

我想遵循有关何时填充静态成员

_instance
和私有成员
_jwt
的值的最佳建议。请参阅
_instance.getToken(...)
周围的代码。

是否最好只在静态方法

_instance = new JWTSingleton()
内创建实例
getInstance()
,并在单例类外部调用Web服务,然后使用setter方法在单例实例内设置令牌?

或者最好在静态方法

getInstance()
中使用
_instance.getToken(...)
调用单例类内部的Web服务(这是当前的实现)?

java web-services jwt singleton
1个回答
0
投票

就像评论的那样,在 Web 服务器中使用具有状态(某些特定于请求的数据)的同步单例是非常值得怀疑的,它会产生不必要的瓶颈。为什么不实例化一个常规对象?或者无状态的 Stoneleigh 输入每次调用中提供的 jwt 使用,就像旧的 java bean 一样?

管理单例实例的一种更现代的方法是使用java中的ENUM构成。此技术的更详细的演练中的代码示例如下所示:

// Java program to demonstrate the example 
// of using Enum as Singleton
  
enum SingletonEnum {
    INSTANCE;
    int value;
  
    public int getValue() {
        return value;
    }
  
    public void setValue(int value) {
        this.value = value;
    }
}

class Main {
  
    public static void main(String[] args) {
        SingletonEnum singleton = SingletonEnum.INSTANCE;
  
        System.out.println(singleton.getValue());
        singleton.setValue(2);
        System.out.println(singleton.getValue());
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.