The AspectJ runtime is a small library necessary to run Java programs enhanced by AspectJ aspects during a previous compile-time or post-compile-time (binary weaving) build step.
—
Runtime support for aspect instantiation, lifecycle management, and access across different instantiation models. AspectJ supports various aspect instantiation patterns including singleton, per-object (perthis/pertarget), per-type-within, and control flow-based (percflow/percflowbelow) aspects. The aspect management API provides programmatic access to aspect instances and their binding status.
The Aspects class handles generic aspectOf method functionality when those methods are not available in the aspects but added later through load time weaving. It provides reflective access to aspect instances across all supported instantiation models.
/**
* Handles generic aspectOf method when those are not available in the aspects but added later on
* through load time weaving. Aspects.aspectOf(..) is doing reflective calls to the aspect aspectOf,
* so for better performance consider using ajc compilation of the aspects and using them as a binary
* dependencies in your project.
*/
public class Aspects {
/**
* Returns the singleton aspect or the percflow / percflowbelow associated with the current thread
* @param aspectClass the aspect class
* @return the singleton aspect or the percflow / percflowbelow associated with the current thread
* @throws NoAspectBoundException if no such aspect
*/
public static <T> T aspectOf(Class<T> aspectClass) throws NoAspectBoundException;
/**
* Returns the associated perthis / pertarget aspect instance
* @param aspectClass the aspect class
* @param perObject the this/target object for which to look for an aspect instance
* @return the associated perthis / pertarget aspect instance
* @throws NoAspectBoundException if no such aspect, or no aspect bound
*/
public static <T> T aspectOf(Class<T> aspectClass, Object perObject) throws NoAspectBoundException;
/**
* Returns the associated pertypewithin aspect instance
* @param aspectClass the aspect class
* @param perTypeWithin the class for which to search for an aspect instance
* @return the associated aspect instance
* @throws NoAspectBoundException if no such aspect, or no aspect bound
*/
public static <T> T aspectOf(Class<T> aspectClass, Class<?> perTypeWithin) throws NoAspectBoundException;
/**
* Checks if singleton aspect or percflow / percflowbelow aspect is bound
* @param aspectClass the aspect class
* @return true if singleton aspect or percflow / percflowbelow aspect is bound
*/
public static boolean hasAspect(Class<?> aspectClass);
/**
* Checks if the perthis / pertarget aspect is bound
* @param aspectClass the aspect class
* @param perObject the this/target object for which to look for an aspect instance
* @return true if the perthis / pertarget aspect is bound
*/
public static boolean hasAspect(Class<?> aspectClass, Object perObject);
/**
* Checks if the pertypewithin aspect is bound
* @param aspectClass the aspect class
* @param perTypeWithin class
* @return true if the pertypewithin aspect is bound
*/
public static boolean hasAspect(Class<?> aspectClass, Class<?> perTypeWithin);
}Usage Examples:
import org.aspectj.lang.Aspects;
import org.aspectj.lang.NoAspectBoundException;
// Singleton aspect access
@Aspect
public class LoggingAspect {
private int callCount = 0;
@Before("execution(* com.example..*.*(..))")
public void logCall() {
callCount++;
System.out.println("Call #" + callCount);
}
public int getCallCount() {
return callCount;
}
}
public class AspectClient {
public void checkLoggingAspect() {
try {
if (Aspects.hasAspect(LoggingAspect.class)) {
LoggingAspect aspect = Aspects.aspectOf(LoggingAspect.class);
System.out.println("Total calls: " + aspect.getCallCount());
} else {
System.out.println("Logging aspect is not bound");
}
} catch (NoAspectBoundException e) {
System.out.println("Failed to access aspect: " + e.getMessage());
}
}
}For aspects with perthis() or pertarget() instantiation, each target object gets its own aspect instance:
// Per-object aspect example
@Aspect("perthis(execution(* com.example.service.*.*(..)))")
public class ServiceMonitorAspect {
private long startTime;
private int methodCount = 0;
@Before("execution(* com.example.service.*.*(..))")
public void startTiming() {
if (methodCount == 0) {
startTime = System.currentTimeMillis();
}
methodCount++;
}
public long getElapsedTime() {
return System.currentTimeMillis() - startTime;
}
public int getMethodCount() {
return methodCount;
}
}
public class ServiceClient {
public void monitorService(Object serviceInstance) {
try {
if (Aspects.hasAspect(ServiceMonitorAspect.class, serviceInstance)) {
ServiceMonitorAspect monitor =
Aspects.aspectOf(ServiceMonitorAspect.class, serviceInstance);
System.out.println("Service has been running for " +
monitor.getElapsedTime() + " ms");
System.out.println("Methods called: " + monitor.getMethodCount());
}
} catch (NoAspectBoundException e) {
System.out.println("No monitor bound to this service instance");
}
}
}For aspects with pertypewithin() instantiation, each type within the specified type pattern gets its own aspect instance:
// Per-type-within aspect example
@Aspect("pertypewithin(com.example.model.*)")
public class EntityAuditAspect {
private final String entityType;
private int operationCount = 0;
public EntityAuditAspect() {
// The entity type is determined at aspect creation time
this.entityType = thisJoinPoint.getSignature().getDeclaringType().getSimpleName();
}
@Before("execution(* set*(..))")
public void auditPropertyChange() {
operationCount++;
System.out.println("Property change in " + entityType +
" (operation #" + operationCount + ")");
}
public int getOperationCount() {
return operationCount;
}
}
public class EntityAuditClient {
public void checkEntityAudit(Class<?> entityClass) {
try {
if (Aspects.hasAspect(EntityAuditAspect.class, entityClass)) {
EntityAuditAspect audit =
Aspects.aspectOf(EntityAuditAspect.class, entityClass);
System.out.println("Audit operations for " + entityClass.getSimpleName() +
": " + audit.getOperationCount());
}
} catch (NoAspectBoundException e) {
System.out.println("No audit aspect for " + entityClass.getSimpleName());
}
}
}The aspect management API uses NoAspectBoundException to indicate when aspects are not available:
/**
* Thrown by the aspectOf special method on aspect types
* when there is no aspect of that type currently bound.
*/
public class NoAspectBoundException extends RuntimeException {
/**
* Constructs exception with aspect name and optional cause
* @param aspectName name of the aspect that is not bound
* @param inner the underlying cause, if any
*/
public NoAspectBoundException(String aspectName, Throwable inner);
/**
* Default constructor for cases where no specific information is available
*/
public NoAspectBoundException();
/**
* Returns the underlying cause of this exception
* @return the cause, or null if there is no cause
*/
public Throwable getCause();
}Usage Examples:
public class RobustAspectClient {
public <T> T safeAspectAccess(Class<T> aspectClass) {
try {
return Aspects.aspectOf(aspectClass);
} catch (NoAspectBoundException e) {
System.err.println("Aspect " + aspectClass.getSimpleName() +
" is not bound: " + e.getMessage());
if (e.getCause() != null) {
System.err.println("Underlying cause: " + e.getCause().getMessage());
}
return null;
}
}
public void conditionalAspectUsage(Object target) {
// Check before attempting access
if (Aspects.hasAspect(ServiceMonitorAspect.class, target)) {
try {
ServiceMonitorAspect monitor =
Aspects.aspectOf(ServiceMonitorAspect.class, target);
// Use the aspect safely
System.out.println("Monitor found: " + monitor.getMethodCount() + " calls");
} catch (NoAspectBoundException e) {
// This should rarely happen if hasAspect returned true
System.err.println("Race condition: aspect became unbound");
}
}
}
}AspectJ supports several instantiation models that determine when and how aspect instances are created:
@Aspect or @Aspect("")Aspects.aspectOf(AspectClass.class)@Aspect("perthis(pointcut)")this()Aspects.aspectOf(AspectClass.class, thisObject)@Aspect("pertarget(pointcut)")target()Aspects.aspectOf(AspectClass.class, targetObject)@Aspect("pertypewithin(TypePattern)")Aspects.aspectOf(AspectClass.class, matchingClass)@Aspect("percflow(pointcut)") or @Aspect("percflowbelow(pointcut)")Aspects.aspectOf(AspectClass.class) (thread-local)ajc and use them as binary dependencies rather than relying on load-time weavingAspects class uses reflection internally, so direct aspect access (when available) is more efficienthasAspect() before aspectOf() to avoid exceptions in conditional access scenariosInstall with Tessl CLI
npx tessl i tessl/maven-org-aspectj--aspectjrt