
Originally Posted by
Marten Deinum
Post your pointcuts... There should be nothing preventing you writing a single method, the transaction support (for one example) does the same.
OK, here are more details.
Main.java:
Code:
package com.mypackage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import com.mypackage.service.MyService;
@Component
public class Main {
@Autowired
private MyService service;
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
Main instance = context.getBean(Main.class);
instance.go();
}
private void go() {
service.operation1();
service.operation2();
}
}
MyService.java:
Code:
package com.mypackage.service;
public interface MyService {
void operation1();
void operation2();
}
MyServiceImpl.java:
Code:
package com.mypackage.service;
import org.springframework.stereotype.Service;
import com.mypackage.Retryable;
@Service
@Retryable(maxRetries = 1)
public class ServiceImpl implements MyService {
@Retryable(maxRetries = 2)
public void operation1() {
System.out.println("operation1()");
}
// maxRetries = 1 should apply here
public void operation2() {
System.out.println("operation2()");
}
}
Retryable.java:
Code:
package com.mypackage;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Retryable {
int maxRetries();
}
MyAdvice.java:
Code:
package com.mypackage;
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.springframework.stereotype.Component;
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(* com.mypackage.service.*.*(..))")
public void serviceOperation() {
}
@Pointcut("serviceOperation() && @target(retryable)")
public void operWithTypeLevel(Retryable retryable) {
}
@Pointcut("serviceOperation() && @annotation(retryable)")
public void operWithMethodLevel(Retryable retryable) {
}
@Pointcut("operWithTypeLevel(retryable) || operWithMethodLevel(retryable)")
public void operWithTypeOrMethodLevel(Retryable retryable) {
}
@Around("operWithTypeOrMethodLevel(retryable)")
public Object advise(ProceedingJoinPoint jp, Retryable retryable)
throws Throwable {
System.out.println(String.format("jp: %s, r: %s", jp, retryable));
return jp.proceed();
}
}
applicationContext.xml:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
>
<context:component-scan base-package="com.mypackage"/>
<aop:aspectj-autoproxy/>
</beans>
Execution output:
Code:
jp: execution(void com.mypackage.service.MyService.operation1()), r: @com.mypackage.Retryable(maxRetries=2)
operation1()
jp: execution(void com.mypackage.service.MyService.operation2()), r: null
operation2()
As you can see, the passed-in annotation is null for the second method, where I was expecting the type level annotation to apply. If I refactor the above code to use two advice methods (one to handle each case), it works as expected. I also came across another post here (I don't have a link now), where someone mentioned that having a single pointcut would be ambiguous.
Thanks,
Lukasz