You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在@Scheduled方法中调用API初始化并更新Bean内的AccessToken?

解决方案:定时刷新AccessToken并注入使用

核心思路

不要试图在@Scheduled方法中调用@Bean方法(这会绕过Spring容器,生成不受管理的独立实例),而是创建一个可更新状态的单例Bean来持有AccessToken,调度器注入该Bean并定时更新令牌,其他业务类通过@Autowired注入这个Bean获取最新令牌。

具体实现步骤

1. 创建AccessToken持有者Bean

这个Bean负责存储令牌,并提供线程安全的读写方法:

import org.springframework.stereotype.Component;
import java.util.concurrent.atomic.AtomicReference;

@Component
public class AccessTokenHolder {
    // 用AtomicReference保证多线程环境下的读写原子性,避免脏读
    private final AtomicReference<String> token = new AtomicReference<>();

    // 获取当前有效令牌
    public String getToken() {
        return token.get();
    }

    // 更新令牌
    public void setToken(String newToken) {
        token.set(newToken);
    }
}

2. 编写令牌刷新调度器

注入AccessTokenHolder,定时调用认证API更新令牌:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;

@Component
public class TokenRefreshScheduler {
    private final AccessTokenHolder tokenHolder;
    private final RestTemplate restTemplate;

    // 构造注入(推荐写法,避免字段注入的耦合问题)
    public TokenRefreshScheduler(AccessTokenHolder tokenHolder, RestTemplate restTemplate) {
        this.tokenHolder = tokenHolder;
        this.restTemplate = restTemplate;
    }

    // 应用启动时立即初始化令牌,避免等待第一次调度触发
    @PostConstruct
    public void initAccessToken() {
        refreshAccessToken();
    }

    // 每15分钟执行一次刷新(15分钟=900000毫秒)
    @Scheduled(fixedRate = 900000)
    public void refreshAccessToken() {
        // 替换为实际的认证API调用逻辑,这里用RestTemplate示例
        AuthResponse authResponse = restTemplate.postForObject(
                "https://your-auth-server/api/token",
                yourAuthRequestParams, // 替换为实际的请求参数
                AuthResponse.class // 替换为API返回的响应实体类
        );
        tokenHolder.setToken(authResponse.getAccessToken());
    }
}

3. 业务类中使用令牌

直接注入AccessTokenHolder,获取最新令牌调用其他API:

import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpEntity;

@Service
public class BusinessApiService {
    private final AccessTokenHolder tokenHolder;
    private final RestTemplate restTemplate;

    public BusinessApiService(AccessTokenHolder tokenHolder, RestTemplate restTemplate) {
        this.tokenHolder = tokenHolder;
        this.restTemplate = restTemplate;
    }

    public void callTargetApi() {
        String currentToken = tokenHolder.getToken();
        // 构造请求头携带令牌
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(currentToken);
        HttpEntity<Void> entity = new HttpEntity<>(headers);
        
        // 调用目标API
        // YourApiResponse response = restTemplate.exchange(
        //         "https://target-api/api/resource",
        //         HttpMethod.GET,
        //         entity,
        //         YourApiResponse.class
        // ).getBody();
    }
}

关键注意事项

  • 线程安全:使用AtomicReference而非普通字符串字段,避免多线程读写时的脏读问题。
  • 初始化令牌:通过@PostConstruct在应用启动时立即获取令牌,无需等待第一次调度触发。
  • 避免直接调用@Bean方法:Spring的@Bean方法被代理,直接调用会生成新的实例,无法共享状态;必须注入容器管理的Bean实例进行状态更新。

内容的提问来源于stack exchange,提问作者jvx23

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 01:08:29