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