0
# AspectJ Integration
1
2
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.
3
4
## Capabilities
5
6
### AspectJ Expression Pointcuts
7
8
Pointcut implementation using AspectJ's expression language for sophisticated join point matching.
9
10
```java { .api }
11
public class AspectJExpressionPointcut implements ClassFilter, MethodMatcher, Pointcut, BeanFactoryAware, ParameterNameDiscoverer {
12
/**
13
* Set the AspectJ expression.
14
* @param expression the AspectJ expression
15
*/
16
public void setExpression(String expression);
17
18
/**
19
* Return the AspectJ expression.
20
*/
21
public String getExpression();
22
23
/**
24
* Set the parameter types, if they are known.
25
* @param types the parameter types
26
*/
27
public void setParameterTypes(Class<?>... types);
28
29
/**
30
* Set the parameter names, if they are known.
31
* @param names the parameter names
32
*/
33
public void setParameterNames(String... names);
34
35
/**
36
* Return the parameter names, if they are known, or {@code null} if not.
37
*/
38
public String[] getParameterNames();
39
40
/**
41
* Check whether this pointcut is ready to match,
42
* i.e. whether it has been configured with a complete expression.
43
*/
44
public boolean isReady();
45
46
// ClassFilter implementation
47
@Override
48
public boolean matches(Class<?> clazz);
49
50
// MethodMatcher implementation
51
@Override
52
public boolean matches(Method method, Class<?> targetClass);
53
54
@Override
55
public boolean isRuntime();
56
57
@Override
58
public boolean matches(Method method, Class<?> targetClass, Object... args);
59
60
// Pointcut implementation
61
@Override
62
public ClassFilter getClassFilter();
63
64
@Override
65
public MethodMatcher getMethodMatcher();
66
}
67
68
public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdvisor implements BeanFactoryAware {
69
/**
70
* Create a new AspectJExpressionPointcutAdvisor.
71
*/
72
public AspectJExpressionPointcutAdvisor();
73
74
/**
75
* Create a new AspectJExpressionPointcutAdvisor.
76
* @param advice the advice to use
77
* @param expression the AspectJ expression
78
*/
79
public AspectJExpressionPointcutAdvisor(Advice advice, String expression);
80
81
/**
82
* Set the AspectJ expression.
83
* @param expression the AspectJ expression
84
*/
85
public void setExpression(String expression);
86
87
/**
88
* Return the AspectJ expression.
89
*/
90
public String getExpression();
91
92
/**
93
* Set the parameter names for the pointcut.
94
* @param parameterNames the parameter names
95
*/
96
public void setParameterNames(String... parameterNames);
97
98
/**
99
* Set the parameter types for the pointcut.
100
* @param parameterTypes the parameter types
101
*/
102
public void setParameterTypes(Class<?>... parameterTypes);
103
104
@Override
105
public Pointcut getPointcut();
106
}
107
```
108
109
### AspectJ Advice Types
110
111
Spring AOP advice implementations that wrap AspectJ-style advice methods with precedence information.
112
113
```java { .api }
114
public class AspectJMethodBeforeAdvice implements MethodBeforeAdvice, AspectJPrecedenceInformation {
115
/**
116
* Create a new AspectJMethodBeforeAdvice for the given advice method.
117
* @param adviceMethod the AspectJ-style advice method
118
* @param pointcut the AspectJ expression pointcut
119
* @param aspectInstanceFactory the factory for aspect instances
120
*/
121
public AspectJMethodBeforeAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory);
122
123
@Override
124
public void before(Method method, Object[] args, Object target) throws Throwable;
125
126
// AspectJPrecedenceInformation implementation
127
@Override
128
public String getAspectName();
129
130
@Override
131
public int getDeclarationOrder();
132
133
@Override
134
public boolean isBeforeAdvice();
135
136
@Override
137
public boolean isAfterAdvice();
138
}
139
140
public class AspectJAfterAdvice implements MethodInterceptor, AfterAdvice, AspectJPrecedenceInformation {
141
/**
142
* Create a new AspectJAfterAdvice for the given advice method.
143
* @param adviceMethod the AspectJ-style advice method
144
* @param pointcut the AspectJ expression pointcut
145
* @param aspectInstanceFactory the factory for aspect instances
146
*/
147
public AspectJAfterAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory);
148
149
@Override
150
public Object invoke(MethodInvocation mi) throws Throwable;
151
152
// AspectJPrecedenceInformation implementation
153
@Override
154
public String getAspectName();
155
156
@Override
157
public int getDeclarationOrder();
158
159
@Override
160
public boolean isBeforeAdvice();
161
162
@Override
163
public boolean isAfterAdvice();
164
}
165
166
public class AspectJAfterReturningAdvice implements AfterReturningAdvice, AspectJPrecedenceInformation {
167
/**
168
* Create a new AspectJAfterReturningAdvice for the given advice method.
169
* @param adviceMethod the AspectJ-style advice method
170
* @param pointcut the AspectJ expression pointcut
171
* @param aspectInstanceFactory the factory for aspect instances
172
*/
173
public AspectJAfterReturningAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory);
174
175
/**
176
* Set the name of the parameter in the advice method that receives the return value.
177
* @param name parameter name
178
*/
179
public void setReturningName(String name);
180
181
@Override
182
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
183
184
// AspectJPrecedenceInformation implementation methods...
185
}
186
187
public class AspectJAfterThrowingAdvice implements MethodInterceptor, AfterAdvice, AspectJPrecedenceInformation {
188
/**
189
* Create a new AspectJAfterThrowingAdvice for the given advice method.
190
* @param adviceMethod the AspectJ-style advice method
191
* @param pointcut the AspectJ expression pointcut
192
* @param aspectInstanceFactory the factory for aspect instances
193
*/
194
public AspectJAfterThrowingAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory);
195
196
/**
197
* Set the name of the parameter in the advice method that receives the thrown exception.
198
* @param name parameter name
199
*/
200
public void setThrowingName(String name);
201
202
@Override
203
public Object invoke(MethodInvocation mi) throws Throwable;
204
205
// AspectJPrecedenceInformation implementation methods...
206
}
207
208
public class AspectJAroundAdvice implements MethodInterceptor, AspectJPrecedenceInformation {
209
/**
210
* Create a new AspectJAroundAdvice for the given advice method.
211
* @param adviceMethod the AspectJ-style advice method
212
* @param pointcut the AspectJ expression pointcut
213
* @param aspectInstanceFactory the factory for aspect instances
214
*/
215
public AspectJAroundAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory);
216
217
@Override
218
public Object invoke(MethodInvocation mi) throws Throwable;
219
220
// AspectJPrecedenceInformation implementation methods...
221
}
222
```
223
224
### AspectJ Proxy Factory
225
226
Specialized proxy factory for creating proxies with AspectJ aspects.
227
228
```java { .api }
229
public class AspectJProxyFactory extends ProxyCreatorSupport {
230
/**
231
* Create a new AspectJProxyFactory.
232
*/
233
public AspectJProxyFactory();
234
235
/**
236
* Create a new AspectJProxyFactory.
237
* <p>Will proxy all interfaces that the given target implements.
238
* @param target the target object to be proxied
239
*/
240
public AspectJProxyFactory(Object target);
241
242
/**
243
* Add the supplied aspect instance to the chain. The type of the aspect instance
244
* supplied must be a singleton aspect. True singleton lifecycle is not honoured when
245
* using this method - the caller is responsible for managing the lifecycle of any
246
* aspects added in this way.
247
* @param aspectInstance the AspectJ aspect instance
248
*/
249
public void addAspect(Object aspectInstance);
250
251
/**
252
* Add an aspect of the supplied type to the end of the advice chain.
253
* @param aspectClass the AspectJ aspect class
254
*/
255
public void addAspect(Class<?> aspectClass);
256
257
/**
258
* Create a proxy according to this factory's settings.
259
* @return the proxy object
260
*/
261
@SuppressWarnings("unchecked")
262
public <T> T getProxy();
263
264
/**
265
* Create a proxy according to this factory's settings.
266
* @param classLoader the class loader to create the proxy with
267
* @return the proxy object
268
*/
269
@SuppressWarnings("unchecked")
270
public <T> T getProxy(ClassLoader classLoader);
271
}
272
```
273
274
### Aspect Instance Factories
275
276
Factories for managing aspect instances and their metadata.
277
278
```java { .api }
279
public interface AspectInstanceFactory {
280
/**
281
* Create an instance of this factory's aspect.
282
* @return the aspect instance (never {@code null})
283
*/
284
Object getAspectInstance();
285
286
/**
287
* Expose the aspect class loader that this factory uses.
288
* @return the aspect class loader (or {@code null} for the bootstrap loader)
289
* @see org.springframework.util.ClassUtils#getDefaultClassLoader()
290
*/
291
ClassLoader getAspectClassLoader();
292
293
/**
294
* Return the order value of this object, with a higher value meaning greater
295
* precedence. Normally starting with 0, with {@code Integer.MAX_VALUE}
296
* indicating the greatest precedence (corresponding to the lowest priority).
297
* <p>Same order values will result in arbitrary sort positions for the
298
* affected objects.
299
* @return the order value
300
* @see #HIGHEST_PRECEDENCE
301
* @see #LOWEST_PRECEDENCE
302
*/
303
int getOrder();
304
}
305
306
public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactory {
307
/**
308
* Return the AspectJ AspectMetadata for this factory's aspect.
309
* @return the aspect metadata
310
*/
311
AspectMetadata getAspectMetadata();
312
313
/**
314
* Return the best possible creation mutex for this factory:
315
* that is, an object that should be synchronized on for creation
316
* of the aspect instance.
317
* @return the mutex object (may be {@code null} for no mutex to use)
318
*/
319
Object getAspectCreationMutex();
320
}
321
322
public class SimpleAspectInstanceFactory implements AspectInstanceFactory {
323
/**
324
* Create a new SimpleAspectInstanceFactory for the given aspect class.
325
* @param aspectClass the aspect class
326
*/
327
public SimpleAspectInstanceFactory(Class<?> aspectClass);
328
329
@Override
330
public final Object getAspectInstance();
331
332
@Override
333
public ClassLoader getAspectClassLoader();
334
335
@Override
336
public int getOrder();
337
}
338
339
public class SingletonAspectInstanceFactory implements AspectInstanceFactory {
340
/**
341
* Create a new SingletonAspectInstanceFactory for the given aspect.
342
* @param aspectInstance the singleton aspect instance
343
*/
344
public SingletonAspectInstanceFactory(Object aspectInstance);
345
346
@Override
347
public final Object getAspectInstance();
348
349
@Override
350
public ClassLoader getAspectClassLoader();
351
352
@Override
353
public int getOrder();
354
}
355
356
public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInstanceFactory, BeanFactoryAware {
357
/**
358
* Create a BeanFactoryAspectInstanceFactory. AspectJ will be called to
359
* introspect to create AJType metadata using the type returned for the
360
* given bean name from the BeanFactory.
361
* @param beanFactory the BeanFactory to obtain instance(s) from
362
* @param beanName the name of the bean
363
*/
364
public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String beanName);
365
366
/**
367
* Set the name of the aspect bean. This is only used for tracing purposes,
368
* but can help debugging.
369
* @param aspectName the name to use. If not specified the bean name is used.
370
*/
371
public void setAspectName(String aspectName);
372
373
@Override
374
public Object getAspectInstance();
375
376
@Override
377
public ClassLoader getAspectClassLoader();
378
379
@Override
380
public AspectMetadata getAspectMetadata();
381
382
@Override
383
public Object getAspectCreationMutex();
384
385
@Override
386
public int getOrder();
387
}
388
```
389
390
### AspectJ Metadata Support
391
392
Classes for managing AspectJ aspect metadata and precedence information.
393
394
```java { .api }
395
public class AspectMetadata implements Serializable {
396
/**
397
* Create a new AspectMetadata instance for the given aspect class.
398
* @param aspectClass the aspect class
399
* @param aspectName the name of the aspect
400
*/
401
public AspectMetadata(Class<?> aspectClass, String aspectName);
402
403
/**
404
* Return the AspectJ type representation of this aspect class.
405
*/
406
public AjType<?> getAjType();
407
408
/**
409
* Return the aspect class.
410
*/
411
public Class<?> getAspectClass();
412
413
/**
414
* Return the aspect name.
415
*/
416
public String getAspectName();
417
418
/**
419
* Return the per clause pointcut, or {@code Pointcut.TRUE} if there is no per clause.
420
* <p>NB: This returns the value of the per clause on the aspect.
421
* If this aspect was configured as a Spring bean using BeanFactory semantics,
422
* then this will not be the same as BeanFactory semantics.
423
* In such cases {@code BeanFactoryAspectInstanceFactory} should be used.
424
*/
425
public Pointcut getPerClausePointcut();
426
427
/**
428
* Return whether the aspect is defined as "perthis" or "pertarget".
429
*/
430
public boolean isPerThisOrPerTarget();
431
432
/**
433
* Return whether the aspect is defined as "pertypewithin".
434
*/
435
public boolean isPerTypeWithin();
436
437
/**
438
* Return whether the aspect needs to be lazily instantiated.
439
*/
440
public boolean isLazilyInstantiated();
441
}
442
443
public interface AspectJPrecedenceInformation {
444
/**
445
* Return the name of the aspect (bean) in which the advice was declared.
446
*/
447
String getAspectName();
448
449
/**
450
* Return the declaration order of the advice member within the aspect.
451
*/
452
int getDeclarationOrder();
453
454
/**
455
* Return whether this is a before advice.
456
*/
457
boolean isBeforeAdvice();
458
459
/**
460
* Return whether this is an after advice.
461
*/
462
boolean isAfterAdvice();
463
}
464
```
465
466
### @AspectJ Annotation Support
467
468
Support for processing @AspectJ annotated classes and creating advisors from them.
469
470
```java { .api }
471
public interface AspectJAdvisorFactory {
472
/**
473
* Determine whether or not the given class is an aspect, as reported
474
* by AspectJ's {@link org.aspectj.lang.reflect.AjTypeSystem}.
475
* <p>Will simply return {@code false} if the supposed aspect is
476
* not an AspectJ aspect at all.
477
* @param clazz the supposed annotation-style AspectJ aspect class
478
* @return whether or not this class is recognized by AspectJ as an aspect class
479
*/
480
boolean isAspect(Class<?> clazz);
481
482
/**
483
* Is the given class a valid AspectJ aspect class?
484
* @param aspectClass the aspect class to validate
485
* @throws AopConfigException if the class is an invalid aspect
486
* (which can never be legal)
487
* @throws NotAnAtAspectException if the class is not an aspect at all
488
* (which may or may not be legal, depending on the context)
489
*/
490
void validate(Class<?> aspectClass) throws AopConfigException;
491
492
/**
493
* Build Spring AOP Advisors for all annotated At-AspectJ methods
494
* on the specified aspect instance.
495
* @param aspectInstanceFactory the aspect instance factory
496
* (not the aspect instance itself in order to avoid eager instantiation)
497
* @return a list of advisors for this class
498
*/
499
List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory);
500
501
/**
502
* Build a Spring AOP Advisor for the given AspectJ advice method.
503
* @param candidateAdviceMethod the candidate advice method
504
* @param aspectInstanceFactory the aspect instance factory
505
* @param declarationOrder the declaration order within the aspect
506
* @param aspectName the name of the aspect
507
* @return {@code null} if the method is not an AspectJ advice method
508
* or if it is a pointcut that will be used by other advice but will not
509
* create a Spring advice in its own right
510
*/
511
Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
512
int declarationOrder, String aspectName);
513
}
514
515
public class ReflectiveAspectJAdvisorFactory implements AspectJAdvisorFactory, Serializable {
516
@Override
517
public boolean isAspect(Class<?> clazz);
518
519
@Override
520
public void validate(Class<?> aspectClass) throws AopConfigException;
521
522
@Override
523
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory);
524
525
@Override
526
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
527
int declarationOrder, String aspectName);
528
}
529
```
530
531
### Support Classes
532
533
Additional support classes for AspectJ integration.
534
535
```java { .api }
536
public class TypePatternClassFilter implements ClassFilter {
537
/**
538
* Create a new TypePatternClassFilter for the given AspectJ type pattern.
539
* @param typePattern the AspectJ type pattern
540
*/
541
public TypePatternClassFilter(String typePattern);
542
543
@Override
544
public boolean matches(Class<?> clazz);
545
}
546
547
public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint, JoinPoint.StaticPart {
548
/**
549
* Create a new MethodInvocationProceedingJoinPoint, wrapping the given
550
* Spring ProxyMethodInvocation object.
551
* @param methodInvocation the Spring ProxyMethodInvocation object
552
*/
553
public MethodInvocationProceedingJoinPoint(ProxyMethodInvocation methodInvocation);
554
555
@Override
556
public Object proceed() throws Throwable;
557
558
@Override
559
public Object proceed(Object[] args) throws Throwable;
560
561
// JoinPoint implementation methods...
562
@Override
563
public String toShortString();
564
565
@Override
566
public String toLongString();
567
568
@Override
569
public Object getThis();
570
571
@Override
572
public Object getTarget();
573
574
@Override
575
public Object[] getArgs();
576
577
@Override
578
public Signature getSignature();
579
580
@Override
581
public SourceLocation getSourceLocation();
582
583
@Override
584
public String getKind();
585
586
@Override
587
public JoinPoint.StaticPart getStaticPart();
588
}
589
```
590
591
## Usage Examples
592
593
### AspectJ Expression Pointcuts
594
595
```java
596
// Create pointcut with AspectJ expression
597
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
598
pointcut.setExpression("execution(* com.example.service.*Service.*(..))");
599
600
// Use in advisor
601
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
602
advisor.setExpression("execution(* com.example.service.*Service.*(..))");
603
advisor.setAdvice(new LoggingInterceptor());
604
605
// Complex expressions
606
pointcut.setExpression(
607
"execution(public * com.example.service.*Service.*(..)) && " +
608
"@annotation(org.springframework.transaction.annotation.Transactional)"
609
);
610
```
611
612
### Using AspectJ Proxy Factory
613
614
```java
615
// Create AspectJ-based proxy
616
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
617
618
// Add aspect instance
619
@Aspect
620
class LoggingAspect {
621
@Around("execution(* com.example.service.*.*(..))")
622
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
623
long start = System.currentTimeMillis();
624
Object result = joinPoint.proceed();
625
long executionTime = System.currentTimeMillis() - start;
626
System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");
627
return result;
628
}
629
}
630
631
factory.addAspect(new LoggingAspect());
632
MyService proxy = factory.getProxy();
633
634
// Or add aspect class
635
factory.addAspect(LoggingAspect.class);
636
```
637
638
### Creating Custom AspectJ Advice
639
640
```java
641
public class CustomAspectJAdvice implements MethodInterceptor, AspectJPrecedenceInformation {
642
private final String aspectName;
643
private final int declarationOrder;
644
645
public CustomAspectJAdvice(String aspectName, int declarationOrder) {
646
this.aspectName = aspectName;
647
this.declarationOrder = declarationOrder;
648
}
649
650
@Override
651
public Object invoke(MethodInvocation invocation) throws Throwable {
652
// Custom advice logic here
653
System.out.println("Custom AspectJ advice executing for: " + invocation.getMethod().getName());
654
return invocation.proceed();
655
}
656
657
@Override
658
public String getAspectName() {
659
return aspectName;
660
}
661
662
@Override
663
public int getDeclarationOrder() {
664
return declarationOrder;
665
}
666
667
@Override
668
public boolean isBeforeAdvice() {
669
return false;
670
}
671
672
@Override
673
public boolean isAfterAdvice() {
674
return true;
675
}
676
}
677
```
678
679
### Working with Aspect Metadata
680
681
```java
682
// Examine aspect metadata
683
Class<?> aspectClass = MyAspect.class;
684
AspectMetadata metadata = new AspectMetadata(aspectClass, "myAspect");
685
686
System.out.println("Aspect name: " + metadata.getAspectName());
687
System.out.println("Aspect class: " + metadata.getAspectClass().getName());
688
System.out.println("Is per-this or per-target: " + metadata.isPerThisOrPerTarget());
689
System.out.println("Requires lazy instantiation: " + metadata.isLazilyInstantiated());
690
691
// Get per-clause pointcut
692
Pointcut perClause = metadata.getPerClausePointcut();
693
if (perClause != Pointcut.TRUE) {
694
System.out.println("Has per-clause pointcut");
695
}
696
```