Announcement Announcement Module
No announcement yet.
Cache Abstraction with MVC Controller Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • Cache Abstraction with MVC Controller

    I'm trying to understand the functionality of cache abstraction when it is invoked via a @RequestMapping registered in a (MVC) @Controller class.

    I setup a simple proof of concept where I had STS generate an MVC project. I configured the cache abstraction in the root context and tied it to Redis as the cache manager. I then created an arbitrary method on a class annotated as a @Service and declared that method to be @Cacheable. I wrote a simple junit test that would load the root context and trigger the method several times. Based on a print statement I could tell that the first time in, it would run the method, after that it would hit the cache. As expected.

    I then had my @Controller call to the same method that was autowired in the controller, but no matter what it would never cache or read from cache, it would always enter the method. Not expected. In order to make it work I had to add the following statement to my servlet context:

    HTML Code:
    <cache:annotation-driven />
    With that in the servlet context (as well as the root context) the interactions started by the controller would then allow the caching in the service to function properly, as well as those triggered by the junit tests.

    My question is why would I have to do this? I thought that the web context inherited everything from the root context with the ability to override. I'm assuming it has something to do with spring created proxies, but not really sure.

    Also, is this the recommended way of doing this? I want caching to be functional on the mid-tier of my applications, and usable by both a testing framework as well as my MVC layer without having to declare annotation-driven multiple times all over the code. I suppose I could always create a test context that imports the root context for testing, but I wanted to get some insight from the community.


  • #2
    You are, probably, using component-scanning and scanning for everything in both the contextloaderlistener and dispatcherservlet, basically resulting in 2 instances of the same bean. Aspects (Bean(Factory)PostProcessors) operate only on beans in the same context as they are defined in so your cache:annotation-driven in the ContextLoaderListener context has no effect on beans detected/loaded in the DispatcherServlet and as both contain an instance of your @Service the one closest to the caller (the controller) is being used. So basically you have rendered your ContextLoaderListener useless.

    In short don't your CLL should scan for everything but web related things (@Controllers) and your DispatcherServlet should only scan for @Controllers and nothing else.

    Use the forum search as the question has been answered before (in general in regard to @Transactional).


    • #3
      Thanks Marten, that solved my problem. I searched the forum and found a post you had probably referred to, Why tx:annotation-driven doesn't work in my service configuration file . That deffintely clears some things up. I hadn't realized that the annotation driven tags for both caching and transactions were operating against the beans in their same context.

      I had the root context component-scan declaration exclude the @Controller annotations, and the servlet context component-scan exclude all but the @Controller. I was then able to remove the cache:annotation-driven declaration from the servlet context, leaving it in the root context, and caching worked just fine hitting the service from the controller. That level of isolation is definitely helpful but obviously necessary.