Pessoal,
Criei um aspecto:
public aspect AutoCache {
pointcut publicMethods():execution(public * cc.marcio.cache.service..*(..));
pointcut autoCache(): publicMethods();
before() : autoCache() {
System.out.println("Before");
}
after() : autoCache() {
System.out.println("After");
}
Isso significa que todos os métodos executados dentro do diretório cc.marcio.cache.service.* serão interceptados.
Gostaria de melhorar este aspect usando annotation, onde ao invés de executar a cada método do pacote, só executaria no método que fosse anotado.
Alguém sabe se isso é possivel ou poderia me dar uma idéia de como fazer isso?
De qualquer forma, estou pesquisando, e caso encontre a solução, eu posto aqui.
[]'s
Resolvi o problema fazendo o seguinte:
Criei a anotação:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target( {ElementType.METHOD})
public @interface AutoCache { }
Meu aspecto ficou da seguinte forma:
public aspect AutoCacheAspect {
pointcut publicMethods():execution(public * *.*(..));
pointcut autoCache(): publicMethods();
before() : autoCache() {
if( this.isAssigned(thisJoinPointStaticPart.getSignature()) ) {
System.out.println("Before");
}
}
after() : autoCache() {
if( this.isAssigned(thisJoinPointStaticPart.getSignature()) ) {
System.out.println("After");
}
}
private Boolean isAssigned(Signature sig) {
Method method = ((MethodSignature)sig).getMethod();
Annotation [] annotations = method.getDeclaredAnnotations();
for( Annotation an : annotations ) {
if( an instanceof AutoCache ) {
return true;
}
}
return false;
}
}
Sendo assim, para que um método seja interceptado pelo Aspecto, basta anotá-lo conforme abaixo:
public PessoaServiceImpl implements PessoaService {
@AutoCache
public Pessoa get(Long id) {
// Do something
}
Se por acaso alguém tiver alguma sugestão de como melhorar esta implementação, por favor comentar.
[]'s
Annotation [] annotations = method.getDeclaredAnnotations();
for( Annotation an : annotations ) {
if( an instanceof AutoCache ) {
return true;
}
}
Não seria um pouquinho mais rápido:
return method.getAnnotation (AutoCache.class) != null;
:?:
(Não testei portanto não sei se funciona. Obviamente usar “getAnnotation” em vez de “getDeclaredAnnotations” tem uma semântica um pouco diferente, já que “getAnnotation” pega anotações herdadas, e “getDeclaredAnnotations” só pega as diretamente anotadas na classe.)
O incrivel thingol foi que eu executei o processo pegando os milisegundos para ver qto estava demorando, e praticamente não tem diferença. E como vc mesmo disse, o interessante é que eu considere somente as anotações declaradas diretamente no método.
Mas algo que esta me deixando com a pulga atrás da orelha é que eu encontrei uma implementação onde eu declaro a annotation no meu aspecto, mas não estou conseguindo entender como fazer o aspecto considerar somente os métodos anotados.
O processo que eu fiz irá considerar todos os métodos publicos dentro do projeto, e eu irei filtrar somente pelo if … esta tentando fazer um filtro mais inteligente.
Eu encontrei este link mas não consegui entender mto bem como fazer meu pointcut entender que eu irei considerar somente os métodos anotados.
public aspect AutoCacheAspect {
pointcut publicMethods(): execution(public * *.*(..));
declare @method : public * *.*(..) : @AutoCache; // Queria fazer isso funcionar :/
pointcut autoCache(): publicMethods();
before() : autoCache() {
if( this.isAssigned(thisJoinPointStaticPart.getSignature()) ) {
System.out.println("Before");
}
}
after() : autoCache() {
if( this.isAssigned(thisJoinPointStaticPart.getSignature()) ) {
System.out.println("After");
}
}
private Boolean isAssigned(Signature sig) {
Method method = ((MethodSignature)sig).getMethod();
Annotation [] annotations = method.getDeclaredAnnotations();
for( Annotation an : annotations ) {
if( an instanceof AutoCache ) {
return true;
}
}
return false;
}
}
Resolvi o problema com a seguinte solução:
public aspect AutoCacheAspect {
pointcut publicMethods(): execution(public * *.*(..));
pointcut autoCache(): publicMethods();
before() : autoCache() && @annotation( cc.marcio.cache.annotation.AutoCache ) {
System.out.println("Before");
}
after() : autoCache() && @annotation( cc.marcio.cache.annotation.AutoCache ) {
System.out.println("After");
}
}
Desta forma, os únicos métodos da aplicação que serão interceptados são os que forem anotados com @AutoCache.
[]'s
Pessoal,
Mais um problema no mesmo escopo.
Eu tenho na minha aplicação o spring fazendo a injeção de dependências dos objetos.
No spring, eu associo uma interface a um bean, e o mesmo via polimorfismo, instancia a implementação e injeta onde é necessário.
No meu aspecto, quando eu tento fazer o seguinte …
Signature sig = thisJoinPoint.getStaticPart().getSignature();
Method method = ((MethodSignature)sig).getMethod();
Annotation[] annotations = method.getAnnotations();
this.debug("Nome da classe do método : " + method.getDeclaringClass());
this.debug("Nome do método : " + method.getName());
this.debug("Quantidade de anotações no método : " + method.getDeclaredAnnotations().length);
… esta printando o seguinte :
[Fri Mar 13 17:53:23 BRT 2009] DEBUG : Nome da classe do método : interface cc.marcio.systems.service.IPessoaService
[Fri Mar 13 17:53:23 BRT 2009] DEBUG : Nome do método : list
[Fri Mar 13 17:53:23 BRT 2009] DEBUG : Quantidade de anotações no método : 0
O problema é que desta forma não estou conseguindo acessar a implementação do método, pois preciso recuperar algumas anotações que estão na implementação e a própria execução do método.
Alguém sabe como resolver isso?!?
Obrigado,
Ninguém tem idéia??!?! Desculpe o desespero