:: Spring + AspectJ - Injeção de uma interface em um aspecto

Pessoal,

Eu escrevi um aspecto que esta funcionando perfeitamente.

Agora surgiu um problema:

Tenho que injetar uma interface no aspecto para trabalhar com um bean gerenciado pelo spring.

Tentei da forma convencional, ou seja, criei um bean para o aspecto referenciando a dependencia que também é um bean configurado no applicationcontext-xml, mas o aspecto nem rodou.

Alguém poderia me dar uma idéia de como fazer isso?

[]'s

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