基于注解的Spring缓存

4

我的Spring应用由两个上下文XML配置文件组成,第一个是root-context.xml,只扫描非@Controller注释的bean:

<beans ...>
  <context:component-scan base-package="com.myapp.test">
    <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
  </context:component-scan>
</beans>

第二个servlet-context.xml文件包含所有Spring-MVC设置和扫描@Controller注释的bean。

<beans:beans xmlns="http://www.springframework.org/schema/mvc" ...>
  <annotation-driven />
  <context:component-scan base-package="com.myapp.test">
    <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
  </context:component-scan>
  ...
</beans:beans>

web.xml中DispatcherServlet的配置如下:

<web-app ...>
  ...
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/root-context.xml</param-value>
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  ...

</web-app>

我想尝试基于注解的缓存,因此我将以下bean定义添加到root-context.xml

<cache:annotation-driven/>

<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
  <property name="caches">
    <set>
      <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="foo"/>
    </set>
  </property>
</bean>

请测试一下一个使用了@Service注解的类,该类应该被root-context.xml扫描。

@Service
public FooService {
  @Cacheable("foo")
  public int getFoo() {
    System.out.println("cache miss");
    return new Random().nextInt(50);
  }
}

但是getFoo()方法调用从未被缓存,每次都会得到随机数。

然而,如果我在servlet-context.xml文件中扫描所有的bean并将缓存bean定义重新定位到那里,它就可以工作。

这是什么原因呢?显然,我还不理解缓存注解的某些内容。


我们可以看到调用 getFoo() 的代码吗? - user180100
1个回答

5
在您的servlet-controller.xml文件中,当进行context:component-scan时,您没有排除@Component bean。
<context:component-scan base-package="com.myapp.test">
    <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
  </context:component-scan>

you should add use-default-filters="false"

 <context:component-scan base-package="com.myapp.test" use-default-filters="false">
        <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
  </context:component-scan>

为了避免Bean影子化问题。

谢谢,我确认这确实是问题所在。由于默认的过滤器设置,bean被servlet-context.xml扫描到了。 - gerrytan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接