Arquivos:
spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:ehcache="http://www.springmodules.org/schema/ehcache"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springmodules.org/schema/ehcache http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd">
<aop:aspectj-autoproxy/>
<!-- Habilita o uso da annotation para gerenciamento de cache -->
<bean id="pessoaDao" class="dao.impl.PessoaDaoImpl" />
<bean id="pessoaService" class="service.impl.PessoaServiceImpl">
<property name="pessoaDao" ref="pessoaDao" />
</bean>
<!-- CacheManager Objects -->
<bean id="cacheManager" class="cache.impl.TestCacheManagerImpl" />
<bean id="autoCacheAspect" class="aspects.AutoCacheAspect">
<property name="cacheManager" ref="cacheManager" />
</bean>
</beans>
TestCacheManager
public class TestCacheManagerImpl implements ICacheManager {
private final static String APPLICATION_SCOPE = "application";
private final static String SESSION_SCOPE = "session";
private Map<String, Object> cacheApplication;
private Map<String, Object> cacheSession;
public TestCacheManagerImpl() {
this.cacheApplication = new HashMap<String, Object>();
this.cacheSession = new HashMap<String, Object>();
}
public Boolean contains(String key, String scope) throws Throwable {
if( APPLICATION_SCOPE.equals(scope) ) {
return this.cacheApplication.containsKey(key);
} else {
return this.cacheSession.containsKey(key);
}
}
public void flush(Object object, String key, String scope) throws Throwable {
if( APPLICATION_SCOPE.equals(scope) ) {
this.cacheApplication.remove(key);
this.cacheApplication.put(key, object);
} else {
this.cacheSession.remove(key);
this.cacheSession.put(key, object);
}
}
public Object get(String key, String scope) throws Throwable {
if( APPLICATION_SCOPE.equals(scope) ) {
return this.cacheApplication.get(key);
} else {
this.cacheSession.remove(key);
return this.cacheSession.get(key);
}
}
public void put(Object object, String key, String scope) throws Throwable {
if( APPLICATION_SCOPE.equals(scope) ) {
this.cacheApplication.put(key, object);
} else {
this.cacheSession.put(key, object);
}
}
public void remove(Object object, String key, String scope) throws Throwable {
if( APPLICATION_SCOPE.equals(scope) ) {
this.cacheApplication.remove(key);
} else {
this.cacheSession.remove(key);
}
}
}
PessoaServiceImpl
public class PessoaServiceImpl implements PessoaService {
private PessoaDao pessoaDao;
@AutoCache(key="123456789",scope="session")
public Pessoa get(Long id) {
return this.pessoaDao != null && id > 0 ? this.pessoaDao.get(id) : null;
}
public void update(Pessoa entity) {
if( this.pessoaDao != null && entity != null ) {
this.pessoaDao.update(entity);
}
}
public void remove(Pessoa entity) {
if( this.pessoaDao != null && entity != null ) {
this.pessoaDao.remove(entity);
}
}
public void save(Pessoa entity) {
if( this.pessoaDao != null && entity != null ) {
this.pessoaDao.save(entity);
}
}
public PessoaDao getPessoaDao() {
return pessoaDao;
}
public void setPessoaDao(PessoaDao dao) {
this.pessoaDao = dao;
}
}
AutoCacheAspect
public aspect AutoCacheAspect {
private ICacheManager cacheManager;
Object around() : @annotation( annotations.AutoCache ) {
Signature sig = thisJoinPointStaticPart.getSignature();
String key = new String();
String scope = new String();
try {
for( Annotation annotation : sig.getDeclaringType().getDeclaredAnnotations() ) {
if( annotation instanceof AutoCache ) {
key = this.getAnnotationValue(annotation, "key");
scope = this.getAnnotationValue(annotation, "scope");
break;
}
}
// Verificando se o objeto identificado pela key e scope
// existe no cacheManager
if( cacheManager.contains(key, scope) ) {
return cacheManager.get(key, scope);
} else {
Object obj = proceed();
cacheManager.put(obj, key, scope);
return obj;
}
} catch (Throwable e) {
// Caso ocorra uma exceção no processo de autocaching, o método será executado
// normalmente e o objeto não será guardado no cacheManager
return proceed();
}
}
private String getAnnotationValue(Annotation annotation, String methodname) throws Throwable {
try {
for( Method method : annotation.annotationType().getDeclaredMethods() ) {
if( method.getName().equals(methodname) ) {
return method.invoke(annotation).toString();
}
}
throw new Throwable("Não foi possivel recuperar o valor para o atributo "+methodname+" da anotação "+annotation.annotationType().getName());
} catch(Exception e) {
throw new Throwable("Erro ao tentar recuperar o valor para o atributo "+methodname+" da anotação "+annotation.annotationType().getName());
}
}
public void setCacheManager(ICacheManager cacheManager) {
this.cacheManager = cacheManager;
}
}
Test
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
PessoaService service = (PessoaService)ctx.getBean("pessoaService");
Pessoa p = new Pessoa(1L, "Marcio", "marcio@gmail.com");
service.save(p);
// Deve buscar no dao por ser a primeira execução
service.get(1L);
// Deve buscar no cache
service.get(1L);
}
}
Vale lembrar que a classe TestCacheManager é um mock.
Qual o fluxo:
Teoricamente, após o spring fazer o build dos beans, o aspecto deveria interceptar o método get da classe PessoaServiceImpl chamado no main da classe Test.
Quando eu implementei o aspecto, fiz vários testes e ele funciona perfeitamente. Só parou de funcionar a partir do momento que eu adicionei o cacheManager nele. Daqui por diante, o aspecto deveria passar a ser gerenciado pelo spring e com isso, injetar o cacheManager. Mas quando executo a aplicação, é como se o aspecto não existisse. O log mostra o aspecto sendo instanciado pelo spring, mas o mesmo não é chamado na interceptação. Como disse, no log da para ver o spring instanciando o bean do aspecto, mas o estranho é: um aspecto pode ser instanciado ?!?!?!?!?!?!?!?!?!!?
Qualquer idéia é benvinda.
[]'s