There is a lot of unnecessary complexity in CacheImpl caused by handling two types of caches: transactional and non-transactional.
This code (and potentially InvocationContextContainer) can be simplified a lot by splitting the logic into two cache implementations: TransactionalCache and NonTransactionalCache. The common logic would be moved in an AbstractCache.