Home > Enterprise >  Refresh a bean on schedule
Refresh a bean on schedule

Time:12-10

I have a method to create a security token. The token stays alive for 5 mins.

I then use that token to perform other actions. Since it stays alive for 5 mins, I dont want to create the token on every request. Is expensive.

Instead I wish to reuse it for 4 mins then refresh the call to create a new token.

Thus thought to do it in the following manner.

@Configuration
@EnableScheduling
public class Config {

    private final Authorization authorization; // this is a @Component

    public AuthConfig(Authorization authorization) {
        this.authorization = authorization;
    }

    @Scheduled(fixedDelayString = "${fixed.delay:PT4M}") // either use a value to pass in else default to 4 mins
    @Bean
    public String getToken() {  // can't actually do this. Method needs to be void
        return authorization.getToken();
    }
}

Then use this String in the Component where I need the token.

Like:

@Component
public class Manager {

    private final String path;
    private final String token; // coming from above bean
    private final RestOperations restOperations;

    public Manager(
            @Value("${my.path}")String path,
            String token,
            RestOperations restOperations) {
        this.path = path;
        this.token = token;
        this.restOperations = restOperations;
    }

    public Object restCall() {
        // use the token to make a rest call here.
    }
}

But it turns out I actually can't use @Scheduled to return the value.

Methods using @Scheduled needs to be void.

Is there way I could schedule this so that I could reuse the token and refresh it every 4 mins?

Doesn't need to use @Scheduled. Just looking for a way to do it.

CodePudding user response:

What you could do easily, to work around the return type restriction:

@Scheduled(fixedDelayString = "${fixed.delay:PT4M}")
public void updateToken() { 
    someTokenHolder.setToken(authorization.getToken());
}

where someTokenHolder would be an (e.g.) singleton bean. (at the costs of replacing token with someTokenHolder.token).

Without a holder object/bean, we could use spring context directly, e.g. like:

@Autowired 
GenericApplicationContext ctxt;

@Scheduled(fixedDelayString = "${fixed.delay:PT4M}")
public void updateToken() { 
    ctxt.registerBean("token", String.class, authorization.getToken());
}

GenericApplicationContext

(my) Best (un-over-slept) in your scenario:

Authorization (class/object) will be "token holder", whereas the @Scheduled job will trigger an update.

  1. Refactor Authorization#getToken to:
    • rename to updateToken().
    • return void.
    • store the token to an instance variable (token, instead).
  2. Introduce a (plain field) getter for token: getToken().
  3. In your Manager don't (constructor) wire the token, but Authorization (singleton?), and refer to authorization.getToken() (where you need token).
  4. Implement the @Scheduled as outlined:
    @Scheduled(fixedDelayString = "${fixed.delay:PT4M}")
    public void updateToken() { 
     authorization.updateToken();
    }
    
  • Related