
# @Aspect

`@Aspect()` marks a bean class whose methods are advice: code that runs before, after or around the calls of other beans.

## Why you need it

An aspect is the place where cross-cutting code lives: logging, timing, auditing, checks. You write it once, and its pointcuts decide which methods of which beans it applies to. The advised beans stay unchanged.

You do not need an aspect when:

- the extra code concerns one class only: put it in that class;
- the advice is a reusable object chosen in code, for example in a library: declare a `PointcutAdvisor` bean instead (see [Proxies](proxies.md)).

## Declaring an aspect

The aspect must also be a bean. Add `@Component()`, or return it from a `@Bean` method. It can inject other beans like any bean. It is never proxied itself.

```dart
import 'package:spring_core_dart/spring_core_dart.dart';

// A plain bean that stores audit lines.
@Component()
class AuditTrail {
  final lines = <String>[];

  void record(String line) => lines.add(line);
}

// Records every call to the order service.
@Aspect()
@Component()
class AuditAspect {
  AuditAspect(this.trail); // aspects inject other beans as usual

  final AuditTrail trail;

  @Before('execution(* OrderService.*(..))')
  void audit(JoinPoint joinPoint) =>
      trail.record('${joinPoint.toShortString()} ${joinPoint.args}');
}
```

The methods of an aspect carry one advice annotation each: `@Before`, `@After`, `@AfterReturning`, `@AfterThrowing` or `@Around` (see [Advice](advice.md)). Empty methods with `@Pointcut` give a pointcut a name (see [Pointcuts](pointcut.md)). Advice and `@Pointcut` methods of the aspect's superclasses and mixins are inherited.

## Ordering several aspects

When several aspects advise the same call, `@Order` on the aspect class decides, or implementing `Ordered`. The lower value is the outer one: its `@Before` runs first and its `@After` runs last. Aspects without an order come last.

```dart
// Security checks run outside timing, so a refused call is not timed.
@Aspect()
@Component()
@Order(1)
class SecurityAspect {
  @Before('@within(Service)')
  void check(JoinPoint joinPoint) {
    // throw to refuse the call
  }
}

@Aspect()
@Component()
@Order(2)
@Log()
class TimingAspect {
  @Around('@within(Service)')
  Object? time(ProceedingJoinPoint call) {
    final watch = Stopwatch()..start();
    try {
      return call.proceed();
    } finally {
      log.info('${call.toShortString()} ${watch.elapsedMilliseconds} ms');
    }
  }
}
```

Inside one aspect, advice nests by kind: around, then before, after, afterReturning, afterThrowing. Advice of the same kind keeps declaration order.

## Per-instance aspects

By default there is one aspect instance for the whole application. The annotation's value can change this:

- `perthis(pointcut)`: one aspect instance per proxy;
- `pertarget(pointcut)`: one aspect instance per target bean.

Use this when the aspect keeps state for each advised object. Such an aspect must be a prototype bean (`@Scope('prototype')`). Its advice applies only where both the per-clause pointcut and the advice's own pointcut match.

```dart
// Counts the calls of each Orders proxy separately.
@Aspect('perthis(execution(* Orders.*(..)))')
@Component()
@Scope('prototype')
class CallCounter {
  int calls = 0;

  @Before('execution(* Orders.*(..))')
  void count() => calls++;
}
```

The build fails for a singleton per-instance aspect, for `percflow` and for `pertypewithin`.

## Parameters

| Name | Type | Default | Meaning |
|---|---|---|---|
| `value` | `String` | `''` | The instantiation model. Empty: one shared instance. `perthis(pointcut)`: one per proxy. `pertarget(pointcut)`: one per target bean. |

## Rules

- `@Aspect()` alone does not make a bean. Add `@Component()` or a `@Bean` method.
- The generator must run (`dart run build_runner build`). It checks every pointcut of the aspect and fails the build on a syntax error, with the aspect, the advice and the position.
- Aspects of a parent context also apply to the beans of its child contexts.
- An aspect turned off by a condition or a profile is simply not registered, and its advice does not apply.

## In Spring (Java)

```java
@Aspect
@Component
@Order(1)
class AuditAspect {
  @Before("execution(* com.example.OrderService.*(..))")
  void audit(JoinPoint joinPoint) {
    log.info(joinPoint.toShortString());
  }
}

@Aspect("perthis(execution(* com.example.Orders.*(..)))")
@Component
@Scope("prototype")
class CallCounter { ... }
```

Differences that matter:

- No `@EnableAspectJAutoProxy`: the context registers the auto-proxy creator itself when an aspect or advisor bean exists.
- `percflow` and `pertypewithin` are not supported.
- Pointcuts use simple type names, not package-qualified ones.

## See also

- [AOP overview](index.md)
- [Advice](advice.md)
- [Pointcuts](pointcut.md)
- [@Component](../beans/component.md)
- [@Bean](../beans/bean.md)
