:: Problema usando Spring AOP

0 respostas
marciobarroso

Estou com um problema e queria ver se alguém poderia me dar uma sugestão de como resolver.

Desenvolvi um componente de log que usa aspecto.

Funciona da seguinte forma:

Annotation Log

package com.marciob.components.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)  
@Target({ElementType.TYPE, ElementType.METHOD}) 
@Documented
public @interface Log {
	
	boolean exclude() default false;
	Level level() default Level.TRACE;
	public enum Level { TRACE, DEBUG, INFO, WARN, ERROR }
	
}

Aspecto LoggerAspect

package com.marciob.components.aspects;

import com.marciob.components.annotations.Log;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggerAspect {
	
	@Pointcut("execution(* @com.marciob.components.annotations.Log *.*(..))")
	public void methodAnnotatedExecution() {}
	
	@Pointcut("execution(@com.marciob.components.annotations.Log *.new(..))")
	public void methodExecutionInATypeAnnotated() {}
	
	@Around("methodAnnotatedExecution() && !methodExecutionInATypeAnnotated()")
	public Object arround(ProceedingJoinPoint pjp) throws Throwable {
		// Execução do logger
	}
}

O escopo da annotation é type e método, ou seja, você pode anotar alguns métodos de uma classe ou anotar a classe, fazendo com que todos os métodos sejam logados.

Eu escrevi também alguns testes unitários para este componente:

JUnit LoggerTest

package com.marciob.components.aspects;

import java.util.Date;

import junit.framework.TestCase;

import com.marciob.components.annotations.Log;
import com.marciob.components.annotations.Log.Level;

@Log
public class LoggerTest extends TestCase {

	public void testLogTraceLevel() {
		assert(true);
	}
	
	@Log(level=Level.DEBUG)
	public void testLogDebugLevel() {
		Date date = this.getDate("param string", 32, new Date());
		assert(date != null);
	}
	
	@Log(level=Level.INFO)
	public void testLogInfoLevel() {
		assert(true);
	}
	
	@Log(level=Level.ERROR)
	public void testLogErrorLevel() {
		assert(true);
	}
	
	@Log(level=Level.ERROR)
	public Date getDate(String param, Integer num, Date date) {
		return date;
	}
}

A execução do teste unitário funciona normalmente sem nenhum problema. Mas quando eu aplico o aspecto a uma classe da minha aplicação web, esta dando um erro na hora de subir o TOMCAT.

Log Tomcat

Cannot resolve reference to bean 'checkoutTriggerJob' while setting bean property 'jobDetail'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'checkoutTriggerJob' defined in class path resource [ApplicationContext.xml]: Cannot resolve reference to bean 'userBusiness' while setting bean property 'jobDataAsMap' with key [TypedStringValue: value [userBusiness], target type [null]]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userBusiness' defined in file [C:\_dev\tools\apache\apache-tomcat-6.0.29\webapps\marciob\WEB-INF\classes\com\marciob\site\business\UserBusinessImpl.class]: Instantiation of bean failed; nested exception is java.lang.NoSuchMethodError: com.marciob.components.aspects.LoggerAspect.aspectOf()Lcom/marciob/components/aspects/LoggerAspect;
PropertyAccessException 2: org.springframework.beans.MethodInvocationException: Property 'transportIds' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.scheduling.quartz.SchedulerFactoryBean#0' defined in class path resource [ApplicationContext.xml]: Cannot resolve reference to bean 'checkoutTriggerSchedule' while setting bean property 'triggers' with key [0]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'checkoutTriggerSchedule' defined in class path resource [ApplicationContext.xml]: Cannot resolve reference to bean 'checkoutTriggerJob' while setting bean property 'jobDetail'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'checkoutTriggerJob' defined in class path resource [ApplicationContext.xml]: Cannot resolve reference to bean 'userBusiness' while setting bean property 'jobDataAsMap' with key [TypedStringValue: value [userBusiness], target type [null]]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userBusiness' defined in file [C:\_dev\tools\apache\apache-tomcat-6.0.29\webapps\marciob\WEB-INF\classes\com\marciob\site\business\UserBusinessImpl.class]: Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: Could not initialize class com.marciob.site.business.UserBusinessImpl

Eu verifiquei que no ambiente Spring existem algumas restrições para o suporte AOP e eu estou respeitando estas restrições. O erro esta relacionado a inicialização da classe que esta sendo anotada, falando que a inicialização da classe não suporta o pointcut @Around

Eu tentei de todas as formas escrever um pointcut que restrinja o aspecto de inicialização da classe, porém no ambiente do JUnit funciona, mas no Spring não.

Alguém tem alguma sugestão de como resolver isso?

Minha classe de negócio que esta dando problemas no ambiente spring é a seguinte:

Classe negócio - ambiente Spring

package com.marciob.site.business;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.marciob.components.annotations.Log;

@Component("securityChecker")
@Transactional
@Log
public class UserBusinessImpl implements UserBusiness {
	
	private UserService userService;
	
	@Autowired
	public void setUserService(UserService userService) {
		this.userService = userService;
	}
	
	// Métodos
}

Qualquer ajuda é válida.

[]'s

Criado 29 de abril de 2011
Respostas 0
Participantes 1