Back-End

28 jan, 2013

Configuração e Cache do Spring 3.1

Publicidade

Eu tenho escrito recentemente sobre Spring 3.1 e suas novas anotações de cache @Cacheable e @CacheEvict. Assim como acontece com todas as características do Spring, é preciso fazer uma determinada quantidade de configuração e, como de costume, isso é feito com o arquivo de configuração XML do Spring. No caso do cache, ativar @Cacheable e @CacheEvict não poderia ser mais simples, já que tudo o que você precisa fazer é adicionar o que segue abaixo ao seu arquivo de configuração do Spring:

<cache:annotation-driven />

… juntamente com a definição do esquema apropriado em sua declaração de elemento beans XML:

<beans xmlns="http://www.springframework.org/schema/beans" 
  xmlns:p="http://www.springframework.org/schema/p"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:cache="http://www.springframework.org/schema/cache" 
  xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/cache
        http://www.springframework.org/schema/cache/spring-cache.xsd">

… com as linhas salientes sendo:

xmlns:cache="http://www.springframework.org/schema/cache"

… e:

http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd

No entanto, esse não é o fim da história, já que também é necessário especificar um gerenciador de cache e uma implementação de cache. A boa notícia é que se você estiver familiarizado com a configuração de outros componentes do Spring, como o gerenciador de transações de banco de dados, então não há surpresas na forma como isso é feito.

Uma classe de gerenciadora de cache parece ser qualquer classe que implementa a interface do Spring org.springframework.cache.CacheManager. Ela é responsável pela gestão de uma ou mais implementações de cache nas quais as instâncias de implementação de cache (s) são responsáveis por fazer o cache de seus dados de fato.

A amostra XML abaixo foi tirada do exemplo de código usado em meu dois últimos artigos.

<bean id="cacheManager">
  <property name="caches">
 <set>
   <bean

             p:name="employee"/>
   <!-- 
   TODO Add other cache instances in here
    -->
 </set>
  </property>
</bean>

Estou usando SimpleCacheManager do Spring na configuração acima para gerenciar uma instância de sua ConcurrentMapCacheFactoryBean com uma implementação de cache chamada: “employee“.

Um ponto importante a ser observado é que o seu gerenciador de cache deve ter um ID bean de cacheManager. Se você entender isso errado, então você vai ter a seguinte exceção:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.cache.interceptor.CacheInterceptor#0': Cannot resolve reference to bean 'cacheManager' while setting bean property 'cacheManager'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'cacheManager' is defined
 at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
 at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1360)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1118)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
:
:  trace details removed for clarity
:
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'cacheManager' is defined
 at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:553)
 at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1095)
 at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:277)
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
 at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:322)

Como eu disse acima, na minha simples configuração, todo o assunto é orquestrado pelo SimpleCacheManager. Isso, de acordo com a documentação, normalmente é “útil para teste ou declarações de cache simples”. Embora você possa escrever sua própria implementação CacheManager, os caras do Spring forneceram outros gerenciadores de cache para situações diferentes.

  • SimpleCacheManager – ver acima.
  • NoOpCacheManager – usado para testes em que ele não armazena nada de fato no cache, mas seja cuidadoso aqui, já que testar o seu código sem armazenar em cache poderá te confundir quando você ligar o cache.
  • CompositeCacheManager – permite o uso de múltiplos gerenciadores de cache em um único aplicativo.
  • EhCacheCacheManager – um gerenciador de cache que envolve uma instância ehCache.

Isso encerra as coisas. Abaixo segue o arquivo de configuração completo usado em meus últimos dois artigos:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
  xmlns:p="http://www.springframework.org/schema/p"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:cache="http://www.springframework.org/schema/cache" 
  xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">

  <!-- Switch on the Caching -->
   <cache:annotation-driven />

 <!-- Do the component scan path -->
 <context:component-scan base-package="caching" />

 <!-- simple cache manager -->
 <bean id="cacheManager">
   <property name="caches">
     <set>
       <bean p:name="employee"/>
       <!-- 
       TODO Add other cache instances in here
        -->
     </set>
   </property>
 </bean>

</beans>

Como o tenente Columbo costuma dizer: “E só mais uma coisa, você sabe o que me incomoda sobre este caso…”; bem, existem várias coisas que me incomodam sobre gerenciadores de cache, por exemplo:

  • O que os caras do Spring querem dizer com “útil para teste ou declarações de cache simples” ao falar sobre o SimpleCacheManager? Exatamente quando você deve usá-lo de maneira aprofundada ao invés de para testes?
  • Seria alguma vez aconselhável escrever sua implementação própria CacheManager ou até mesmo uma implementação Cache?
  • Quais são exatamente as vantagens de usar o EhCacheCacheManager?
  • Quantas vezes você realmente precisa do CompositeCacheManager?

Falarei sobre essas e outras questões no futuro…

***

Texto original disponível em http://www.captaindebug.com/2012/09/spring-31-caching-and-config.html#.UPVRHm_7KSo