Mastering Spring AOP Advice Lifecycle and Types with Code Examples
This article explains the Spring AOP advice lifecycle, distinguishes shared and per‑instance advice beans, and details each advice type—around, before, throws, after‑returning, and introduction—along with practical Java code snippets for implementation.
Advice Lifecycle
In Spring, every Advice is a bean. An Advice instance can be shared across all Advisors or be unique per Advisor, corresponding to class‑level or instance‑level advice.
The most common scenario is class‑level (shared) advice, used for generic concerns such as transaction management that do not depend on the proxy instance state.
Instance‑level advice is used for introductions (mix‑ins) where the advice adds state to the proxy object.
You can combine shared and instance advice within the same AOP proxy.
Advice Types
Spring provides several advice types and can be extended to support custom ones.
Around Advice (MethodInterceptor)
The core around advice is implemented via the MethodInterceptor interface from the AOP Alliance.
<code>public interface MethodInterceptor extends org.aopalliance.intercept.Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}</code>A simple implementation:
<code>public class DebugInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Before: invocation=[" + invocation + "]");
Object rval = invocation.proceed();
System.out.println("Invocation returned");
return rval;
}
}</code>MethodInterceptor provides interoperability with other AOP Alliance implementations; using the most specific advice type is beneficial, but for cross‑framework compatibility prefer MethodInterceptor.
Before Advice
Executed before a method invocation and does not require a MethodInvocation object.
<code>public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method m, Object[] args, Object target) throws Throwable;
}</code>Example that counts method calls:
<code>public class CountingBeforeAdvice implements MethodBeforeAdvice {
private int count;
public void before(Method m, Object[] args, Object target) throws Throwable {
++count;
}
public int getCount() { return count; }
}</code>Throws Advice
Invoked after a method throws an exception. The marker interface ThrowsAdvice has no methods; concrete advice defines afterThrowing signatures.
<code>public class BusinessThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(BusinessException ex) throws Throwable {
// ...
}
}</code>Multiple signatures can be defined to access method, args, target, and exception details.
<code>public class ControllerAdviceWithArguments implements ThrowsAdvice {
public void afterThrowing(Method m, Object[] args, Object target, MethodArgumentNotValidException ex) {
// ...
}
}</code>After‑Returning Advice
Implemented via AfterReturningAdvice , it can read the return value but cannot modify it.
<code>public interface AfterReturningAdvice extends Advice {
void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable;
}</code>Example that counts successful returns:
<code>public class CountingAfterReturningAdvice implements AfterReturningAdvice {
private int count;
public void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable {
++count;
}
public int getCount() { return count; }
}</code>Introduction Advice
Specialized interceptor that adds new interfaces to a target class. It requires an IntroductionAdvisor and an IntroductionInterceptor .
<code>public interface IntroductionInterceptor extends MethodInterceptor {
boolean implementsInterface(Class intf);
}</code>Sample interceptor that adds a CountDAO interface:
<code>public class CustomIntroductionInterceptor implements IntroductionInterceptor, CountDAO {
@Override public void count() { System.out.println("订单统计..."); }
@Override public boolean implementsInterface(Class<?> intf) { return CountDAO.class.isAssignableFrom(intf); }
@Override public Object invoke(MethodInvocation invocation) throws Throwable {
if (implementsInterface(invocation.getMethod().getDeclaringClass())) {
System.out.println("我是Introduction增强... Class: " + invocation.getMethod().getDeclaringClass() + ", method: " + invocation.getMethod().getName());
return invocation.getMethod().invoke(this, invocation.getArguments());
}
return invocation.proceed();
}
}</code>The advisor supplies the interceptor and the interface to introduce:
<code>public interface IntroductionAdvisor extends Advisor, IntroductionInfo {
ClassFilter getClassFilter();
void validateInterfaces() throws IllegalArgumentException;
}
public interface IntroductionInfo { Class<?>[] getInterfaces(); }</code>Creating a proxy that applies the introduction only to beans of type OrderDAO :
<code>@Component
public class OrderProxyCreator extends AbstractAutoProxyCreator {
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource) throws BeansException {
return new Object[] { new DefaultIntroductionAdvisor(new CustomIntroductionInterceptor(), CountDAO.class) };
}
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
return !OrderDAO.class.isAssignableFrom(beanClass);
}
}</code>Testing the setup demonstrates that OrderDAO gains the CountDAO capability at runtime.
<code>AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext("com.pack.aop");
ctx.registerShutdownHook();
OrderDAO orderDao = ctx.getBean(OrderDAO.class);
orderDao.save();
Object obj = ctx.getBean("orderDAOImpl");
if (obj instanceof CountDAO) { ((CountDAO) obj).count(); }</code>Output:
<code>保存订单...
我是Introduction增强.. Class: interface com.pack.aop.CountDAO, method: count
订单统计...</code>The result shows that OrderDAO now implements CountDAO through the introduction interceptor.
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.