This is the question about should we use "real" AOP at all (by "real" I mean quantification and obliviousness, so that you can enable aspects globally and 100% transparently for the system). My opinion is to avoid that 100% transparent solutions every time you can. If you're at the development stage, it will be better to design your system in the way that don't force you to do tricks like AOP weaving at intermediate code level.
At the other hand, it will be quite disturbing to write caching concern for every component/interface you need, no matter how you'll do it. The most obvious way which came to my mind is to have a caching Decorator class for each cached class - one thing done many times.
So the path I will try to follow is to have an idea of AOP done using some IoC extension based on dynamic proxying. When fetching an object from IoC, container can check in its configuration should the cache be applied for given type and if so, create an interface-based dynamic proxy with caching. This solution is not forcing you to write a lot of similar code and is less confusing than "real" AOP by its visibility in the source code. There are some implementations like this, but you haven't specified any language, so I can't offer any.