Home > database >  Spring custom Scope with timed refresh of beans
Spring custom Scope with timed refresh of beans

Time:10-26

I am working within an environment that changes credentials every several minutes. In order for beans that implement clients who depend on these credentials to work, the beans need to be refreshed. I decided that a good approach for that would be implementing a custom scope for it. After looking around a bit on the documentation I found that the main method for a scope to be implemented is the get method:

public class CyberArkScope implements Scope {

  private Map<String, Pair<LocalDateTime, Object>> scopedObjects = new ConcurrentHashMap<>();
  private Map<String, Runnable> destructionCallbacks = new ConcurrentHashMap<>();
  private Integer scopeRefresh;


  public CyberArkScope(Integer scopeRefresh) {
    this.scopeRefresh = scopeRefresh;
  }

  @Override
  public Object get(String name, ObjectFactory<?> objectFactory) {
    if (!scopedObjects.containsKey(name) || scopedObjects.get(name).getKey()
        .isBefore(LocalDateTime.now().minusMinutes(scopeRefresh))) {
      scopedObjects.put(name, Pair.of(LocalDateTime.now(), objectFactory.getObject()));
    }
    return scopedObjects.get(name).getValue();
  }

  @Override
  public Object remove(String name) {
    destructionCallbacks.remove(name);
    return scopedObjects.remove(name);
  }

  @Override
  public void registerDestructionCallback(String name, Runnable runnable) {
    destructionCallbacks.put(name, runnable);
  }

  @Override
  public Object resolveContextualObject(String name) {
    return null;
  }

  @Override
  public String getConversationId() {
    return "CyberArk";
  }
}

@Configuration
@Import(CyberArkScopeConfig.class)
public class TestConfig {
  @Bean
  @Scope(scopeName = "CyberArk")
  public String dateString(){
    return LocalDateTime.now().toString();
  }
}

@RestController
public class HelloWorld {

    @Autowired
    private String dateString;

    @RequestMapping("/")
    public String index() {
        return dateString;
    }
}

When I debug this implemetation with a simple String scope autowired in a controller I see that the get method is only called once in the startup and never again. So this means that the bean is never again refreshed. Is there something wrong in this behaviour or is that how the get method is supposed to work?

CodePudding user response:

It seems you need to also define the proxyMode which injects an AOP proxy instead of a static reference to a string. Note that the bean class cant be final. This solved it:

@Configuration
@Import(CyberArkScopeConfig.class)
public class TestConfig {
  @Bean
  @Scope(scopeName = "CyberArk", proxyMode=ScopedProxyMode.TARGET_CLASS)
  public NonFinalString dateString(){
    return new NonFinalString(LocalDateTime.now());
  }
}
  • Related