0
# Template Caching and Loading
1
2
FreeMarker provides a flexible system for loading templates from various sources and caching them for optimal performance. The template loading and caching system consists of template loaders, cache storage, and lookup strategies.
3
4
## Template Loader Interface
5
6
The core interface for loading template sources:
7
8
```java { .api }
9
interface TemplateLoader {
10
Object findTemplateSource(String name) throws IOException;
11
long getLastModified(Object templateSource);
12
Reader getReader(Object templateSource, String encoding) throws IOException;
13
void closeTemplateSource(Object templateSource) throws IOException;
14
}
15
16
// Enhanced template loader with state information
17
interface StatefulTemplateLoader extends TemplateLoader {
18
void resetState();
19
}
20
```
21
22
## Built-in Template Loaders
23
24
### File Template Loader
25
26
Loads templates from the file system:
27
28
```java { .api }
29
class FileTemplateLoader implements TemplateLoader {
30
// Constructors
31
FileTemplateLoader(File baseDir) throws IOException;
32
FileTemplateLoader(File baseDir, boolean disableCanonicalization) throws IOException;
33
34
// TemplateLoader methods
35
Object findTemplateSource(String name) throws IOException;
36
long getLastModified(Object templateSource);
37
Reader getReader(Object templateSource, String encoding) throws IOException;
38
void closeTemplateSource(Object templateSource) throws IOException;
39
40
// Configuration methods
41
File getBaseDirectory();
42
boolean getEagerCanonicalization();
43
}
44
```
45
46
Usage example:
47
```java
48
// Load templates from /path/to/templates directory
49
Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
50
cfg.setTemplateLoader(new FileTemplateLoader(new File("/path/to/templates")));
51
52
// Or use the convenience method
53
cfg.setDirectoryForTemplateLoading(new File("/path/to/templates"));
54
```
55
56
### Class Template Loader
57
58
Loads templates from the classpath:
59
60
```java { .api }
61
class ClassTemplateLoader extends URLTemplateLoader {
62
// Constructors
63
ClassTemplateLoader(Class resourceLoaderClass, String basePackagePath);
64
65
// URLTemplateLoader methods
66
URL getURL(String name);
67
}
68
```
69
70
Usage example:
71
```java
72
// Load templates from classpath under /templates package
73
Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
74
cfg.setTemplateLoader(new ClassTemplateLoader(MyClass.class, "/templates"));
75
76
// Or use the convenience method
77
cfg.setClassForTemplateLoading(MyClass.class, "/templates");
78
```
79
80
### String Template Loader
81
82
Loads templates from strings stored in memory:
83
84
```java { .api }
85
class StringTemplateLoader implements TemplateLoader {
86
// Constructor
87
StringTemplateLoader();
88
89
// Template management
90
void putTemplate(String name, String templateSource);
91
void putTemplate(String name, String templateSource, long lastModified);
92
void removeTemplate(String name);
93
void closeTemplateSource(Object templateSource) throws IOException;
94
95
// TemplateLoader methods
96
Object findTemplateSource(String name) throws IOException;
97
long getLastModified(Object templateSource);
98
Reader getReader(Object templateSource, String encoding) throws IOException;
99
}
100
```
101
102
Usage example:
103
```java
104
StringTemplateLoader loader = new StringTemplateLoader();
105
loader.putTemplate("hello.ftl", "<html><body>Hello ${name}!</body></html>");
106
loader.putTemplate("email.ftl", "Dear ${recipient}, Your order #${orderNumber} is ready.");
107
108
Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
109
cfg.setTemplateLoader(loader);
110
```
111
112
### Multi Template Loader
113
114
Combines multiple template loaders:
115
116
```java { .api }
117
class MultiTemplateLoader implements StatefulTemplateLoader {
118
// Constructor
119
MultiTemplateLoader(TemplateLoader[] loaders);
120
121
// StatefulTemplateLoader methods
122
Object findTemplateSource(String name) throws IOException;
123
long getLastModified(Object templateSource);
124
Reader getReader(Object templateSource, String encoding) throws IOException;
125
void closeTemplateSource(Object templateSource) throws IOException;
126
void resetState();
127
128
// Configuration methods
129
TemplateLoader[] getTemplateLoaders();
130
}
131
```
132
133
Usage example:
134
```java
135
// Combine file system and classpath loading
136
TemplateLoader[] loaders = {
137
new FileTemplateLoader(new File("/custom/templates")),
138
new ClassTemplateLoader(MyClass.class, "/default/templates")
139
};
140
141
Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
142
cfg.setTemplateLoader(new MultiTemplateLoader(loaders));
143
```
144
145
### URL Template Loader
146
147
Abstract base class for URL-based template loading:
148
149
```java { .api }
150
abstract class URLTemplateLoader implements TemplateLoader {
151
// Abstract method to be implemented by subclasses
152
protected abstract URL getURL(String name);
153
154
// TemplateLoader implementation
155
Object findTemplateSource(String name) throws IOException;
156
long getLastModified(Object templateSource);
157
Reader getReader(Object templateSource, String encoding) throws IOException;
158
void closeTemplateSource(Object templateSource) throws IOException;
159
160
// Configuration methods
161
void setURLConnectionUsesCaches(Boolean urlConnectionUsesCaches);
162
Boolean getURLConnectionUsesCaches();
163
}
164
```
165
166
### Webapp Template Loader
167
168
Loads templates from servlet context:
169
170
```java { .api }
171
class WebappTemplateLoader implements TemplateLoader {
172
// Constructors
173
WebappTemplateLoader(ServletContext servletContext);
174
WebappTemplateLoader(ServletContext servletContext, String subdirPath);
175
176
// TemplateLoader methods
177
Object findTemplateSource(String name) throws IOException;
178
long getLastModified(Object templateSource);
179
Reader getReader(Object templateSource, String encoding) throws IOException;
180
void closeTemplateSource(Object templateSource) throws IOException;
181
}
182
```
183
184
Usage example:
185
```java
186
// In a servlet context
187
Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
188
cfg.setTemplateLoader(new WebappTemplateLoader(servletContext, "/WEB-INF/templates"));
189
```
190
191
## Cache Storage
192
193
### Cache Storage Interface
194
195
```java { .api }
196
interface CacheStorage {
197
Object get(Object key);
198
void put(Object key, Object value);
199
void remove(Object key);
200
void clear();
201
}
202
203
// Enhanced cache storage with size information
204
interface CacheStorageWithGetSize extends CacheStorage {
205
int getSize();
206
}
207
208
// Thread-safe cache storage
209
interface ConcurrentCacheStorage extends CacheStorage {
210
// Marker interface for thread-safe implementations
211
}
212
```
213
214
### Built-in Cache Storage Implementations
215
216
#### MRU Cache Storage
217
218
Most Recently Used cache with configurable size limits:
219
220
```java { .api }
221
class MruCacheStorage implements CacheStorageWithGetSize {
222
// Constructors
223
MruCacheStorage(int maxStrongSize);
224
MruCacheStorage(int maxStrongSize, int maxSoftSize);
225
226
// CacheStorage methods
227
Object get(Object key);
228
void put(Object key, Object value);
229
void remove(Object key);
230
void clear();
231
int getSize();
232
233
// Configuration methods
234
int getMaxStrongSize();
235
int getMaxSoftSize();
236
}
237
```
238
239
Usage example:
240
```java
241
// Cache up to 100 templates with strong references, 1000 with soft references
242
Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
243
cfg.setCacheStorage(new MruCacheStorage(100, 1000));
244
```
245
246
#### Soft Cache Storage
247
248
Uses soft references for automatic memory management:
249
250
```java { .api }
251
class SoftCacheStorage implements ConcurrentCacheStorage, CacheStorageWithGetSize {
252
// Constructor
253
SoftCacheStorage();
254
255
// CacheStorage methods
256
Object get(Object key);
257
void put(Object key, Object value);
258
void remove(Object key);
259
void clear();
260
int getSize();
261
}
262
```
263
264
#### Strong Cache Storage
265
266
No automatic eviction - cached items remain until explicitly removed:
267
268
```java { .api }
269
class StrongCacheStorage implements ConcurrentCacheStorage, CacheStorageWithGetSize {
270
// Constructor
271
StrongCacheStorage();
272
273
// CacheStorage methods
274
Object get(Object key);
275
void put(Object key, Object value);
276
void remove(Object key);
277
void clear();
278
int getSize();
279
}
280
```
281
282
#### Null Cache Storage
283
284
Disables caching completely:
285
286
```java { .api }
287
class NullCacheStorage implements ConcurrentCacheStorage, CacheStorageWithGetSize {
288
// Singleton instance
289
static final NullCacheStorage INSTANCE = new NullCacheStorage();
290
291
// Constructor
292
NullCacheStorage();
293
294
// CacheStorage methods (all no-ops)
295
Object get(Object key);
296
void put(Object key, Object value);
297
void remove(Object key);
298
void clear();
299
int getSize();
300
}
301
```
302
303
### Cache Configuration Examples
304
305
```java
306
// Default cache (MRU with reasonable limits)
307
Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
308
// Uses default MruCacheStorage
309
310
// Custom MRU cache
311
cfg.setCacheStorage(new MruCacheStorage(50, 200));
312
313
// Soft references cache (good for memory-constrained environments)
314
cfg.setCacheStorage(new SoftCacheStorage());
315
316
// Strong cache (never evicts, good for small template sets)
317
cfg.setCacheStorage(new StrongCacheStorage());
318
319
// Disable caching (useful for development)
320
cfg.setCacheStorage(NullCacheStorage.INSTANCE);
321
```
322
323
## Template Lookup Strategy
324
325
Controls how templates are resolved and loaded:
326
327
```java { .api }
328
abstract class TemplateLookupStrategy {
329
// Main lookup method
330
abstract TemplateLookupResult lookup(TemplateLookupContext ctx) throws IOException;
331
332
// Default strategy constants
333
static final TemplateLookupStrategy DEFAULT_2_3_0 = DefaultTemplateLookupStrategy.INSTANCE;
334
}
335
336
// Lookup context
337
class TemplateLookupContext {
338
String getTemplateName();
339
Locale getTemplateLocale();
340
String getCustomLookupCondition();
341
TemplateLoader getTemplateLoader();
342
}
343
344
// Lookup result
345
abstract class TemplateLookupResult {
346
abstract boolean isPositive();
347
}
348
```
349
350
## Template Name Format
351
352
Controls template name formatting and normalization:
353
354
```java { .api }
355
abstract class TemplateNameFormat {
356
// Name formatting methods
357
abstract String normalizeAbsoluteName(String name) throws MalformedTemplateNameException;
358
abstract String normalizeName(String name) throws MalformedTemplateNameException;
359
abstract String toAbsoluteName(String baseName, String targetName) throws MalformedTemplateNameException;
360
abstract String toRootBasedName(String baseName, String targetName) throws MalformedTemplateNameException;
361
362
// Default format constants
363
static final TemplateNameFormat DEFAULT_2_3_0 = DefaultTemplateNameFormat.INSTANCE_2_3_0;
364
static final TemplateNameFormat DEFAULT_2_4_0 = DefaultTemplateNameFormat.INSTANCE_2_4_0;
365
}
366
```
367
368
## Template Configuration
369
370
Per-template configuration using matchers:
371
372
```java { .api }
373
abstract class TemplateConfigurationFactory {
374
abstract TemplateConfiguration get(String sourceName, Object templateSource) throws IOException, TemplateConfigurationFactory.TemplateConfigurationFactoryException;
375
}
376
377
class ConditionalTemplateConfigurationFactory extends TemplateConfigurationFactory {
378
// Constructor
379
ConditionalTemplateConfigurationFactory(TemplateSourceMatcher matcher, TemplateConfigurationFactory factory);
380
381
TemplateConfiguration get(String sourceName, Object templateSource) throws IOException, TemplateConfigurationFactoryException;
382
}
383
384
// Template-specific configuration
385
class TemplateConfiguration extends Configurable implements ParserConfiguration {
386
TemplateConfiguration();
387
388
// Apply configuration to parent configurable
389
void apply(Configurable configurable);
390
}
391
```
392
393
## Template Source Matchers
394
395
Match templates based on various criteria:
396
397
```java { .api }
398
abstract class TemplateSourceMatcher {
399
abstract boolean matches(String sourceName, Object templateSource) throws IOException;
400
}
401
402
// Path glob matching
403
class PathGlobMatcher extends TemplateSourceMatcher {
404
PathGlobMatcher(String glob);
405
PathGlobMatcher(String glob, boolean caseSensitive);
406
boolean matches(String sourceName, Object templateSource) throws IOException;
407
}
408
409
// File extension matching
410
class FileExtensionMatcher extends TemplateSourceMatcher {
411
FileExtensionMatcher(String extension);
412
FileExtensionMatcher(String extension, boolean caseSensitive);
413
boolean matches(String sourceName, Object templateSource) throws IOException;
414
}
415
416
// OR matcher - matches if any submatcher matches
417
class OrMatcher extends TemplateSourceMatcher {
418
OrMatcher(TemplateSourceMatcher... matchers);
419
boolean matches(String sourceName, Object templateSource) throws IOException;
420
}
421
```
422
423
### Template Configuration Examples
424
425
```java
426
Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
427
428
// Configure specific output format for HTML templates
429
TemplateConfiguration htmlConfig = new TemplateConfiguration();
430
htmlConfig.setOutputFormat(HTMLOutputFormat.INSTANCE);
431
htmlConfig.setAutoEscapingPolicy(Configuration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY);
432
433
cfg.setTemplateConfigurations(
434
new ConditionalTemplateConfigurationFactory(
435
new FileExtensionMatcher("html"),
436
new FirstMatchTemplateConfigurationFactory(htmlConfig)
437
)
438
);
439
440
// Configure different settings for email templates
441
TemplateConfiguration emailConfig = new TemplateConfiguration();
442
emailConfig.setOutputFormat(PlainTextOutputFormat.INSTANCE);
443
emailConfig.setWhitespaceStripping(true);
444
445
cfg.setTemplateConfigurations(
446
new ConditionalTemplateConfigurationFactory(
447
new PathGlobMatcher("email/**"),
448
new FirstMatchTemplateConfigurationFactory(emailConfig)
449
)
450
);
451
```
452
453
## Cache Management
454
455
### Cache Control Methods
456
457
```java { .api }
458
// In Configuration class
459
void clearTemplateCache();
460
void removeTemplateFromCache(String name);
461
void removeTemplateFromCache(String name, Locale locale);
462
void removeTemplateFromCache(String name, Locale locale, String encoding);
463
void removeTemplateFromCache(String name, Locale locale, String encoding, boolean parseAsFTL);
464
465
// Cache statistics (if supported by cache storage)
466
CacheStorage getCacheStorage();
467
```
468
469
### Cache Monitoring Example
470
471
```java
472
Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
473
MruCacheStorage cache = new MruCacheStorage(100, 500);
474
cfg.setCacheStorage(cache);
475
476
// Monitor cache size
477
System.out.println("Cache size: " + cache.getSize());
478
System.out.println("Max strong size: " + cache.getMaxStrongSize());
479
480
// Clear specific templates from cache
481
cfg.removeTemplateFromCache("outdated-template.ftl");
482
483
// Clear entire cache
484
cfg.clearTemplateCache();
485
```
486
487
## Performance Optimization
488
489
### Template Loading Best Practices
490
491
1. **Use appropriate cache storage**: Choose based on memory constraints and template count
492
2. **Configure cache size limits**: Set limits based on your application's template usage patterns
493
3. **Use template pre-loading**: Load frequently used templates at startup
494
4. **Monitor cache hit rates**: Adjust cache size based on actual usage patterns
495
496
### Example: High-Performance Configuration
497
498
```java
499
Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
500
501
// Optimized for high-throughput applications
502
cfg.setTemplateLoader(new FileTemplateLoader(new File("templates")));
503
cfg.setCacheStorage(new MruCacheStorage(500, 2000)); // Large cache
504
cfg.setDefaultEncoding("UTF-8");
505
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
506
cfg.setLogTemplateExceptions(false); // Reduce logging overhead
507
cfg.setWrapUncheckedExceptions(true);
508
509
// Pre-load critical templates
510
cfg.getTemplate("header.ftl");
511
cfg.getTemplate("footer.ftl");
512
cfg.getTemplate("main-layout.ftl");
513
```
514
515
### Custom Template Loader Example
516
517
```java
518
public class DatabaseTemplateLoader implements TemplateLoader {
519
private final DataSource dataSource;
520
521
public DatabaseTemplateLoader(DataSource dataSource) {
522
this.dataSource = dataSource;
523
}
524
525
@Override
526
public Object findTemplateSource(String name) throws IOException {
527
try (Connection conn = dataSource.getConnection();
528
PreparedStatement stmt = conn.prepareStatement(
529
"SELECT content, last_modified FROM templates WHERE name = ?")) {
530
531
stmt.setString(1, name);
532
ResultSet rs = stmt.executeQuery();
533
534
if (rs.next()) {
535
return new DatabaseTemplateSource(
536
name,
537
rs.getString("content"),
538
rs.getTimestamp("last_modified").getTime()
539
);
540
}
541
return null;
542
} catch (SQLException e) {
543
throw new IOException("Failed to load template: " + name, e);
544
}
545
}
546
547
@Override
548
public long getLastModified(Object templateSource) {
549
return ((DatabaseTemplateSource) templateSource).getLastModified();
550
}
551
552
@Override
553
public Reader getReader(Object templateSource, String encoding) throws IOException {
554
String content = ((DatabaseTemplateSource) templateSource).getContent();
555
return new StringReader(content);
556
}
557
558
@Override
559
public void closeTemplateSource(Object templateSource) throws IOException {
560
// Nothing to close for database templates
561
}
562
563
private static class DatabaseTemplateSource {
564
private final String name;
565
private final String content;
566
private final long lastModified;
567
568
DatabaseTemplateSource(String name, String content, long lastModified) {
569
this.name = name;
570
this.content = content;
571
this.lastModified = lastModified;
572
}
573
574
String getContent() { return content; }
575
long getLastModified() { return lastModified; }
576
}
577
}
578
```