Spring AOP module providing aspect-oriented programming capabilities for the Spring Framework
—
Spring AOP provides comprehensive integration with AspectJ, supporting AspectJ pointcut expressions, @AspectJ annotations, and aspect instance management. This integration enables developers to use AspectJ's powerful expression language and annotation-based configuration while leveraging Spring's proxy-based AOP infrastructure.
Pointcut implementation using AspectJ's expression language for sophisticated join point matching.
public class AspectJExpressionPointcut implements ClassFilter, MethodMatcher, Pointcut, BeanFactoryAware, ParameterNameDiscoverer {
/**
* Set the AspectJ expression.
* @param expression the AspectJ expression
*/
public void setExpression(String expression);
/**
* Return the AspectJ expression.
*/
public String getExpression();
/**
* Set the parameter types, if they are known.
* @param types the parameter types
*/
public void setParameterTypes(Class<?>... types);
/**
* Set the parameter names, if they are known.
* @param names the parameter names
*/
public void setParameterNames(String... names);
/**
* Return the parameter names, if they are known, or {@code null} if not.
*/
public String[] getParameterNames();
/**
* Check whether this pointcut is ready to match,
* i.e. whether it has been configured with a complete expression.
*/
public boolean isReady();
// ClassFilter implementation
@Override
public boolean matches(Class<?> clazz);
// MethodMatcher implementation
@Override
public boolean matches(Method method, Class<?> targetClass);
@Override
public boolean isRuntime();
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args);
// Pointcut implementation
@Override
public ClassFilter getClassFilter();
@Override
public MethodMatcher getMethodMatcher();
}
public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdvisor implements BeanFactoryAware {
/**
* Create a new AspectJExpressionPointcutAdvisor.
*/
public AspectJExpressionPointcutAdvisor();
/**
* Create a new AspectJExpressionPointcutAdvisor.
* @param advice the advice to use
* @param expression the AspectJ expression
*/
public AspectJExpressionPointcutAdvisor(Advice advice, String expression);
/**
* Set the AspectJ expression.
* @param expression the AspectJ expression
*/
public void setExpression(String expression);
/**
* Return the AspectJ expression.
*/
public String getExpression();
/**
* Set the parameter names for the pointcut.
* @param parameterNames the parameter names
*/
public void setParameterNames(String... parameterNames);
/**
* Set the parameter types for the pointcut.
* @param parameterTypes the parameter types
*/
public void setParameterTypes(Class<?>... parameterTypes);
@Override
public Pointcut getPointcut();
}Spring AOP advice implementations that wrap AspectJ-style advice methods with precedence information.
public class AspectJMethodBeforeAdvice implements MethodBeforeAdvice, AspectJPrecedenceInformation {
/**
* Create a new AspectJMethodBeforeAdvice for the given advice method.
* @param adviceMethod the AspectJ-style advice method
* @param pointcut the AspectJ expression pointcut
* @param aspectInstanceFactory the factory for aspect instances
*/
public AspectJMethodBeforeAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory);
@Override
public void before(Method method, Object[] args, Object target) throws Throwable;
// AspectJPrecedenceInformation implementation
@Override
public String getAspectName();
@Override
public int getDeclarationOrder();
@Override
public boolean isBeforeAdvice();
@Override
public boolean isAfterAdvice();
}
public class AspectJAfterAdvice implements MethodInterceptor, AfterAdvice, AspectJPrecedenceInformation {
/**
* Create a new AspectJAfterAdvice for the given advice method.
* @param adviceMethod the AspectJ-style advice method
* @param pointcut the AspectJ expression pointcut
* @param aspectInstanceFactory the factory for aspect instances
*/
public AspectJAfterAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory);
@Override
public Object invoke(MethodInvocation mi) throws Throwable;
// AspectJPrecedenceInformation implementation
@Override
public String getAspectName();
@Override
public int getDeclarationOrder();
@Override
public boolean isBeforeAdvice();
@Override
public boolean isAfterAdvice();
}
public class AspectJAfterReturningAdvice implements AfterReturningAdvice, AspectJPrecedenceInformation {
/**
* Create a new AspectJAfterReturningAdvice for the given advice method.
* @param adviceMethod the AspectJ-style advice method
* @param pointcut the AspectJ expression pointcut
* @param aspectInstanceFactory the factory for aspect instances
*/
public AspectJAfterReturningAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory);
/**
* Set the name of the parameter in the advice method that receives the return value.
* @param name parameter name
*/
public void setReturningName(String name);
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
// AspectJPrecedenceInformation implementation methods...
}
public class AspectJAfterThrowingAdvice implements MethodInterceptor, AfterAdvice, AspectJPrecedenceInformation {
/**
* Create a new AspectJAfterThrowingAdvice for the given advice method.
* @param adviceMethod the AspectJ-style advice method
* @param pointcut the AspectJ expression pointcut
* @param aspectInstanceFactory the factory for aspect instances
*/
public AspectJAfterThrowingAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory);
/**
* Set the name of the parameter in the advice method that receives the thrown exception.
* @param name parameter name
*/
public void setThrowingName(String name);
@Override
public Object invoke(MethodInvocation mi) throws Throwable;
// AspectJPrecedenceInformation implementation methods...
}
public class AspectJAroundAdvice implements MethodInterceptor, AspectJPrecedenceInformation {
/**
* Create a new AspectJAroundAdvice for the given advice method.
* @param adviceMethod the AspectJ-style advice method
* @param pointcut the AspectJ expression pointcut
* @param aspectInstanceFactory the factory for aspect instances
*/
public AspectJAroundAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory);
@Override
public Object invoke(MethodInvocation mi) throws Throwable;
// AspectJPrecedenceInformation implementation methods...
}Specialized proxy factory for creating proxies with AspectJ aspects.
public class AspectJProxyFactory extends ProxyCreatorSupport {
/**
* Create a new AspectJProxyFactory.
*/
public AspectJProxyFactory();
/**
* Create a new AspectJProxyFactory.
* <p>Will proxy all interfaces that the given target implements.
* @param target the target object to be proxied
*/
public AspectJProxyFactory(Object target);
/**
* Add the supplied aspect instance to the chain. The type of the aspect instance
* supplied must be a singleton aspect. True singleton lifecycle is not honoured when
* using this method - the caller is responsible for managing the lifecycle of any
* aspects added in this way.
* @param aspectInstance the AspectJ aspect instance
*/
public void addAspect(Object aspectInstance);
/**
* Add an aspect of the supplied type to the end of the advice chain.
* @param aspectClass the AspectJ aspect class
*/
public void addAspect(Class<?> aspectClass);
/**
* Create a proxy according to this factory's settings.
* @return the proxy object
*/
@SuppressWarnings("unchecked")
public <T> T getProxy();
/**
* Create a proxy according to this factory's settings.
* @param classLoader the class loader to create the proxy with
* @return the proxy object
*/
@SuppressWarnings("unchecked")
public <T> T getProxy(ClassLoader classLoader);
}Factories for managing aspect instances and their metadata.
public interface AspectInstanceFactory {
/**
* Create an instance of this factory's aspect.
* @return the aspect instance (never {@code null})
*/
Object getAspectInstance();
/**
* Expose the aspect class loader that this factory uses.
* @return the aspect class loader (or {@code null} for the bootstrap loader)
* @see org.springframework.util.ClassUtils#getDefaultClassLoader()
*/
ClassLoader getAspectClassLoader();
/**
* Return the order value of this object, with a higher value meaning greater
* precedence. Normally starting with 0, with {@code Integer.MAX_VALUE}
* indicating the greatest precedence (corresponding to the lowest priority).
* <p>Same order values will result in arbitrary sort positions for the
* affected objects.
* @return the order value
* @see #HIGHEST_PRECEDENCE
* @see #LOWEST_PRECEDENCE
*/
int getOrder();
}
public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactory {
/**
* Return the AspectJ AspectMetadata for this factory's aspect.
* @return the aspect metadata
*/
AspectMetadata getAspectMetadata();
/**
* Return the best possible creation mutex for this factory:
* that is, an object that should be synchronized on for creation
* of the aspect instance.
* @return the mutex object (may be {@code null} for no mutex to use)
*/
Object getAspectCreationMutex();
}
public class SimpleAspectInstanceFactory implements AspectInstanceFactory {
/**
* Create a new SimpleAspectInstanceFactory for the given aspect class.
* @param aspectClass the aspect class
*/
public SimpleAspectInstanceFactory(Class<?> aspectClass);
@Override
public final Object getAspectInstance();
@Override
public ClassLoader getAspectClassLoader();
@Override
public int getOrder();
}
public class SingletonAspectInstanceFactory implements AspectInstanceFactory {
/**
* Create a new SingletonAspectInstanceFactory for the given aspect.
* @param aspectInstance the singleton aspect instance
*/
public SingletonAspectInstanceFactory(Object aspectInstance);
@Override
public final Object getAspectInstance();
@Override
public ClassLoader getAspectClassLoader();
@Override
public int getOrder();
}
public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInstanceFactory, BeanFactoryAware {
/**
* Create a BeanFactoryAspectInstanceFactory. AspectJ will be called to
* introspect to create AJType metadata using the type returned for the
* given bean name from the BeanFactory.
* @param beanFactory the BeanFactory to obtain instance(s) from
* @param beanName the name of the bean
*/
public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String beanName);
/**
* Set the name of the aspect bean. This is only used for tracing purposes,
* but can help debugging.
* @param aspectName the name to use. If not specified the bean name is used.
*/
public void setAspectName(String aspectName);
@Override
public Object getAspectInstance();
@Override
public ClassLoader getAspectClassLoader();
@Override
public AspectMetadata getAspectMetadata();
@Override
public Object getAspectCreationMutex();
@Override
public int getOrder();
}Classes for managing AspectJ aspect metadata and precedence information.
public class AspectMetadata implements Serializable {
/**
* Create a new AspectMetadata instance for the given aspect class.
* @param aspectClass the aspect class
* @param aspectName the name of the aspect
*/
public AspectMetadata(Class<?> aspectClass, String aspectName);
/**
* Return the AspectJ type representation of this aspect class.
*/
public AjType<?> getAjType();
/**
* Return the aspect class.
*/
public Class<?> getAspectClass();
/**
* Return the aspect name.
*/
public String getAspectName();
/**
* Return the per clause pointcut, or {@code Pointcut.TRUE} if there is no per clause.
* <p>NB: This returns the value of the per clause on the aspect.
* If this aspect was configured as a Spring bean using BeanFactory semantics,
* then this will not be the same as BeanFactory semantics.
* In such cases {@code BeanFactoryAspectInstanceFactory} should be used.
*/
public Pointcut getPerClausePointcut();
/**
* Return whether the aspect is defined as "perthis" or "pertarget".
*/
public boolean isPerThisOrPerTarget();
/**
* Return whether the aspect is defined as "pertypewithin".
*/
public boolean isPerTypeWithin();
/**
* Return whether the aspect needs to be lazily instantiated.
*/
public boolean isLazilyInstantiated();
}
public interface AspectJPrecedenceInformation {
/**
* Return the name of the aspect (bean) in which the advice was declared.
*/
String getAspectName();
/**
* Return the declaration order of the advice member within the aspect.
*/
int getDeclarationOrder();
/**
* Return whether this is a before advice.
*/
boolean isBeforeAdvice();
/**
* Return whether this is an after advice.
*/
boolean isAfterAdvice();
}Support for processing @AspectJ annotated classes and creating advisors from them.
public interface AspectJAdvisorFactory {
/**
* Determine whether or not the given class is an aspect, as reported
* by AspectJ's {@link org.aspectj.lang.reflect.AjTypeSystem}.
* <p>Will simply return {@code false} if the supposed aspect is
* not an AspectJ aspect at all.
* @param clazz the supposed annotation-style AspectJ aspect class
* @return whether or not this class is recognized by AspectJ as an aspect class
*/
boolean isAspect(Class<?> clazz);
/**
* Is the given class a valid AspectJ aspect class?
* @param aspectClass the aspect class to validate
* @throws AopConfigException if the class is an invalid aspect
* (which can never be legal)
* @throws NotAnAtAspectException if the class is not an aspect at all
* (which may or may not be legal, depending on the context)
*/
void validate(Class<?> aspectClass) throws AopConfigException;
/**
* Build Spring AOP Advisors for all annotated At-AspectJ methods
* on the specified aspect instance.
* @param aspectInstanceFactory the aspect instance factory
* (not the aspect instance itself in order to avoid eager instantiation)
* @return a list of advisors for this class
*/
List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory);
/**
* Build a Spring AOP Advisor for the given AspectJ advice method.
* @param candidateAdviceMethod the candidate advice method
* @param aspectInstanceFactory the aspect instance factory
* @param declarationOrder the declaration order within the aspect
* @param aspectName the name of the aspect
* @return {@code null} if the method is not an AspectJ advice method
* or if it is a pointcut that will be used by other advice but will not
* create a Spring advice in its own right
*/
Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrder, String aspectName);
}
public class ReflectiveAspectJAdvisorFactory implements AspectJAdvisorFactory, Serializable {
@Override
public boolean isAspect(Class<?> clazz);
@Override
public void validate(Class<?> aspectClass) throws AopConfigException;
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory);
@Override
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrder, String aspectName);
}Additional support classes for AspectJ integration.
public class TypePatternClassFilter implements ClassFilter {
/**
* Create a new TypePatternClassFilter for the given AspectJ type pattern.
* @param typePattern the AspectJ type pattern
*/
public TypePatternClassFilter(String typePattern);
@Override
public boolean matches(Class<?> clazz);
}
public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint, JoinPoint.StaticPart {
/**
* Create a new MethodInvocationProceedingJoinPoint, wrapping the given
* Spring ProxyMethodInvocation object.
* @param methodInvocation the Spring ProxyMethodInvocation object
*/
public MethodInvocationProceedingJoinPoint(ProxyMethodInvocation methodInvocation);
@Override
public Object proceed() throws Throwable;
@Override
public Object proceed(Object[] args) throws Throwable;
// JoinPoint implementation methods...
@Override
public String toShortString();
@Override
public String toLongString();
@Override
public Object getThis();
@Override
public Object getTarget();
@Override
public Object[] getArgs();
@Override
public Signature getSignature();
@Override
public SourceLocation getSourceLocation();
@Override
public String getKind();
@Override
public JoinPoint.StaticPart getStaticPart();
}// Create pointcut with AspectJ expression
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* com.example.service.*Service.*(..))");
// Use in advisor
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
advisor.setExpression("execution(* com.example.service.*Service.*(..))");
advisor.setAdvice(new LoggingInterceptor());
// Complex expressions
pointcut.setExpression(
"execution(public * com.example.service.*Service.*(..)) && " +
"@annotation(org.springframework.transaction.annotation.Transactional)"
);// Create AspectJ-based proxy
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
// Add aspect instance
@Aspect
class LoggingAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long executionTime = System.currentTimeMillis() - start;
System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");
return result;
}
}
factory.addAspect(new LoggingAspect());
MyService proxy = factory.getProxy();
// Or add aspect class
factory.addAspect(LoggingAspect.class);public class CustomAspectJAdvice implements MethodInterceptor, AspectJPrecedenceInformation {
private final String aspectName;
private final int declarationOrder;
public CustomAspectJAdvice(String aspectName, int declarationOrder) {
this.aspectName = aspectName;
this.declarationOrder = declarationOrder;
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// Custom advice logic here
System.out.println("Custom AspectJ advice executing for: " + invocation.getMethod().getName());
return invocation.proceed();
}
@Override
public String getAspectName() {
return aspectName;
}
@Override
public int getDeclarationOrder() {
return declarationOrder;
}
@Override
public boolean isBeforeAdvice() {
return false;
}
@Override
public boolean isAfterAdvice() {
return true;
}
}// Examine aspect metadata
Class<?> aspectClass = MyAspect.class;
AspectMetadata metadata = new AspectMetadata(aspectClass, "myAspect");
System.out.println("Aspect name: " + metadata.getAspectName());
System.out.println("Aspect class: " + metadata.getAspectClass().getName());
System.out.println("Is per-this or per-target: " + metadata.isPerThisOrPerTarget());
System.out.println("Requires lazy instantiation: " + metadata.isLazilyInstantiated());
// Get per-clause pointcut
Pointcut perClause = metadata.getPerClausePointcut();
if (perClause != Pointcut.TRUE) {
System.out.println("Has per-clause pointcut");
}Install with Tessl CLI
npx tessl i tessl/maven-org-springframework--spring-aop