0
# Multi-Classloader Support
1
2
The AspectJ weaver provides comprehensive support for complex classloader hierarchies, OSGi environments, and multi-module applications. The weaving context system allows customization of class loading behavior and resource resolution for different deployment scenarios.
3
4
## Core Context Interfaces
5
6
### IWeavingContext
7
8
Interface for supporting AspectJ in OSGi and multi-classloader environments.
9
10
```java { .api }
11
public interface IWeavingContext {
12
Enumeration<URL> getResources(String name) throws IOException;
13
String getBundleIdFromURL(URL url);
14
String getClassLoaderName();
15
ClassLoader getClassLoader();
16
String getFile(URL url);
17
String getId();
18
boolean isLocallyDefined(String classname);
19
List<Definition> getDefinitions(ClassLoader loader, WeavingAdaptor adaptor);
20
}
21
```
22
23
#### getResources
24
25
Retrieves resources with the given name from the context.
26
27
```java { .api }
28
Enumeration<URL> getResources(String name) throws IOException
29
```
30
31
**Parameters:**
32
- `name` - Resource name to search for
33
34
**Returns:** Enumeration of URLs for matching resources
35
36
**Throws:** `IOException` if resource lookup fails
37
38
#### getBundleIdFromURL
39
40
Returns the bundle ID for a given URL (deprecated, OSGi-specific).
41
42
```java { .api }
43
String getBundleIdFromURL(URL url)
44
```
45
46
**Parameters:**
47
- `url` - URL to get bundle ID for
48
49
**Returns:** Bundle identifier string
50
51
**Deprecated:** This method is deprecated in favor of more generic approaches
52
53
#### getClassLoaderName
54
55
Returns a descriptive name for the classloader.
56
57
```java { .api }
58
String getClassLoaderName()
59
```
60
61
**Returns:** Human-readable name for the classloader
62
63
#### getClassLoader
64
65
Returns the classloader associated with this context.
66
67
```java { .api }
68
ClassLoader getClassLoader()
69
```
70
71
**Returns:** ClassLoader instance for this context
72
73
#### getFile
74
75
Returns the file path for a given URL.
76
77
```java { .api }
78
String getFile(URL url)
79
```
80
81
**Parameters:**
82
- `url` - URL to convert to file path
83
84
**Returns:** File path string
85
86
#### getId
87
88
Returns a unique identifier for this weaving context.
89
90
```java { .api }
91
String getId()
92
```
93
94
**Returns:** Unique context identifier
95
96
#### isLocallyDefined
97
98
Checks if a class is locally defined in this context.
99
100
```java { .api }
101
boolean isLocallyDefined(String classname)
102
```
103
104
**Parameters:**
105
- `classname` - Fully qualified class name
106
107
**Returns:** True if class is defined locally in this context
108
109
#### getDefinitions
110
111
Returns weaving definitions for the given classloader and adaptor.
112
113
```java { .api }
114
List<Definition> getDefinitions(ClassLoader loader, WeavingAdaptor adaptor)
115
```
116
117
**Parameters:**
118
- `loader` - ClassLoader to get definitions for
119
- `adaptor` - WeavingAdaptor instance
120
121
**Returns:** List of Definition objects containing weaving configuration
122
123
### DefaultWeavingContext
124
125
Default implementation of IWeavingContext.
126
127
```java { .api }
128
public class DefaultWeavingContext implements IWeavingContext {
129
public DefaultWeavingContext(ClassLoader loader);
130
// Implements all IWeavingContext methods
131
}
132
```
133
134
#### Constructor
135
136
```java { .api }
137
public DefaultWeavingContext(ClassLoader loader)
138
```
139
140
Creates a default weaving context for the specified classloader.
141
142
**Parameters:**
143
- `loader` - ClassLoader to create context for
144
145
## Specialized ClassLoaders
146
147
### WeavingURLClassLoader
148
149
URLClassLoader implementation with integrated weaving capabilities.
150
151
```java { .api }
152
public class WeavingURLClassLoader extends URLClassLoader implements WeavingClassLoader {
153
public WeavingURLClassLoader(URL[] urls, ClassLoader parent);
154
public WeavingURLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory);
155
// Additional weaving-specific methods
156
}
157
```
158
159
#### Constructors
160
161
```java { .api }
162
public WeavingURLClassLoader(URL[] urls, ClassLoader parent)
163
```
164
165
Creates a weaving classloader with the specified URLs and parent.
166
167
**Parameters:**
168
- `urls` - Array of URLs to load classes from
169
- `parent` - Parent classloader
170
171
```java { .api }
172
public WeavingURLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory)
173
```
174
175
Creates a weaving classloader with URLs, parent, and URL stream handler factory.
176
177
**Parameters:**
178
- `urls` - Array of URLs to load classes from
179
- `parent` - Parent classloader
180
- `factory` - URLStreamHandlerFactory for custom protocol handling
181
182
## Configuration and Options
183
184
### Options
185
186
Configuration options for load-time weaving.
187
188
```java { .api }
189
public class Options {
190
// Configuration methods and constants for weaving options
191
}
192
```
193
194
### DefaultMessageHandler
195
196
Default message handler for weaving operations.
197
198
```java { .api }
199
public class DefaultMessageHandler implements IMessageHandler {
200
public DefaultMessageHandler();
201
// Message handling implementation
202
}
203
```
204
205
#### Constructor
206
207
```java { .api }
208
public DefaultMessageHandler()
209
```
210
211
Creates a default message handler for weaving messages.
212
213
## Usage Examples
214
215
### Custom Weaving Context
216
217
```java
218
import org.aspectj.weaver.loadtime.IWeavingContext;
219
import org.aspectj.weaver.loadtime.Aj;
220
221
public class CustomWeavingContext implements IWeavingContext {
222
private final ClassLoader classLoader;
223
private final String contextId;
224
225
public CustomWeavingContext(ClassLoader loader, String id) {
226
this.classLoader = loader;
227
this.contextId = id;
228
}
229
230
@Override
231
public Enumeration<URL> getResources(String name) throws IOException {
232
// Custom resource resolution logic
233
return classLoader.getResources(name);
234
}
235
236
@Override
237
public String getClassLoaderName() {
238
return classLoader.getClass().getSimpleName() + "@" + System.identityHashCode(classLoader);
239
}
240
241
@Override
242
public ClassLoader getClassLoader() {
243
return classLoader;
244
}
245
246
@Override
247
public String getId() {
248
return contextId;
249
}
250
251
@Override
252
public boolean isLocallyDefined(String classname) {
253
// Check if class is defined in this specific classloader
254
try {
255
Class<?> clazz = classLoader.loadClass(classname);
256
return clazz.getClassLoader() == classLoader;
257
} catch (ClassNotFoundException e) {
258
return false;
259
}
260
}
261
262
@Override
263
public List<Definition> getDefinitions(ClassLoader loader, WeavingAdaptor adaptor) {
264
// Return weaving definitions for this context
265
return Collections.emptyList();
266
}
267
268
@Override
269
public String getFile(URL url) {
270
return url.getFile();
271
}
272
273
@Override
274
public String getBundleIdFromURL(URL url) {
275
// Legacy method, return null for non-OSGi environments
276
return null;
277
}
278
}
279
280
// Usage
281
public class CustomWeavingExample {
282
public static void setupCustomWeaving() {
283
ClassLoader loader = Thread.currentThread().getContextClassLoader();
284
IWeavingContext context = new CustomWeavingContext(loader, "custom-context");
285
286
// Create Aj processor with custom context
287
Aj processor = new Aj(context);
288
processor.initialize();
289
290
// Use processor for weaving
291
byte[] originalBytes = getClassBytes("com.example.MyClass");
292
byte[] wovenBytes = processor.preProcess("com.example.MyClass",
293
originalBytes, loader, null);
294
}
295
296
private static byte[] getClassBytes(String className) {
297
// Implementation to get class bytes
298
return new byte[0];
299
}
300
}
301
```
302
303
### Multi-ClassLoader Environment
304
305
```java
306
import org.aspectj.weaver.tools.WeavingAdaptor;
307
import org.aspectj.weaver.loadtime.WeavingURLClassLoader;
308
309
public class MultiClassLoaderExample {
310
public static void setupMultiClassLoaderWeaving() {
311
// Create parent classloader
312
ClassLoader parentLoader = Thread.currentThread().getContextClassLoader();
313
314
// Create weaving classloaders for different modules
315
URL[] moduleAUrls = {getModuleAUrl()};
316
URL[] moduleBUrls = {getModuleBUrl()};
317
318
WeavingURLClassLoader moduleALoader = new WeavingURLClassLoader(moduleAUrls, parentLoader);
319
WeavingURLClassLoader moduleBLoader = new WeavingURLClassLoader(moduleBUrls, parentLoader);
320
321
// Create separate weaving adaptors for each module
322
WeavingAdaptor adaptorA = new WeavingAdaptor(moduleALoader);
323
WeavingAdaptor adaptorB = new WeavingAdaptor(moduleBLoader);
324
325
// Load and weave classes from different modules
326
loadAndWeaveClass(adaptorA, moduleALoader, "com.modulea.ClassA");
327
loadAndWeaveClass(adaptorB, moduleBLoader, "com.moduleb.ClassB");
328
}
329
330
private static void loadAndWeaveClass(WeavingAdaptor adaptor, ClassLoader loader, String className) {
331
try {
332
// Load original class bytes
333
byte[] originalBytes = getClassBytesFromLoader(loader, className);
334
335
// Weave the class
336
byte[] wovenBytes = adaptor.weaveClass(className, originalBytes);
337
338
// Define the class in the appropriate classloader
339
Class<?> wovenClass = defineClass(loader, className, wovenBytes);
340
341
System.out.println("Successfully wove class: " + wovenClass.getName());
342
343
} catch (Exception e) {
344
System.err.println("Failed to weave class " + className + ": " + e.getMessage());
345
}
346
}
347
348
private static URL getModuleAUrl() {
349
// Return URL for module A classes
350
return null;
351
}
352
353
private static URL getModuleBUrl() {
354
// Return URL for module B classes
355
return null;
356
}
357
358
private static byte[] getClassBytesFromLoader(ClassLoader loader, String className) {
359
// Implementation to get class bytes from specific loader
360
return new byte[0];
361
}
362
363
private static Class<?> defineClass(ClassLoader loader, String name, byte[] bytes) {
364
// Implementation to define class in loader
365
return null;
366
}
367
}
368
```
369
370
### OSGi Environment Support
371
372
```java
373
import org.aspectj.weaver.loadtime.IWeavingContext;
374
import org.osgi.framework.Bundle;
375
import org.osgi.framework.BundleContext;
376
377
public class OSGiWeavingContext implements IWeavingContext {
378
private final Bundle bundle;
379
private final BundleContext bundleContext;
380
381
public OSGiWeavingContext(Bundle bundle) {
382
this.bundle = bundle;
383
this.bundleContext = bundle.getBundleContext();
384
}
385
386
@Override
387
public Enumeration<URL> getResources(String name) throws IOException {
388
// Use OSGi bundle resource lookup
389
return bundle.getResources(name);
390
}
391
392
@Override
393
public String getBundleIdFromURL(URL url) {
394
// Extract bundle ID from OSGi URL
395
String path = url.getPath();
396
if (path.startsWith("/bundle")) {
397
String[] parts = path.split("/");
398
if (parts.length > 1) {
399
return parts[1];
400
}
401
}
402
return String.valueOf(bundle.getBundleId());
403
}
404
405
@Override
406
public String getClassLoaderName() {
407
return "OSGi Bundle: " + bundle.getSymbolicName();
408
}
409
410
@Override
411
public ClassLoader getClassLoader() {
412
// OSGi bundles don't expose classloaders directly
413
return this.getClass().getClassLoader();
414
}
415
416
@Override
417
public String getId() {
418
return bundle.getSymbolicName() + "_" + bundle.getVersion();
419
}
420
421
@Override
422
public boolean isLocallyDefined(String classname) {
423
try {
424
// Check if class is provided by this bundle
425
return bundle.loadClass(classname) != null;
426
} catch (ClassNotFoundException e) {
427
return false;
428
}
429
}
430
431
@Override
432
public List<Definition> getDefinitions(ClassLoader loader, WeavingAdaptor adaptor) {
433
// Load weaving definitions from bundle resources
434
List<Definition> definitions = new ArrayList<>();
435
436
try {
437
Enumeration<URL> aopXmlUrls = getResources("META-INF/aop.xml");
438
while (aopXmlUrls.hasMoreElements()) {
439
URL aopXmlUrl = aopXmlUrls.nextElement();
440
// Parse aop.xml and create Definition objects
441
Definition def = parseAopXml(aopXmlUrl);
442
definitions.add(def);
443
}
444
} catch (IOException e) {
445
System.err.println("Failed to load aop.xml from bundle: " + e.getMessage());
446
}
447
448
return definitions;
449
}
450
451
@Override
452
public String getFile(URL url) {
453
return url.getFile();
454
}
455
456
private Definition parseAopXml(URL aopXmlUrl) {
457
// Implementation to parse aop.xml file
458
return null;
459
}
460
}
461
462
// Usage in OSGi environment
463
public class OSGiWeavingExample {
464
public void setupOSGiWeaving(Bundle bundle) {
465
IWeavingContext context = new OSGiWeavingContext(bundle);
466
Aj processor = new Aj(context);
467
processor.initialize();
468
469
// Use processor for OSGi-aware weaving
470
}
471
}
472
```
473
474
### Class Loading Isolation
475
476
```java
477
import org.aspectj.weaver.tools.cache.WeavedClassCache;
478
479
public class IsolatedWeavingExample {
480
public static void setupIsolatedWeaving() {
481
// Create isolated classloaders for different application modules
482
ClassLoader appLoader = createApplicationClassLoader();
483
ClassLoader pluginLoader1 = createPluginClassLoader("plugin1");
484
ClassLoader pluginLoader2 = createPluginClassLoader("plugin2");
485
486
// Create separate caches for each classloader
487
List<String> appAspects = Arrays.asList("com.app.LoggingAspect");
488
List<String> plugin1Aspects = Arrays.asList("com.plugin1.SecurityAspect");
489
List<String> plugin2Aspects = Arrays.asList("com.plugin2.MetricsAspect");
490
491
WeavedClassCache appCache = WeavedClassCache.createCache(appLoader, appAspects, null, null);
492
WeavedClassCache plugin1Cache = WeavedClassCache.createCache(pluginLoader1, plugin1Aspects, null, null);
493
WeavedClassCache plugin2Cache = WeavedClassCache.createCache(pluginLoader2, plugin2Aspects, null, null);
494
495
// Each cache operates independently with its own classloader scope
496
System.out.println("App cache: " + appCache.getName());
497
System.out.println("Plugin1 cache: " + plugin1Cache.getName());
498
System.out.println("Plugin2 cache: " + plugin2Cache.getName());
499
}
500
501
private static ClassLoader createApplicationClassLoader() {
502
URL[] urls = {getApplicationJarUrl()};
503
return new URLClassLoader(urls, ClassLoader.getSystemClassLoader());
504
}
505
506
private static ClassLoader createPluginClassLoader(String pluginName) {
507
URL[] urls = {getPluginJarUrl(pluginName)};
508
return new URLClassLoader(urls, ClassLoader.getSystemClassLoader());
509
}
510
511
private static URL getApplicationJarUrl() {
512
// Return URL for application JAR
513
return null;
514
}
515
516
private static URL getPluginJarUrl(String pluginName) {
517
// Return URL for plugin JAR
518
return null;
519
}
520
}
521
```
522
523
## Configuration
524
525
### Context-Specific Configuration
526
527
Different classloader contexts can have different weaving configurations:
528
529
```xml
530
<!-- META-INF/aop.xml for Module A -->
531
<aspectj>
532
<weaver options="-verbose">
533
<include within="com.modulea..*"/>
534
</weaver>
535
<aspects>
536
<aspect name="com.modulea.LoggingAspect"/>
537
</aspects>
538
</aspectj>
539
```
540
541
```xml
542
<!-- META-INF/aop.xml for Module B -->
543
<aspectj>
544
<weaver options="-showWeaveInfo">
545
<include within="com.moduleb..*"/>
546
</weaver>
547
<aspects>
548
<aspect name="com.moduleb.SecurityAspect"/>
549
</aspects>
550
</aspectj>
551
```
552
553
### System Properties
554
555
- **`aj.class.path`**: Additional classpath for aspect resolution
556
- **`org.aspectj.weaver.loadtime.configuration`**: Custom configuration file location
557
- **`aj.weaving.loadtime.configuration.debug`**: Debug configuration loading
558
559
## Best Practices
560
561
1. **Context Isolation**: Use separate weaving contexts for different modules
562
2. **Resource Management**: Properly clean up classloaders and contexts
563
3. **Cache Scoping**: Use appropriate cache scoping for classloader hierarchies
564
4. **Configuration Management**: Keep weaving configuration close to the code it affects
565
566
## Troubleshooting
567
568
### Common Issues
569
570
1. **ClassNotFoundException**: Check classloader hierarchy and resource visibility
571
2. **Aspect Not Applied**: Verify aspect is visible from the target class's classloader
572
3. **Memory Leaks**: Ensure proper cleanup of custom classloaders and contexts
573
574
### Debug Output
575
576
```java
577
// Enable classloader debugging
578
System.setProperty("aj.weaving.loadtime.configuration.debug", "true");
579
System.setProperty("java.system.class.loader", "custom.DebuggingClassLoader");
580
```
581
582
### Context Information
583
584
```java
585
public static void printContextInfo(IWeavingContext context) {
586
System.out.println("Context ID: " + context.getId());
587
System.out.println("ClassLoader: " + context.getClassLoaderName());
588
System.out.println("ClassLoader instance: " + context.getClassLoader());
589
590
// Test resource resolution
591
try {
592
Enumeration<URL> resources = context.getResources("META-INF/aop.xml");
593
while (resources.hasMoreElements()) {
594
System.out.println("Found aop.xml: " + resources.nextElement());
595
}
596
} catch (IOException e) {
597
System.err.println("Failed to load resources: " + e.getMessage());
598
}
599
}
600
```