0
# Core AOP Abstractions
1
2
Fundamental interfaces and classes that form the foundation of Spring's AOP system. These abstractions provide the basic building blocks for implementing aspect-oriented programming, including pointcuts for defining where advice should be applied, advisors that combine advice with pointcuts, and various advice types for different interception strategies.
3
4
## Capabilities
5
6
### Pointcut System
7
8
Core abstraction for defining where advice should be applied, combining class filters and method matchers to precisely target join points.
9
10
```java { .api }
11
public interface Pointcut {
12
/**
13
* Return the ClassFilter for this pointcut.
14
* @return the ClassFilter (never null)
15
*/
16
ClassFilter getClassFilter();
17
18
/**
19
* Return the MethodMatcher for this pointcut.
20
* @return the MethodMatcher (never null)
21
*/
22
MethodMatcher getMethodMatcher();
23
24
/**
25
* Canonical Pointcut instance that always matches.
26
*/
27
Pointcut TRUE = TruePointcut.INSTANCE;
28
}
29
30
public interface ClassFilter {
31
/**
32
* Should the pointcut apply to the given interface or target class?
33
* @param clazz the candidate target class
34
* @return whether the advice should apply to the given target class
35
*/
36
boolean matches(Class<?> clazz);
37
38
/**
39
* Canonical ClassFilter instance that matches all classes.
40
*/
41
ClassFilter TRUE = TrueClassFilter.INSTANCE;
42
}
43
44
public interface MethodMatcher {
45
/**
46
* Perform static checking whether the given method matches.
47
* @param method the candidate method
48
* @param targetClass the target class
49
* @return whether or not this method matches statically
50
*/
51
boolean matches(Method method, Class<?> targetClass);
52
53
/**
54
* Is this MethodMatcher dynamic, that is, must a final call be made on the
55
* {@link #matches(java.lang.reflect.Method, Class, Object[])} method at
56
* runtime even when the 2-arg matches method returns {@code true}?
57
* @return whether or not a runtime match via the 3-arg
58
* {@link #matches(java.lang.reflect.Method, Class, Object[])} method
59
* is required if static matching passed
60
*/
61
boolean isRuntime();
62
63
/**
64
* Check whether there a runtime (dynamic) match for this method,
65
* which must have matched statically.
66
* @param method the candidate method
67
* @param targetClass the target class
68
* @param args arguments to the method
69
* @return whether there's a runtime match
70
* @throws UnsupportedOperationException if matches does not implement
71
* the 3-arg method (i.e. if isRuntime() returns false)
72
*/
73
boolean matches(Method method, Class<?> targetClass, Object... args);
74
75
/**
76
* Canonical MethodMatcher instance that matches all methods.
77
*/
78
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
79
}
80
```
81
82
### Advisor Hierarchy
83
84
Advisors combine advice with applicability information to determine when and where advice should be applied.
85
86
```java { .api }
87
public interface Advisor {
88
/**
89
* Return the advice part of this aspect. An advice may be an
90
* interceptor, a before advice, a throws advice, etc.
91
* @return the advice that should apply if the pointcut matches
92
* @see org.aopalliance.intercept.MethodInterceptor
93
* @see BeforeAdvice
94
* @see ThrowsAdvice
95
* @see AfterReturningAdvice
96
*/
97
Advice getAdvice();
98
99
/**
100
* Return whether this advice is associated with a particular instance
101
* (for example, creating a mixin) or shared with all instances of
102
* the advised class obtained through the same Spring bean factory.
103
* <p><b>Note that this method is not currently used by the framework.</b>
104
* Typical Advisor implementations always return {@code true}.
105
* Use singleton/prototype bean definitions or appropriate programmatic
106
* proxy creation to ensure that Advisors have the correct lifecycle model.
107
* @return whether this advice is associated with a particular target instance
108
*/
109
boolean isPerInstance();
110
111
/**
112
* Common placeholder for an empty {@code Advice} to be preserved when
113
* no advice is applicable (e.g. from a {@code PointcutAdvisor} with a
114
* non-matching {@code Pointcut}).
115
*/
116
Advice EMPTY_ADVICE = new Advice() {};
117
}
118
119
public interface PointcutAdvisor extends Advisor {
120
/**
121
* Get the Pointcut that drives this advisor.
122
*/
123
Pointcut getPointcut();
124
}
125
126
public interface IntroductionAdvisor extends Advisor, IntroductionInfo {
127
/**
128
* Return the filter determining which target classes this introduction
129
* should apply to.
130
* <p>This represents the class part of a pointcut. Note that method
131
* matching doesn't make sense to introductions.
132
* @return the class filter
133
*/
134
ClassFilter getClassFilter();
135
136
/**
137
* Can the advised interfaces be implemented by the introduction advice?
138
* Invoked before adding an IntroductionAdvisor.
139
* @throws IllegalArgumentException if the advised interfaces can't be
140
* implemented by the introduction advice
141
*/
142
void validateInterfaces() throws IllegalArgumentException;
143
}
144
```
145
146
### Advice Type System
147
148
Base interfaces for different types of advice that can be applied at join points.
149
150
```java { .api }
151
public interface BeforeAdvice extends Advice {
152
// Marker interface for before advice
153
}
154
155
public interface AfterAdvice extends Advice {
156
// Marker interface for after advice
157
}
158
159
public interface MethodBeforeAdvice extends BeforeAdvice {
160
/**
161
* Callback before a given method is invoked.
162
* @param method the method being invoked
163
* @param args the arguments to the method
164
* @param target the target of the method invocation. May be {@code null}.
165
* @throws Throwable if this object wishes to abort the call.
166
* Any exception thrown will be returned to the caller if it's
167
* allowed by the method signature. Otherwise the exception
168
* will be wrapped as a runtime exception.
169
*/
170
void before(Method method, Object[] args, Object target) throws Throwable;
171
}
172
173
public interface AfterReturningAdvice extends AfterAdvice {
174
/**
175
* Callback after a given method successfully returns.
176
* @param returnValue the value returned by the method, if any
177
* @param method the method being invoked
178
* @param args the arguments to the method
179
* @param target the target of the method invocation. May be {@code null}.
180
* @throws Throwable if this object wishes to abort the call.
181
* Any exception thrown will be returned to the caller if it's
182
* allowed by the method signature. Otherwise the exception
183
* will be wrapped as a runtime exception.
184
*/
185
void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
186
}
187
188
public interface ThrowsAdvice extends AfterAdvice {
189
// Tag interface for throws advice
190
// Methods must follow pattern:
191
// void afterThrowing([Method, args, target], Exception ex)
192
}
193
```
194
195
### Introduction Support
196
197
Interfaces for implementing introductions (mixins) that add new interfaces to existing objects.
198
199
```java { .api }
200
public interface IntroductionInfo {
201
/**
202
* Return the additional interfaces introduced by this Advisor or Advice.
203
* @return the introduced interfaces
204
*/
205
Class<?>[] getInterfaces();
206
}
207
208
public interface IntroductionInterceptor extends MethodInterceptor, DynamicIntroductionAdvice {
209
// Combined interface for introduction interceptors
210
}
211
212
public interface DynamicIntroductionAdvice extends Advice {
213
/**
214
* Does this introduction advice implement the given interface?
215
* @param intf the interface to check
216
* @return whether the advice implements the specified interface
217
*/
218
boolean implementsInterface(Class<?> intf);
219
}
220
221
public interface IntroductionAwareMethodMatcher extends MethodMatcher {
222
/**
223
* Perform static checking whether the given method matches.
224
* This method is called when an AOP proxy is created, and need not
225
* account for the particular instance. If this method returns false
226
* or if the isRuntime() method returns false, no runtime check
227
* will be made.
228
* @param method the candidate method
229
* @param targetClass the target class
230
* @param hasIntroductions true if the object on whose behalf we are
231
* asking is the subject on one or more introductions; false otherwise
232
* @return whether or not this method matches statically
233
*/
234
boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions);
235
}
236
```
237
238
### Proxy and Target Support
239
240
Core interfaces for working with AOP proxies and target objects.
241
242
```java { .api }
243
public interface TargetClassAware {
244
/**
245
* Return the target class behind the implementing object
246
* (typically a proxy configuration or an actual proxy).
247
* @return the target Class, or {@code null} if not known
248
*/
249
Class<?> getTargetClass();
250
}
251
252
public interface SpringProxy {
253
// Marker interface implemented by all proxies created by Spring's AOP infrastructure
254
}
255
256
public interface RawTargetAccess {
257
// Marker interface that indicates that the annotated method is eligible for
258
// invocation even if the target object is in "raw" mode
259
}
260
261
public interface ProxyMethodInvocation extends MethodInvocation {
262
/**
263
* Return the proxy that this method invocation was made through.
264
* @return the original proxy object
265
*/
266
Object getProxy();
267
268
/**
269
* Create a clone of this object. If cloning is done before {@code proceed()}
270
* is invoked on this object, {@code proceed()} can be invoked once per clone
271
* to invoke the joinpoint (and the rest of the advice chain) more than once.
272
* @return an invocable clone of this invocation.
273
* {@link #proceed()} can be called once per clone.
274
*/
275
MethodInvocation invocableClone();
276
277
/**
278
* Create a clone of this object. If cloning is done before {@code proceed()}
279
* is invoked on this object, {@code proceed()} can be invoked once per clone
280
* to invoke the joinpoint (and the rest of the advice chain) more than once.
281
* @param arguments the arguments that the cloned invocation is supposed to use,
282
* overriding the original arguments
283
* @return an invocable clone of this invocation.
284
* {@link #proceed()} can be called once per clone.
285
*/
286
MethodInvocation invocableClone(Object... arguments);
287
288
/**
289
* Set the arguments to be used on subsequent invocations in the any advice
290
* in this chain.
291
* @param arguments the argument array
292
*/
293
void setArguments(Object... arguments);
294
295
/**
296
* Add the specified user attribute with the given value to this invocation.
297
* <p>Such attributes are not used within the AOP framework itself.
298
* They are just kept as part of the invocation object, for use in
299
* special interceptors.
300
* @param key the name of the attribute
301
* @param value the value of the attribute, or {@code null} to reset it
302
*/
303
void setUserAttribute(String key, Object value);
304
305
/**
306
* Return the value of the specified user attribute.
307
* @param key the name of the attribute
308
* @return the value of the attribute, or {@code null} if not set
309
* @see #setUserAttribute
310
*/
311
Object getUserAttribute(String key);
312
}
313
```
314
315
## Usage Examples
316
317
### Creating Custom Pointcuts
318
319
```java
320
// Name-based pointcut
321
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
322
pointcut.setMappedNames("save*", "update*", "delete*");
323
324
// Custom method matcher
325
MethodMatcher customMatcher = new MethodMatcher() {
326
@Override
327
public boolean matches(Method method, Class<?> targetClass) {
328
return method.isAnnotationPresent(Transactional.class);
329
}
330
331
@Override
332
public boolean isRuntime() {
333
return false;
334
}
335
336
@Override
337
public boolean matches(Method method, Class<?> targetClass, Object... args) {
338
throw new UnsupportedOperationException("Not a runtime matcher");
339
}
340
};
341
342
// Composable pointcut
343
ComposablePointcut composite = new ComposablePointcut()
344
.union(pointcut)
345
.intersection(Pointcuts.forAnnotation(Service.class));
346
```
347
348
### Custom Advice Implementation
349
350
```java
351
public class LoggingBeforeAdvice implements MethodBeforeAdvice {
352
private static final Logger logger = LoggerFactory.getLogger(LoggingBeforeAdvice.class);
353
354
@Override
355
public void before(Method method, Object[] args, Object target) throws Throwable {
356
logger.info("Calling method: {} on target: {}",
357
method.getName(), target.getClass().getSimpleName());
358
}
359
}
360
361
public class CachingAfterReturningAdvice implements AfterReturningAdvice {
362
private final Map<String, Object> cache = new ConcurrentHashMap<>();
363
364
@Override
365
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
366
if (method.isAnnotationPresent(Cacheable.class)) {
367
String key = generateCacheKey(method, args);
368
cache.put(key, returnValue);
369
}
370
}
371
372
private String generateCacheKey(Method method, Object[] args) {
373
return method.getName() + Arrays.toString(args);
374
}
375
}
376
```
377
378
### AOP Utility Methods
379
380
Static utility methods for working with AOP proxies, target classes, and method detection.
381
382
```java { .api }
383
public abstract class AopUtils {
384
/**
385
* Check whether the given object is a AOP proxy.
386
* @param object the object to check
387
* @return whether the object is a AOP proxy
388
*/
389
public static boolean isAopProxy(@Nullable Object object);
390
391
/**
392
* Check whether the given object is a JDK dynamic proxy.
393
* @param object the object to check
394
* @return whether the object is a JDK dynamic proxy
395
*/
396
public static boolean isJdkDynamicProxy(@Nullable Object object);
397
398
/**
399
* Check whether the given object is a CGLIB proxy.
400
* @param object the object to check
401
* @return whether the object is a CGLIB proxy
402
*/
403
public static boolean isCglibProxy(@Nullable Object object);
404
405
/**
406
* Determine the target class of the given bean instance which might be an AOP proxy.
407
* @param candidate the instance to check (might be an AOP proxy)
408
* @return the target class (or the plain class of the given object as fallback)
409
*/
410
public static Class<?> getTargetClass(Object candidate);
411
412
/**
413
* Determine whether the given method is an "equals" method.
414
* @param method the method to check
415
* @return whether the method is an "equals" method
416
*/
417
public static boolean isEqualsMethod(@Nullable Method method);
418
419
/**
420
* Determine whether the given method is a "hashCode" method.
421
* @param method the method to check
422
* @return whether the method is a "hashCode" method
423
*/
424
public static boolean isHashCodeMethod(@Nullable Method method);
425
426
/**
427
* Determine whether the given method is a "toString" method.
428
* @param method the method to check
429
* @return whether the method is a "toString" method
430
*/
431
public static boolean isToStringMethod(@Nullable Method method);
432
433
/**
434
* Can the given pointcut apply at all on the given class?
435
* @param pc the static or dynamic pointcut to check
436
* @param targetClass the class to test
437
* @return whether the pointcut can apply on any method
438
*/
439
public static boolean canApply(Pointcut pc, Class<?> targetClass);
440
441
/**
442
* Can the given advisor apply at all on the given class?
443
* @param advisor the advisor to check
444
* @param targetClass class we're testing
445
* @return whether the pointcut can apply on any method
446
*/
447
public static boolean canApply(Advisor advisor, Class<?> targetClass);
448
}
449
```