0
# Proxy Creation and Management
1
2
ProxyFactory and related classes provide programmatic creation of AOP proxies with comprehensive configuration options for different proxy strategies, target source management, and advisor chains. This system enables flexible runtime proxy creation for both interface-based and class-based proxying scenarios.
3
4
## Capabilities
5
6
### ProxyFactory - Main Entry Point
7
8
The primary class for creating AOP proxies programmatically, providing fluent configuration and multiple creation strategies.
9
10
```java { .api }
11
public class ProxyFactory extends ProxyCreatorSupport {
12
/**
13
* Create a new ProxyFactory.
14
*/
15
public ProxyFactory();
16
17
/**
18
* Create a new ProxyFactory.
19
* Will proxy all interfaces that the given target implements.
20
* @param target the target object to be proxied
21
*/
22
public ProxyFactory(Object target);
23
24
/**
25
* Create a new ProxyFactory.
26
* No target, only interfaces. Must add interceptors.
27
* @param proxyInterfaces the interfaces that the proxy should implement
28
*/
29
public ProxyFactory(Class<?>... proxyInterfaces);
30
31
/**
32
* Create a new ProxyFactory for the given interface and interceptor.
33
* Convenience method for creating a proxy for a single interceptor,
34
* assuming that the interceptor handles all calls itself rather than
35
* delegating to a target, like in the case of remoting proxies.
36
* @param proxyInterface the interface that the proxy should implement
37
* @param interceptor the interceptor that the proxy should invoke
38
*/
39
public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor);
40
41
/**
42
* Create a ProxyFactory for the specified {@code TargetSource}.
43
* @param proxyInterface the interface that the proxy should implement
44
* @param targetSource the source for the target object to be proxied
45
*/
46
public ProxyFactory(Class<?> proxyInterface, TargetSource targetSource);
47
48
/**
49
* Create a proxy according to this factory's settings.
50
* <p>Can be called repeatedly. Effect will vary if we've added
51
* or removed interfaces. Can add and remove interceptors.
52
* <p>Uses the default class loader: usually, the thread context class loader
53
* (if necessary for proxy creation).
54
* @return the proxy object
55
*/
56
public Object getProxy();
57
58
/**
59
* Create a proxy according to this factory's settings.
60
* <p>Uses the given class loader (if necessary for proxy creation).
61
* @param classLoader the class loader to create the proxy with
62
* (or {@code null} for the low-level proxy facility's default)
63
* @return the proxy object
64
*/
65
public Object getProxy(ClassLoader classLoader);
66
67
/**
68
* Determine the proxy class according to this factory's settings.
69
* <p>Uses the default class loader: usually, the thread context class loader
70
* (if necessary for proxy creation).
71
* @return the proxy class
72
*/
73
public Class<?> getProxyClass();
74
75
/**
76
* Determine the proxy class according to this factory's settings.
77
* <p>Uses the given class loader (if necessary for proxy creation).
78
* @param classLoader the class loader to create the proxy with
79
* (or {@code null} for the low-level proxy facility's default)
80
* @return the proxy class
81
*/
82
public Class<?> getProxyClass(ClassLoader classLoader);
83
84
// Static convenience methods
85
86
/**
87
* Create a proxy for the specified {@code TargetSource}.
88
* @param targetSource the source for the target object to be proxied
89
* @return the proxy object
90
*/
91
public static Object getProxy(TargetSource targetSource);
92
93
/**
94
* Create a proxy for the specified {@code TargetSource},
95
* using the given class loader.
96
* @param targetSource the source for the target object to be proxied
97
* @param classLoader the class loader to use for the proxy
98
* @return the proxy object
99
*/
100
public static Object getProxy(TargetSource targetSource, ClassLoader classLoader);
101
102
/**
103
* Create a proxy for the given interface and interceptor.
104
* @param proxyInterface the interface that the proxy should implement
105
* @param interceptor the interceptor that the proxy should invoke
106
* @return the proxy object
107
*/
108
public static <T> T getProxy(Class<T> proxyInterface, Interceptor interceptor);
109
110
/**
111
* Create a proxy for the specified {@code TargetSource} that extends
112
* the target class of the {@code TargetSource}.
113
* @param proxyInterface the interface that the proxy should implement
114
* @param targetSource the {@code TargetSource} the proxy should delegate to
115
* @return the proxy object
116
*/
117
public static <T> T getProxy(Class<T> proxyInterface, TargetSource targetSource);
118
}
119
```
120
121
### ProxyCreatorSupport - Base Class
122
123
Base class for proxy factories, providing common functionality for AOP proxy creation and configuration.
124
125
```java { .api }
126
public class ProxyCreatorSupport extends AdvisedSupport {
127
/**
128
* Set the AopProxyFactory to use.
129
* <p>Default is {@link DefaultAopProxyFactory}, creating either a CGLIB proxy
130
* or a JDK dynamic proxy.
131
* @param aopProxyFactory the AOP proxy factory to use
132
*/
133
public void setAopProxyFactory(AopProxyFactory aopProxyFactory);
134
135
/**
136
* Return the AopProxyFactory that this ProxyConfig uses.
137
*/
138
public AopProxyFactory getAopProxyFactory();
139
140
/**
141
* Call this method on a new instance created by the no-arg constructor
142
* to create an independent copy of the configuration from the given object.
143
* @param other the AdvisedSupport object to copy configuration from
144
*/
145
public void copyConfigurationFrom(AdvisedSupport other);
146
147
/**
148
* Create an AOP proxy for this configuration.
149
* @return the AOP proxy for this configuration
150
* @throws AopConfigException if the configuration is invalid
151
*/
152
protected final synchronized AopProxy createAopProxy();
153
154
/**
155
* Copy configuration from the other config object.
156
* @param other configuration to copy from
157
*/
158
protected void copyConfigurationFrom(AdvisedSupport other, TargetSource targetSource, List<Advisor> advisors);
159
}
160
```
161
162
### AOP Proxy Factory System
163
164
Factory interfaces and implementations for creating different types of AOP proxies.
165
166
```java { .api }
167
public interface AopProxyFactory {
168
/**
169
* Create an {@link AopProxy} for the given AOP configuration.
170
* @param config the AOP configuration in the form of an
171
* AdvisedSupport object
172
* @return the corresponding AOP proxy
173
* @throws AopConfigException if the configuration is invalid
174
*/
175
AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;
176
}
177
178
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
179
@Override
180
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;
181
}
182
183
public interface AopProxy {
184
/**
185
* Create a new proxy object.
186
* <p>Uses AopProxy's default class loader (if necessary for proxy creation):
187
* usually, the thread context class loader.
188
* @return the new proxy object (never {@code null})
189
* @see Thread#getContextClassLoader()
190
*/
191
Object getProxy();
192
193
/**
194
* Create a new proxy object.
195
* <p>Uses the given class loader (if necessary for proxy creation).
196
* {@code null} will simply be passed down and thus lead to the low-level
197
* proxy facility's default, which is usually different from the default
198
* chosen by the AopProxy implementation's {@link #getProxy()} method.
199
* @param classLoader the class loader to create the proxy with
200
* (or {@code null} for the low-level proxy facility's default)
201
* @return the new proxy object (never {@code null})
202
*/
203
Object getProxy(ClassLoader classLoader);
204
205
/**
206
* Return the proxy class, as opposed to the proxy instance.
207
* <p>This is essentially equivalent to {@code getProxy().getClass()}
208
* but more efficient (no proxy instantiation required).
209
* @param classLoader the class loader to determine the proxy class for
210
* (may be {@code null} to prioritize the AopProxy implementation's
211
* chosen default class loader)
212
* @return the proxy class (never {@code null})
213
*/
214
Class<?> getProxyClass(ClassLoader classLoader);
215
}
216
```
217
218
### Proxy Configuration Support
219
220
Configuration classes and interfaces for managing AOP proxy settings.
221
222
```java { .api }
223
public class ProxyConfig implements Serializable {
224
/**
225
* Set whether to proxy the target class directly, instead of just proxying
226
* specific interfaces. Default is "false".
227
* <p>Set this to "true" to force proxying for the TargetSource's exposed
228
* target class. If that target class is an interface, a JDK proxy will be
229
* created for the given interface. If that target class is any other class,
230
* a CGLIB proxy will be created for the given class.
231
* @param proxyTargetClass whether to proxy the target class directly as well
232
*/
233
public void setProxyTargetClass(boolean proxyTargetClass);
234
235
/**
236
* Return whether the proxy should be cast to advised.
237
*/
238
public boolean isProxyTargetClass();
239
240
/**
241
* Set whether proxies should perform aggressive optimizations.
242
* The exact meaning of "aggressive optimizations" will differ
243
* between proxies, but there is usually some tradeoff.
244
* Default is "false".
245
* @param optimize whether to apply aggressive optimizations
246
*/
247
public void setOptimize(boolean optimize);
248
249
/**
250
* Return whether proxies should perform aggressive optimizations.
251
*/
252
public boolean isOptimize();
253
254
/**
255
* Set whether this config should be frozen.
256
* <p>When a config is frozen, no advice changes can be made. This is
257
* useful for optimization, and useful when we don't want callers to
258
* be able to manipulate configuration after casting to Advised.
259
* @param frozen whether configuration should be frozen
260
*/
261
public void setFrozen(boolean frozen);
262
263
/**
264
* Return whether the config is frozen, and no advice changes can be made.
265
*/
266
public boolean isFrozen();
267
268
/**
269
* Set whether the proxy created by this configuration should be exposed
270
* via the {@link AopContext} so that it can be accessed by the target.
271
* <p>Default is "false", meaning that no guarantees are made that the target
272
* will be able to access the proxy. If this is set to "true", the proxy
273
* will be accessible via {@link AopContext#currentProxy()}, provided that
274
* the AopContext is configured to hold it.
275
* @param exposeProxy whether to expose the proxy in the AopContext
276
*/
277
public void setExposeProxy(boolean exposeProxy);
278
279
/**
280
* Return whether the factory should expose the proxy.
281
*/
282
public boolean isExposeProxy();
283
284
/**
285
* Set whether this proxy configuration is pre-filtered so that it only
286
* contains applicable advisors (matching this proxy's target class).
287
* <p>Default is "false". Set this to "true" if the advisors have been
288
* pre-filtered already, meaning that the ClassFilter check can be skipped
289
* when building the actual advisor chain for proxy invocations.
290
* @param preFiltered whether the proxy is pre-filtered
291
* @see ClassFilter
292
*/
293
public void setPreFiltered(boolean preFiltered);
294
295
/**
296
* Return whether this proxy configuration is pre-filtered so that it only
297
* contains applicable advisors (matching this proxy's target class).
298
*/
299
public boolean isPreFiltered();
300
}
301
302
public interface Advised extends TargetClassAware {
303
/**
304
* Return whether the Advised configuration is frozen,
305
* in which case no advice changes can be made.
306
*/
307
boolean isFrozen();
308
309
/**
310
* Are we proxying the full target class instead of specified interfaces?
311
*/
312
boolean isProxyTargetClass();
313
314
/**
315
* Return the interfaces proxied by the AOP proxy.
316
* <p>Will not include the target class, which may also be proxied.
317
*/
318
Class<?>[] getProxiedInterfaces();
319
320
/**
321
* Determine whether the given interface is proxied.
322
* @param intf the interface to check
323
*/
324
boolean isInterfaceProxied(Class<?> intf);
325
326
/**
327
* Change the {@code TargetSource} used by this {@code Advised} object.
328
* Only works if the configuration isn't {@linkplain #isFrozen frozen}.
329
* @param targetSource new TargetSource to use
330
*/
331
void setTargetSource(TargetSource targetSource);
332
333
/**
334
* Return the {@code TargetSource} used by this {@code Advised} object.
335
*/
336
TargetSource getTargetSource();
337
338
/**
339
* Set whether the proxy should be exposed by the AOP framework as a
340
* {@link ThreadLocal} for retrieval via the {@link AopContext} class.
341
* <p>It can be necessary to expose proxy if an advised object needs
342
* to call another advised method on itself. (If it uses {@code this},
343
* the call will not be advised).
344
* <p>Default is "false", for optimal performance.
345
*/
346
void setExposeProxy(boolean exposeProxy);
347
348
/**
349
* Return whether the factory should expose the proxy as a ThreadLocal
350
* to be retrievable via the AopContext class. This is particularly
351
* useful if an advised object needs to call another advised method on itself.
352
*/
353
boolean isExposeProxy();
354
355
/**
356
* Set whether this proxy configuration is pre-filtered so that it only
357
* contains applicable advisors (matching this proxy's target class).
358
* <p>Default is "false". Set this to "true" if the advisors have been
359
* pre-filtered already, meaning that the ClassFilter check can be skipped
360
* when building the actual advisor chain for proxy invocations.
361
* @param preFiltered whether the proxy is pre-filtered
362
*/
363
void setPreFiltered(boolean preFiltered);
364
365
/**
366
* Return whether this proxy configuration is pre-filtered so that it only
367
* contains applicable advisors (matching this proxy's target class).
368
*/
369
boolean isPreFiltered();
370
371
/**
372
* Return the advisors applying to this proxy.
373
* @return a list of Advisors applying to this proxy (never {@code null})
374
*/
375
Advisor[] getAdvisors();
376
377
/**
378
* Add an advisor at the end of the advisor chain.
379
* <p>The Advisor may be an {@link org.springframework.aop.IntroductionAdvisor},
380
* in which case the advised interfaces will be those supported by the advisor.
381
* @param advisor the advisor to add to the end of the chain
382
* @throws AopConfigException in case of invalid advice
383
*/
384
void addAdvisor(Advisor advisor) throws AopConfigException;
385
386
/**
387
* Add an Advisor at the specified position in the chain.
388
* @param pos position in chain (0 is head). Must be valid.
389
* @param advisor advisor to add at the specified position in the chain
390
* @throws AopConfigException in case of invalid advice
391
*/
392
void addAdvisor(int pos, Advisor advisor) throws AopConfigException;
393
394
/**
395
* Remove the given advisor.
396
* @param advisor the advisor to remove
397
* @return {@code true} if the advisor was removed; {@code false}
398
* if the advisor was not found in the list
399
*/
400
boolean removeAdvisor(Advisor advisor);
401
402
/**
403
* Remove the advisor at the given index.
404
* @param index the index of advisor to remove
405
* @throws AopConfigException if the index is invalid
406
*/
407
void removeAdvisor(int index) throws AopConfigException;
408
409
/**
410
* Return the index (from 0) of the given advisor,
411
* or -1 if no such advisor applies to this proxy.
412
* <p>The return value of this method can be used to index into the advisors array.
413
* @param advisor the advisor to search for
414
* @return index from 0 of this advisor, or -1 if there's no such advisor
415
*/
416
int indexOf(Advisor advisor);
417
418
/**
419
* Replace the given advisor.
420
* <p><b>Note:</b> If the advisor is an {@link org.springframework.aop.IntroductionAdvisor}
421
* and the replacement is not or vice versa, the relevant interfaces will be added
422
* or removed from the proxied interfaces list.
423
* @param a the advisor to replace
424
* @param b the advisor to replace it with
425
* @return whether it was replaced. If the advisor wasn't found in the
426
* list of advisors, this method returns {@code false} and does nothing.
427
* @throws AopConfigException in case of invalid advice
428
*/
429
boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;
430
431
/**
432
* Add the given AOP Alliance advice to the tail of the advice (advisor) chain.
433
* <p>This will be wrapped in a DefaultPointcutAdvisor with a pointcut that always
434
* applies, and returned from the {@code getAdvisors()} method in this wrapped form.
435
* <p>Note that the given advice will apply to all invocations on the proxy,
436
* even to the {@code toString()} method! Use appropriate advice implementations
437
* or specify appropriate pointcuts to apply to a narrower set of methods.
438
* @param advice the advice to add to the tail of the chain
439
* @throws AopConfigException in case of invalid advice
440
* @see #addAdvice(int, Advice)
441
* @see org.springframework.aop.support.DefaultPointcutAdvisor
442
*/
443
void addAdvice(Advice advice) throws AopConfigException;
444
445
/**
446
* Add the given AOP Alliance Advice at the specified position in the advice chain.
447
* <p>This will be wrapped in a {@link org.springframework.aop.support.DefaultPointcutAdvisor}
448
* with a pointcut that always applies, and returned from the {@link #getAdvisors()}
449
* method in this wrapped form.
450
* <p>Note: The given advice will apply to all invocations on the proxy,
451
* even to the {@code toString()} method! Use appropriate advice implementations
452
* or specify appropriate pointcuts to apply to a narrower set of methods.
453
* @param pos index from 0 (head)
454
* @param advice advice to add at the specified position in the advice chain
455
* @throws AopConfigException in case of invalid advice
456
*/
457
void addAdvice(int pos, Advice advice) throws AopConfigException;
458
459
/**
460
* Remove the Advisor containing the given advice.
461
* @param advice the advice to remove
462
* @return {@code true} of the advice was found and removed;
463
* {@code false} if there was no such advice
464
*/
465
boolean removeAdvice(Advice advice);
466
467
/**
468
* Return the index (from 0) of the given AOP Alliance Advice,
469
* or -1 if no such advice is an advice for this proxy.
470
* <p>The return value of this method can be used to index into
471
* the advisors array.
472
* @param advice AOP Alliance advice to search for
473
* @return index from 0 of this advice, or -1 if there's no such advice
474
*/
475
int indexOf(Advice advice);
476
477
/**
478
* As {@code toString()} will normally be delegated to the target,
479
* this returns the equivalent for the AOP proxy.
480
* @return a string description of the proxy configuration
481
*/
482
String toProxyConfigString();
483
}
484
```
485
486
### Support Classes
487
488
Utility classes for AOP proxy creation and management.
489
490
```java { .api }
491
public final class AopContext {
492
/**
493
* Try to return the current AOP proxy. This method is usable only if the
494
* calling method has been invoked via AOP, and the AOP framework has been set
495
* to expose proxies. Otherwise, this method will throw an IllegalStateException.
496
* @return the current AOP proxy (never returns {@code null})
497
* @throws IllegalStateException if the proxy cannot be found, because the
498
* method was invoked outside an AOP invocation context, or because the
499
* AOP framework has not been configured to expose the proxy
500
*/
501
public static Object currentProxy() throws IllegalStateException;
502
}
503
504
public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanClassLoaderAware, AopInfrastructureBean {
505
/**
506
* This should run after all other processors, so that it can just add
507
* an advisor to existing proxies rather than double-proxy.
508
*/
509
private int order = Ordered.LOWEST_PRECEDENCE;
510
511
@Override
512
public void setBeanClassLoader(ClassLoader classLoader);
513
514
/**
515
* Return the currently configured {@link ClassLoader}, or {@code null}
516
* if none configured yet.
517
* <p>The default implementation simply returns {@code null}, as this
518
* base class does not hold a ClassLoader reference by default.
519
*/
520
protected ClassLoader getProxyClassLoader();
521
522
/**
523
* Check whether the given bean class is an infrastructure class that should
524
* never be proxied.
525
* <p>The default implementation considers Advices, Advisors and AopInfrastructureBeans
526
* as infrastructure classes.
527
* @param beanClass the class of the bean
528
* @return whether the bean represents an infrastructure class
529
* @see org.aopalliance.aop.Advice
530
* @see org.springframework.aop.Advisor
531
* @see org.springframework.aop.framework.AopInfrastructureBean
532
* @see #shouldSkip
533
*/
534
protected boolean isInfrastructureClass(Class<?> beanClass);
535
}
536
```
537
538
## Usage Examples
539
540
### Basic Proxy Creation
541
542
```java
543
// Create a simple proxy with method interceptor
544
Object target = new MyServiceImpl();
545
ProxyFactory factory = new ProxyFactory(target);
546
547
MethodInterceptor interceptor = invocation -> {
548
System.out.println("Before: " + invocation.getMethod().getName());
549
Object result = invocation.proceed();
550
System.out.println("After: " + invocation.getMethod().getName());
551
return result;
552
};
553
554
factory.addAdvice(interceptor);
555
MyService proxy = (MyService) factory.getProxy();
556
```
557
558
### Interface-Based Proxy
559
560
```java
561
// Proxy specific interfaces only
562
ProxyFactory factory = new ProxyFactory();
563
factory.setTarget(new MyServiceImpl());
564
factory.setInterfaces(MyService.class, AnotherInterface.class);
565
factory.addAdvice(new LoggingInterceptor());
566
567
MyService proxy = (MyService) factory.getProxy();
568
```
569
570
### Class-Based Proxy (CGLIB)
571
572
```java
573
// Force CGLIB proxying for target class
574
ProxyFactory factory = new ProxyFactory();
575
factory.setTarget(new ConcreteService());
576
factory.setProxyTargetClass(true); // Use CGLIB
577
factory.addAdvisor(new TransactionAdvisor());
578
579
ConcreteService proxy = (ConcreteService) factory.getProxy();
580
```
581
582
### Advanced Configuration
583
584
```java
585
ProxyFactory factory = new ProxyFactory();
586
factory.setTarget(target);
587
588
// Configure proxy behavior
589
factory.setOptimize(true);
590
factory.setFrozen(false);
591
factory.setExposeProxy(true);
592
factory.setPreFiltered(true);
593
594
// Add multiple advisors
595
factory.addAdvisor(new SecurityAdvisor());
596
factory.addAdvisor(new CachingAdvisor());
597
factory.addAdvisor(new LoggingAdvisor());
598
599
// Create proxy with custom class loader
600
Object proxy = factory.getProxy(Thread.currentThread().getContextClassLoader());
601
```
602
603
### Static Factory Methods
604
605
```java
606
// Convenience methods for common scenarios
607
MyService proxy1 = ProxyFactory.getProxy(MyService.class, loggingInterceptor);
608
609
TargetSource targetSource = new SingletonTargetSource(new MyServiceImpl());
610
MyService proxy2 = ProxyFactory.getProxy(MyService.class, targetSource);
611
```