0

I'm building a "class cache", with classes I want to call later.

The main goal is that I don't want scan the context every time that a class instance is needed.

# Model / Repository classes

@Getter
@RequiredArgsConstructor
public class Block implements Serializable {
    private final String className;
    private final Set<String> classCandidates = new HashSet<>();
    public boolean addCandidate(final String classCandidate) {
        return this.classCandidates.add(classCandidate);
    }
}

@Slf4j
@Component
@CacheConfig(cacheNames = ConstantsCache.CACHE_BLOCK)
public class BlockRepository {

    @Cacheable(key = "#className")
    public Block findByInputClass(final String className) {
        log.info("---> Loading classes for class '{}'", className);
        val block = new Block(className);
        findCandidates(block);
        return block;
    }
}

First to evaluate the cache, I've put the cache method @Autowired in a @RestController, which works fine. The cache is populated when I call the rest method.

@RestController
public class Controller {

    @Autowired
    BlockRepository blockRepository;

    @RequestMapping("/findByInputClass")
    public Block findByInputClass(@RequestParam("className") final String className) {
        return blockRepository.findByInputClass(className);
    }
}

After doing that, I've moved the @Autowired object to a @Service, creating a method to self-populate the cache. But this does not work. The cache is not populated when the @PostConstructor method is called.

@Slf4j
@Component
public class BlockCacheService {

    @Autowired
    BlockRepository blockRepository;

    @PostConstruct
    private void postConstruct() {
        log.info("*** {} PostConstruct called.", this.getClass().getTypeName());

        val block = blockRepository.findByInputClass(ConstantsGenerics.BLOCK_PARENT_CLASS);

        final Set<String> inputClasses = getInputFromCandidates(block.getClassCandidates());
        appendClassesToCache(inputClasses);
    }

    private void appendClassesToCache(final Set<String> inputClasses) {
        for (val inputClass : inputClasses) {
            blockRepository.findByInputClass(inputClass);
        }
    }
}

How can I properly populate the cache using a service or component, that must start with the application.

Thanks in advance.

EDIT:

I've found a possible solution here: https://stackoverflow.com/a/28311225/1703546

Than I've changed the @Service code to put the cache manually instead of use the @Cacheable magic abstraction.

The class now is like this.

@Slf4j
@Component
public class BlockCacheService {

    @Autowired
    CacheManager cacheManager;

    @Autowired
    BlockRepository blockRepository;

    @PostConstruct
    private void postConstruct() {
        log.info("*** {} PostConstruct called.", this.getClass().getTypeName());

        val block = blockRepository.findByInputClass(ConstantsGenerics.BLOCK_PARENT_CLASS);

        final Set<String> inputClasses = getInputFromCandidates(block.getClassCandidates());
        appendClassesToCache(inputClasses);
    }

    private void appendClassesToCache(final Set<String> inputClasses) {
        for (val inputClass : inputClasses) {
            val block = blockRepository.findByInputClass(inputClass);
            cacheManager.getCache(ConstantsCache.CACHE_BLOCK).put(block.getClassName(), block);
        }
    }
}

Now the cache is populated correctly, but the question is, this is the best solution?

Thanks.

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
DTodt
  • 380
  • 6
  • 19

1 Answers1

0

You can't use an aspect in @PostConstruct as it may not have been created yet (and that is documented by the way).

One possible way to make that work is to implement SmartInitializingBean instead as it gives a callback when all singletons have been fully initialized (including their aspect. Changing that on your original service should work.

Having said that, this code of yours has an impact on the startup time. Why don't you let your cache to be filled lazily instead?

Stephane Nicoll
  • 31,977
  • 9
  • 97
  • 89