Spring AOP pointcut definition for string setter
I'm developing an aspect that checks string arguments of setter methods of my entity package for empty strings and replace them with null
values. But unfortunately my aspect doesn't works well :(. I guess it is because of my pointcut definition, but I'm not sure.
My aspect looks like:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class EmptyStringToNullSetter {
private static final Logger LOGGER = LoggerFactory
.getLogger(EmptyStringToNullSetter.class);
public void check(final JoinPoint jp) {
LOGGER.debug(jp.getSignature().toLongString());
}
}
My spring config looks like:
&l开发者_开发百科t;bean id="emptyStringToNullSetter" class="de.foo.util.aop.parameter.EmptyStringToNullSetter" />
<aop:config>
<aop:pointcut id="entityStringSetter" expression="execution(* de.foo.entity.*.set*(..)) and args(java.lang.String)" />
<aop:aspect id="checkEmptyStringsAspect" ref="emptyStringToNullSetter">
<aop:before method="check" pointcut-ref="entityStringSetter" />
</aop:aspect>
</aop:config>
My test class looks like:
import de.foo.entity.Period;
@ContextConfiguration(locations = { "/spring/test-util-context.xml" })
public class EmptyStringToNullSetterTest extends
AbstractJUnit4SpringContextTests {
@Test
public void testCheck() {
Period period = new Period();
period.setName("");
Assert.assertNull(period.getName());
}
}
When I execute my test the aspect doesn't intercept my setter. Do anyone has any idea why?!
Cheers,
Kevin
Since you are using proxy-based AOP, the advice will apply only to Spring beans and the "period" object isn't a bean. You need to either have "period" as a bean or use AspectJ's weaving based AOP. In either case, you will also need to use an around advice instead of before.
This design is very tricky and error-prone with Spring JDK proxy based AOP.
I've mentionned this point here: http://doanduyhai.wordpress.com/2011/08/08/spring-aop-advices-on-setters-not-trigged/
Basically, an aspect define with Spring AOP is implemented at runtime as a proxy object wrapping around the original target.
In the bean lifecycle, Spring will create proxies only after the bean is fully initialized, e.g. after all properties injection by setter.
So the first time your setter is called, it will not be intercepted by the advice because the proxy does not exist yet.
However all subsequent calls to the setter will be intercepted.
Furthermore, be careful about self-invocation issues, e.g. calling the setter() inside another target method.
精彩评论