Mastering Spring Control Flow Pointcuts: A Hands‑On Example
This article explains Spring's control flow pointcuts, compares them with AspectJ cflow pointcuts, walks through a complete Java example with nested service classes, shows how to configure a ControlFlowPointcut and proxy, and discusses performance implications and usage scenarios.
Environment: Spring 5.3.23.
1. Introduction
Spring control flow pointcuts are conceptually similar to AspectJ cflow pointcuts, though less powerful. They match the current call stack, firing when a join point is invoked from a specified class or method. The pointcut is defined using org.springframework.aop.support.ControlFlowPointcut .
2. Control Flow Example
Three simple classes are used to demonstrate nested calls: PersonDAO , PersonService , and PersonManager .
<code>static class PersonDAO {
public void save(String name) {
System.out.println("PersonDAO save method invoke...");
}
}
static class PersonService {
private PersonDAO dao;
public PersonService(PersonDAO dao) { this.dao = dao; }
public void save(String name) {
System.out.println("PersonService save method invoke...");
this.dao.save(name);
}
}
static class PersonManager {
private PersonService ps;
public void setPs(PersonService ps) { this.ps = ps; }
public void index(String name) {
System.out.println("PersonManager index method invoke...");
this.ps.save(name);
}
}
</code>Instantiate the classes and create a proxy for PersonService using a ControlFlowPointcut that matches PersonManager.index :
<code>PersonDAO dao = new PersonDAO();
PersonService target = new PersonService(dao);
PersonManager pm = new PersonManager();
Class<?> clazz = PersonManager.class;
String methodName = "index";
ControlFlowPointcut pointcut = new ControlFlowPointcut(clazz, methodName);
MethodInterceptor logInterceptor = invocation -> {
System.out.println("before log...");
Object ret = invocation.proceed();
System.out.println("after log...");
return ret;
};
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, logInterceptor);
ProxyFactory factory = new ProxyFactory(target);
factory.addAdvisor(advisor);
factory.setProxyTargetClass(true);
PersonService ps = (PersonService) factory.getProxy();
pm.setPs(ps);
pm.index("张三");
</code>Console output:
<code>PersonManager index method invoke...
before log...
PersonService save method invoke...
PersonDAO save method invoke...
after log...
</code>The output shows that the interceptor runs before and after the PersonService.save method because the control flow matches the specified class and method.
Core Methods of ControlFlowPointcut
<code>public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher, Serializable {
private final Class<?> clazz;
@Nullable private final String methodName;
@Override
public boolean matches(Class<?> clazz) { return true; }
@Override
public boolean matches(Method method, Class<?> targetClass) { return true; }
@Override
public boolean isRuntime() { return true; }
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
for (StackTraceElement element : new Throwable().getStackTrace()) {
if (element.getClassName().equals(this.clazz.getName()) &&
(this.methodName == null || element.getMethodName().equals(this.methodName))) {
return true;
}
}
return false;
}
}
</code>Only when the runtime check returns true does the interceptor execute.
3. Performance
Dynamic pointcuts, including control flow pointcuts, are more expensive to evaluate than static ones because they must consider the current call stack on each method invocation and cannot cache results. In Java 1.4, the cost is roughly five times that of other dynamic pointcuts.
4. Usage Considerations
Control flow pointcuts are useful when you need to apply advice only when a method is invoked within a specific call chain, such as logging or security checks that depend on the caller context.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.