or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotation-configuration.mdapplication-context.mdcaching.mdconfiguration-properties.mddependency-injection.mdevent-handling.mdformatting.mdindex.mdlifecycle-management.mdscheduling.mdvalidation.md

caching.mddocs/

0

# Caching

1

2

Declarative caching abstraction providing transparent caching capabilities for method return values. This includes @Cacheable, @CachePut, and @CacheEvict annotations, cache managers, key generation strategies, and error handling for building high-performance applications with caching.

3

4

## Capabilities

5

6

### Caching Annotations

7

8

Declarative caching through annotations that automatically cache method return values and manage cache entries.

9

10

```java { .api }

11

/**

12

* Annotation indicating that the result of invoking a method (or all methods in a class) can be cached.

13

*/

14

@Target({ElementType.TYPE, ElementType.METHOD})

15

@Retention(RetentionPolicy.RUNTIME)

16

@Inherited

17

public @interface Cacheable {

18

/**

19

* Alias for cacheNames().

20

* @return the cache names

21

*/

22

@AliasFor("cacheNames")

23

String[] value() default {};

24

25

/**

26

* Names of the caches in which method invocation results are stored.

27

* @return the cache names

28

*/

29

@AliasFor("value")

30

String[] cacheNames() default {};

31

32

/**

33

* Spring Expression Language (SpEL) expression for computing the key dynamically.

34

* @return the key expression

35

*/

36

String key() default "";

37

38

/**

39

* The bean name of the custom KeyGenerator to use.

40

* @return the key generator bean name

41

*/

42

String keyGenerator() default "";

43

44

/**

45

* The bean name of the custom CacheManager to use to create a default CacheResolver if none is set already.

46

* @return the cache manager bean name

47

*/

48

String cacheManager() default "";

49

50

/**

51

* The bean name of the custom CacheResolver to use.

52

* @return the cache resolver bean name

53

*/

54

String cacheResolver() default "";

55

56

/**

57

* Spring Expression Language (SpEL) expression used for making the method caching conditional.

58

* @return the condition expression

59

*/

60

String condition() default "";

61

62

/**

63

* Spring Expression Language (SpEL) expression used to veto method caching.

64

* @return the unless expression

65

*/

66

String unless() default "";

67

68

/**

69

* Synchronize the invocation of the underlying method if several threads are attempting to load a value for the same key.

70

* @return whether to synchronize cache access

71

*/

72

boolean sync() default false;

73

}

74

75

/**

76

* Annotation indicating that a method (or all methods on a class) trigger a cache put operation.

77

*/

78

@Target({ElementType.TYPE, ElementType.METHOD})

79

@Retention(RetentionPolicy.RUNTIME)

80

@Inherited

81

public @interface CachePut {

82

/**

83

* Alias for cacheNames().

84

* @return the cache names

85

*/

86

@AliasFor("cacheNames")

87

String[] value() default {};

88

89

/**

90

* Names of the caches in which method invocation results are stored.

91

* @return the cache names

92

*/

93

@AliasFor("value")

94

String[] cacheNames() default {};

95

96

/**

97

* Spring Expression Language (SpEL) expression for computing the key dynamically.

98

* @return the key expression

99

*/

100

String key() default "";

101

102

/**

103

* The bean name of the custom KeyGenerator to use.

104

* @return the key generator bean name

105

*/

106

String keyGenerator() default "";

107

108

/**

109

* The bean name of the custom CacheManager to use to create a default CacheResolver if none is set already.

110

* @return the cache manager bean name

111

*/

112

String cacheManager() default "";

113

114

/**

115

* The bean name of the custom CacheResolver to use.

116

* @return the cache resolver bean name

117

*/

118

String cacheResolver() default "";

119

120

/**

121

* Spring Expression Language (SpEL) expression used for making the method caching conditional.

122

* @return the condition expression

123

*/

124

String condition() default "";

125

126

/**

127

* Spring Expression Language (SpEL) expression used to veto method caching.

128

* @return the unless expression

129

*/

130

String unless() default "";

131

}

132

133

/**

134

* Annotation indicating that a method (or all methods on a class) trigger cache evict operations.

135

*/

136

@Target({ElementType.TYPE, ElementType.METHOD})

137

@Retention(RetentionPolicy.RUNTIME)

138

@Inherited

139

public @interface CacheEvict {

140

/**

141

* Alias for cacheNames().

142

* @return the cache names

143

*/

144

@AliasFor("cacheNames")

145

String[] value() default {};

146

147

/**

148

* Names of the caches to evict.

149

* @return the cache names

150

*/

151

@AliasFor("value")

152

String[] cacheNames() default {};

153

154

/**

155

* Spring Expression Language (SpEL) expression for computing the key dynamically.

156

* @return the key expression

157

*/

158

String key() default "";

159

160

/**

161

* The bean name of the custom KeyGenerator to use.

162

* @return the key generator bean name

163

*/

164

String keyGenerator() default "";

165

166

/**

167

* The bean name of the custom CacheManager to use to create a default CacheResolver if none is set already.

168

* @return the cache manager bean name

169

*/

170

String cacheManager() default "";

171

172

/**

173

* The bean name of the custom CacheResolver to use.

174

* @return the cache resolver bean name

175

*/

176

String cacheResolver() default "";

177

178

/**

179

* Spring Expression Language (SpEL) expression used for making the cache eviction conditional.

180

* @return the condition expression

181

*/

182

String condition() default "";

183

184

/**

185

* Whether all the entries inside the cache(s) are removed.

186

* @return whether to evict all entries

187

*/

188

boolean allEntries() default false;

189

190

/**

191

* Whether the eviction should occur before the method is invoked.

192

* @return whether to evict before invocation

193

*/

194

boolean beforeInvocation() default false;

195

}

196

197

/**

198

* Group annotation for multiple cache annotations (of different or the same type).

199

*/

200

@Target({ElementType.TYPE, ElementType.METHOD})

201

@Retention(RetentionPolicy.RUNTIME)

202

@Inherited

203

public @interface Caching {

204

/**

205

* Array of @Cacheable annotations.

206

* @return the cacheable annotations

207

*/

208

Cacheable[] cacheable() default {};

209

210

/**

211

* Array of @CachePut annotations.

212

* @return the cache put annotations

213

*/

214

CachePut[] put() default {};

215

216

/**

217

* Array of @CacheEvict annotations.

218

* @return the cache evict annotations

219

*/

220

CacheEvict[] evict() default {};

221

}

222

223

/**

224

* @CacheConfig provides a mechanism for sharing common cache-related settings at the class level.

225

*/

226

@Target(ElementType.TYPE)

227

@Retention(RetentionPolicy.RUNTIME)

228

public @interface CacheConfig {

229

/**

230

* Names of the default caches to consider for caching operations defined in this class.

231

* @return the cache names

232

*/

233

String[] cacheNames() default {};

234

235

/**

236

* The bean name of the default KeyGenerator to use for the class.

237

* @return the key generator bean name

238

*/

239

String keyGenerator() default "";

240

241

/**

242

* The bean name of the custom CacheManager to use to create a default CacheResolver if none is set already.

243

* @return the cache manager bean name

244

*/

245

String cacheManager() default "";

246

247

/**

248

* The bean name of the custom CacheResolver to use.

249

* @return the cache resolver bean name

250

*/

251

String cacheResolver() default "";

252

}

253

254

/**

255

* Enables Spring's annotation-driven cache management capability, similar to the support found in Spring's XML namespace.

256

*/

257

@Target(ElementType.TYPE)

258

@Retention(RetentionPolicy.RUNTIME)

259

@Import(CachingConfigurationSelector.class)

260

public @interface EnableCaching {

261

/**

262

* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed to standard Java interface-based proxies.

263

* @return whether to proxy the target class

264

*/

265

boolean proxyTargetClass() default false;

266

267

/**

268

* Indicate how caching advice should be applied.

269

* @return the advice mode

270

*/

271

AdviceMode mode() default AdviceMode.PROXY;

272

273

/**

274

* Indicate the ordering of the execution of the caching advisor when multiple advices are applied at a specific join point.

275

* @return the order for the caching advisor

276

*/

277

int order() default Ordered.LOWEST_PRECEDENCE;

278

}

279

```

280

281

### Cache Abstraction Interfaces

282

283

Core interfaces defining the cache abstraction layer.

284

285

```java { .api }

286

/**

287

* Interface that defines common cache operations.

288

* Note: Due to the generic use of caching, it is recommended that implementations allow storage of null values.

289

*/

290

public interface Cache {

291

/**

292

* Return the cache name.

293

* @return the cache name

294

*/

295

String getName();

296

297

/**

298

* Return the underlying native cache provider.

299

* @return the native cache provider

300

*/

301

Object getNativeCache();

302

303

/**

304

* Return the value to which this cache maps the specified key.

305

* @param key the key whose associated value is to be returned

306

* @return the value to which this cache maps the specified key, or null if the cache contains no mapping for this key

307

*/

308

ValueWrapper get(Object key);

309

310

/**

311

* Return the value to which this cache maps the specified key, generically specifying a type that return value will be cast to.

312

* @param key the key whose associated value is to be returned

313

* @param type the required type of the returned value (may be null to bypass a type check)

314

* @return the value to which this cache maps the specified key (which may be null itself), or also null if the cache contains no mapping for this key

315

* @throws IllegalStateException if a cache entry has been found but failed to match the specified type

316

*/

317

<T> T get(Object key, Class<T> type);

318

319

/**

320

* Return the value to which this cache maps the specified key, obtaining that value from valueLoader if necessary.

321

* @param key the key whose associated value is to be returned

322

* @param valueLoader the value loader which will compute the value if necessary

323

* @return the value to which this cache maps the specified key

324

* @throws ValueRetrievalException if the valueLoader throws an exception or returns a null value

325

*/

326

<T> T get(Object key, Callable<T> valueLoader);

327

328

/**

329

* Associate the specified value with the specified key in this cache.

330

* @param key the key with which the specified value is to be associated

331

* @param value the value to be associated with the specified key

332

*/

333

void put(Object key, Object value);

334

335

/**

336

* Atomically associate the specified value with the specified key in this cache if it is not set already.

337

* @param key the key with which the specified value is to be associated

338

* @param value the value to be associated with the specified key

339

* @return the value that was associated with the key, or null if none was

340

*/

341

default ValueWrapper putIfAbsent(Object key, Object value) {

342

ValueWrapper existingValue = get(key);

343

if (existingValue == null) {

344

put(key, value);

345

}

346

return existingValue;

347

}

348

349

/**

350

* Evict the mapping for this key from this cache if it is present.

351

* @param key the key whose mapping is to be removed from the cache

352

*/

353

void evict(Object key);

354

355

/**

356

* Evict the mapping for this key from this cache if it is present.

357

* @param key the key whose mapping is to be removed from the cache

358

* @return true if the key was present, false if there was no mapping for the key

359

*/

360

default boolean evictIfPresent(Object key) {

361

evict(key);

362

return false;

363

}

364

365

/**

366

* Clear the cache through removing all mappings.

367

*/

368

void clear();

369

370

/**

371

* Invalidate the cache through removing all mappings.

372

* @return true if the cache was cleared, false if there was no cache entry that could be cleared or if the cache is not active

373

*/

374

default boolean invalidate() {

375

clear();

376

return true;

377

}

378

379

/**

380

* A (wrapper) object representing a cache value.

381

*/

382

@FunctionalInterface

383

interface ValueWrapper {

384

/**

385

* Return the actual value in the cache.

386

* @return the actual value in the cache (may be null)

387

*/

388

Object get();

389

}

390

391

/**

392

* Wrapper exception to be thrown from get(Object, Callable) in case of the value loader callback failing with an exception.

393

*/

394

class ValueRetrievalException extends RuntimeException {

395

private final Object key;

396

397

public ValueRetrievalException(Object key, Callable<?> loader, Throwable ex) {}

398

399

public Object getKey() {}

400

}

401

}

402

403

/**

404

* Spring's central cache manager SPI.

405

* Allows for retrieving named Cache regions.

406

*/

407

public interface CacheManager {

408

/**

409

* Get the cache associated with the given name.

410

* @param name the cache identifier (must not be null)

411

* @return the associated cache, or null if such a cache does not exist or could be not created

412

*/

413

Cache getCache(String name);

414

415

/**

416

* Get a collection of the cache names known by this manager.

417

* @return the names of all caches known by the cache manager

418

*/

419

Collection<String> getCacheNames();

420

}

421

```

422

423

### Cache Configuration Support

424

425

Interfaces and classes for configuring caching behavior.

426

427

```java { .api }

428

/**

429

* Interface to be implemented by @Configuration classes annotated with @EnableCaching

430

* that wish to (or need to) specify explicitly how caches are resolved and how keys are generated for annotation-driven cache management.

431

*/

432

public interface CachingConfigurer {

433

/**

434

* Return the cache manager bean to use for annotation-driven cache management.

435

* @return the cache manager instance

436

*/

437

default CacheManager cacheManager() {

438

return null;

439

}

440

441

/**

442

* Return the CacheResolver bean to use to resolve regular caches for annotation-driven cache management.

443

* @return the cache resolver instance

444

*/

445

default CacheResolver cacheResolver() {

446

return null;

447

}

448

449

/**

450

* Return the key generator bean to use for annotation-driven cache management.

451

* @return the key generator instance

452

*/

453

default KeyGenerator keyGenerator() {

454

return null;

455

}

456

457

/**

458

* Return the CacheErrorHandler to use to handle cache-related errors.

459

* @return the error handler instance

460

*/

461

default CacheErrorHandler errorHandler() {

462

return null;

463

}

464

}

465

466

/**

467

* An implementation of CachingConfigurer with empty methods allowing sub-classes to override only the methods they're interested in.

468

*/

469

public class CachingConfigurerSupport implements CachingConfigurer {

470

/**

471

* Return the cache manager bean to use for annotation-driven cache management.

472

* @return null

473

*/

474

@Override

475

public CacheManager cacheManager() {

476

return null;

477

}

478

479

/**

480

* Return the CacheResolver bean to use to resolve regular caches for annotation-driven cache management.

481

* @return null

482

*/

483

@Override

484

public CacheResolver cacheResolver() {

485

return null;

486

}

487

488

/**

489

* Return the key generator bean to use for annotation-driven cache management.

490

* @return null

491

*/

492

@Override

493

public KeyGenerator keyGenerator() {

494

return null;

495

}

496

497

/**

498

* Return the CacheErrorHandler to use to handle cache-related errors.

499

* @return null

500

*/

501

@Override

502

public CacheErrorHandler errorHandler() {

503

return null;

504

}

505

}

506

```

507

508

### Key Generation

509

510

Interfaces and classes for generating cache keys.

511

512

```java { .api }

513

/**

514

* Cache key generator. Used for creating a key based on the given method (used as context) and its parameters.

515

*/

516

@FunctionalInterface

517

public interface KeyGenerator {

518

/**

519

* Generate a key for the given method and its parameters.

520

* @param target the target instance

521

* @param method the method being called

522

* @param params the method parameters (with any var-args expanded)

523

* @return a generated key

524

*/

525

Object generate(Object target, Method method, Object... params);

526

}

527

528

/**

529

* Simple key generator. Returns the parameter itself if a single non-null value is given,

530

* otherwise returns a SimpleKey of the parameters.

531

*/

532

public class SimpleKeyGenerator implements KeyGenerator {

533

/**

534

* Generate a key for the given method and its parameters.

535

* @param target the target instance

536

* @param method the method being called

537

* @param params the method parameters (with any var-args expanded)

538

* @return a generated key

539

*/

540

public Object generate(Object target, Method method, Object... params) {}

541

}

542

543

/**

544

* A simple key as returned by the SimpleKeyGenerator.

545

*/

546

public class SimpleKey implements Serializable {

547

/** The hash code of the key */

548

private final int hashCode;

549

550

/** The parameters that make up the key */

551

private final Object[] params;

552

553

/**

554

* Create a new SimpleKey instance.

555

* @param elements the elements of the key

556

*/

557

public SimpleKey(Object... elements) {}

558

559

/**

560

* Check equality with another object.

561

* @param other the object to compare with

562

* @return true if equal, false otherwise

563

*/

564

@Override

565

public boolean equals(Object other) {}

566

567

/**

568

* Return the hash code for this key.

569

* @return the hash code

570

*/

571

@Override

572

public int hashCode() {}

573

574

/**

575

* Return a string representation of this key.

576

* @return a string representation

577

*/

578

@Override

579

public String toString() {}

580

}

581

```

582

583

### Cache Resolution

584

585

Interfaces and classes for resolving caches based on operation context.

586

587

```java { .api }

588

/**

589

* Determine the Cache instance(s) to use for an intercepted method invocation.

590

*/

591

@FunctionalInterface

592

public interface CacheResolver {

593

/**

594

* Return the cache(s) to use for the specified invocation.

595

* @param context the context of the cache operation

596

* @return the cache(s) to use (never null)

597

* @throws IllegalStateException if cache resolution failed

598

*/

599

Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context);

600

}

601

602

/**

603

* A simple CacheResolver that resolves the Cache instance(s) based on a configurable CacheManager and the name of the cache(s) as provided by getCacheNames().

604

*/

605

public class SimpleCacheResolver extends AbstractCacheResolver {

606

/**

607

* Construct a new SimpleCacheResolver.

608

*/

609

public SimpleCacheResolver() {}

610

611

/**

612

* Construct a new SimpleCacheResolver for the given CacheManager.

613

* @param cacheManager the CacheManager to use

614

*/

615

public SimpleCacheResolver(CacheManager cacheManager) {}

616

}

617

618

/**

619

* A CacheResolver that resolves the caches based on their names.

620

*/

621

public class NamedCacheResolver extends AbstractCacheResolver {

622

private final Collection<String> cacheNames;

623

624

/**

625

* Construct a new NamedCacheResolver for the given CacheManager and cache name(s).

626

* @param cacheManager the CacheManager to use

627

* @param cacheNames the cache name(s) to resolve

628

*/

629

public NamedCacheResolver(CacheManager cacheManager, String... cacheNames) {}

630

631

/**

632

* Set the cache name(s) that this resolver should use.

633

* @param cacheNames the cache name(s)

634

*/

635

public void setCacheNames(Collection<String> cacheNames) {}

636

}

637

```

638

639

### Cache Manager Implementations

640

641

Concrete implementations of CacheManager for different caching providers.

642

643

```java { .api }

644

/**

645

* Simple cache manager working against a given collection of caches.

646

*/

647

public class SimpleCacheManager extends AbstractCacheManager {

648

private Collection<? extends Cache> caches = Collections.emptySet();

649

650

/**

651

* Specify the collection of Cache instances to use for this CacheManager.

652

* @param caches the Cache instances to use

653

*/

654

public void setCaches(Collection<? extends Cache> caches) {}

655

656

/**

657

* Load the initial caches for this cache manager.

658

* @return the collection of caches

659

*/

660

protected Collection<? extends Cache> loadCaches() {}

661

}

662

663

/**

664

* Composite CacheManager implementation that iterates over a given collection of delegate CacheManager instances.

665

*/

666

public class CompositeCacheManager implements CacheManager, InitializingBean {

667

private final List<CacheManager> cacheManagers = new ArrayList<>();

668

private boolean fallbackToNoOpCache = false;

669

670

/**

671

* Construct a CompositeCacheManager.

672

*/

673

public CompositeCacheManager() {}

674

675

/**

676

* Construct a CompositeCacheManager from the given delegate CacheManagers.

677

* @param cacheManagers the CacheManagers to delegate to

678

*/

679

public CompositeCacheManager(CacheManager... cacheManagers) {}

680

681

/**

682

* Set the CacheManagers to delegate to.

683

* @param cacheManagers the CacheManagers to delegate to

684

*/

685

public void setCacheManagers(CacheManager... cacheManagers) {}

686

687

/**

688

* Indicate whether a NoOpCache should be returned when no matching cache is found.

689

* @param fallbackToNoOpCache whether to fall back to NoOpCache

690

*/

691

public void setFallbackToNoOpCache(boolean fallbackToNoOpCache) {}

692

693

/**

694

* Get the cache with the specified name from the first CacheManager that contains it.

695

* @param name the cache name

696

* @return the Cache instance, or null if not found

697

*/

698

public Cache getCache(String name) {}

699

700

/**

701

* Get all cache names from all delegate CacheManagers.

702

* @return the collection of cache names

703

*/

704

public Collection<String> getCacheNames() {}

705

}

706

707

/**

708

* A basic, no operation CacheManager implementation suitable for disabling caching,

709

* typically used for backing cache declarations without an actual backing store.

710

*/

711

public class NoOpCacheManager implements CacheManager {

712

private final Set<String> cacheNames = ConcurrentHashMap.newKeySet(16);

713

714

/**

715

* This implementation always returns a NoOpCache instance.

716

* @param name the cache name

717

* @return a NoOpCache instance

718

*/

719

public Cache getCache(String name) {}

720

721

/**

722

* Return the cache names that have been requested so far.

723

* @return the collection of cache names

724

*/

725

public Collection<String> getCacheNames() {}

726

}

727

728

/**

729

* CacheManager implementation that lazily builds ConcurrentMapCache instances for each getCache(String) request.

730

*/

731

public class ConcurrentMapCacheManager extends AbstractCacheManager {

732

private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);

733

private boolean allowNullValues = true;

734

private boolean storeByValue = false;

735

736

/**

737

* Construct a dynamic ConcurrentMapCacheManager, lazily creating cache instances as they are being requested.

738

*/

739

public ConcurrentMapCacheManager() {}

740

741

/**

742

* Construct a static ConcurrentMapCacheManager, managing caches for the specified cache names only.

743

* @param cacheNames the names of the static cache to create

744

*/

745

public ConcurrentMapCacheManager(String... cacheNames) {}

746

747

/**

748

* Specify the set of cache names for this CacheManager's 'static' mode.

749

* @param cacheNames the names of the static cache to create

750

*/

751

public void setCacheNames(Collection<String> cacheNames) {}

752

753

/**

754

* Specify whether to accept and convert null values for all caches in this cache manager.

755

* @param allowNullValues whether to allow null values

756

*/

757

public void setAllowNullValues(boolean allowNullValues) {}

758

759

/**

760

* Specify whether this cache manager stores a copy of each entry (true) or a reference (false) for all of its caches.

761

* @param storeByValue whether to store by value vs by reference

762

*/

763

public void setStoreByValue(boolean storeByValue) {}

764

765

/**

766

* Load the initial caches for this cache manager.

767

* @return the collection of caches

768

*/

769

protected Collection<Cache> loadCaches() {}

770

771

/**

772

* Dynamically register an additional Cache with this manager.

773

* @param cache the Cache to register

774

*/

775

public void registerCustomCache(Cache cache) {}

776

}

777

```

778

779

### Error Handling

780

781

Interfaces and classes for handling caching errors.

782

783

```java { .api }

784

/**

785

* A strategy for handling cache-related errors. In most cases, any exception thrown by the provider should simply be thrown back at the client.

786

* However, for some cases it might be useful to handle cache provider exceptions in a different way.

787

*/

788

public interface CacheErrorHandler {

789

/**

790

* Handle the given runtime exception thrown by the cache provider when retrieving an item with the specified key,

791

* possibly rethrowing it as a fatal exception.

792

* @param exception the exception thrown by the cache provider

793

* @param cache the cache

794

* @param key the key used to get the item

795

*/

796

void handleCacheGetError(RuntimeException exception, Cache cache, Object key);

797

798

/**

799

* Handle the given runtime exception thrown by the cache provider when updating an item with the specified key and value,

800

* possibly rethrowing it as a fatal exception.

801

* @param exception the exception thrown by the cache provider

802

* @param cache the cache

803

* @param key the key used to update the item

804

* @param value the value used to update the item

805

*/

806

void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value);

807

808

/**

809

* Handle the given runtime exception thrown by the cache provider when clearing an item with the specified key,

810

* possibly rethrowing it as a fatal exception.

811

* @param exception the exception thrown by the cache provider

812

* @param cache the cache

813

* @param key the key used to clear the item

814

*/

815

void handleCacheEvictError(RuntimeException exception, Cache cache, Object key);

816

817

/**

818

* Handle the given runtime exception thrown by the cache provider when clearing the specified cache,

819

* possibly rethrowing it as a fatal exception.

820

* @param exception the exception thrown by the cache provider

821

* @param cache the cache to clear

822

*/

823

void handleCacheClearError(RuntimeException exception, Cache cache);

824

}

825

826

/**

827

* Simple CacheErrorHandler that does not handle any exception at all, simply throwing it back at the client.

828

*/

829

public class SimpleCacheErrorHandler implements CacheErrorHandler {

830

/**

831

* Simply throw the exception as-is.

832

* @param exception the exception thrown by the cache provider

833

* @param cache the cache

834

* @param key the key used to get the item

835

*/

836

@Override

837

public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {}

838

839

/**

840

* Simply throw the exception as-is.

841

* @param exception the exception thrown by the cache provider

842

* @param cache the cache

843

* @param key the key used to update the item

844

* @param value the value used to update the item

845

*/

846

@Override

847

public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {}

848

849

/**

850

* Simply throw the exception as-is.

851

* @param exception the exception thrown by the cache provider

852

* @param cache the cache

853

* @param key the key used to clear the item

854

*/

855

@Override

856

public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {}

857

858

/**

859

* Simply throw the exception as-is.

860

* @param exception the exception thrown by the cache provider

861

* @param cache the cache to clear

862

*/

863

@Override

864

public void handleCacheClearError(RuntimeException exception, Cache cache) {}

865

}

866

867

/**

868

* CacheErrorHandler implementation that logs cache provider exceptions rather than rethrowing them,

869

* allowing the underlying method to be invoked in case of cache errors.

870

*/

871

public class LoggingCacheErrorHandler implements CacheErrorHandler {

872

private final Log logger = LogFactory.getLog(getClass());

873

874

/**

875

* Log the cache get error at WARN level.

876

* @param exception the exception thrown by the cache provider

877

* @param cache the cache

878

* @param key the key used to get the item

879

*/

880

@Override

881

public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {}

882

883

/**

884

* Log the cache put error at WARN level.

885

* @param exception the exception thrown by the cache provider

886

* @param cache the cache

887

* @param key the key used to update the item

888

* @param value the value used to update the item

889

*/

890

@Override

891

public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {}

892

893

/**

894

* Log the cache evict error at WARN level.

895

* @param exception the exception thrown by the cache provider

896

* @param cache the cache

897

* @param key the key used to clear the item

898

*/

899

@Override

900

public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {}

901

902

/**

903

* Log the cache clear error at WARN level.

904

* @param exception the exception thrown by the cache provider

905

* @param cache the cache to clear

906

*/

907

@Override

908

public void handleCacheClearError(RuntimeException exception, Cache cache) {}

909

}

910

```

911

912

### Usage Examples

913

914

**Basic Caching Usage:**

915

916

```java

917

import org.springframework.cache.annotation.*;

918

import org.springframework.stereotype.Service;

919

920

@Service

921

@CacheConfig(cacheNames = "users")

922

public class UserService {

923

924

// Cache the result of this method

925

@Cacheable

926

public User findUser(Long id) {

927

System.out.println("Loading user from database: " + id);

928

// Expensive database operation

929

return userRepository.findById(id);

930

}

931

932

// Cache with specific key

933

@Cacheable(key = "#email")

934

public User findUserByEmail(String email) {

935

System.out.println("Loading user by email: " + email);

936

return userRepository.findByEmail(email);

937

}

938

939

// Cache with condition

940

@Cacheable(condition = "#id > 10")

941

public User findUserConditional(Long id) {

942

// Only cache if id > 10

943

return userRepository.findById(id);

944

}

945

946

// Cache with unless condition

947

@Cacheable(unless = "#result.isTemporary")

948

public User findUserUnless(Long id) {

949

// Don't cache if result is temporary

950

return userRepository.findById(id);

951

}

952

953

// Update cache entry

954

@CachePut(key = "#user.id")

955

public User updateUser(User user) {

956

System.out.println("Updating user: " + user.getId());

957

User updated = userRepository.save(user);

958

return updated; // This will update the cache

959

}

960

961

// Evict cache entry

962

@CacheEvict(key = "#id")

963

public void deleteUser(Long id) {

964

System.out.println("Deleting user: " + id);

965

userRepository.deleteById(id);

966

}

967

968

// Evict all cache entries

969

@CacheEvict(allEntries = true)

970

public void deleteAllUsers() {

971

System.out.println("Deleting all users");

972

userRepository.deleteAll();

973

}

974

}

975

```

976

977

**Advanced Caching Patterns:**

978

979

```java

980

@Service

981

public class ProductService {

982

983

// Multiple cache operations

984

@Caching(

985

cacheable = {

986

@Cacheable(cacheNames = "products", key = "#id"),

987

@Cacheable(cacheNames = "productsByCategory", key = "#result.category.id", condition = "#result != null")

988

},

989

put = {

990

@CachePut(cacheNames = "recentProducts", key = "'recent'")

991

}

992

)

993

public Product findProduct(Long id) {

994

return productRepository.findById(id);

995

}

996

997

// Complex key generation with SpEL

998

@Cacheable(

999

cacheNames = "productSearch",

1000

key = "T(String).format('%s_%s_%d_%d', #category, #brand, #minPrice, #maxPrice)"

1001

)

1002

public List<Product> searchProducts(String category, String brand, int minPrice, int maxPrice) {

1003

return productRepository.search(category, brand, minPrice, maxPrice);

1004

}

1005

1006

// Using method parameter properties in key

1007

@Cacheable(cacheNames = "userProducts", key = "#user.id + '_' + #category")

1008

public List<Product> getUserProducts(User user, String category) {

1009

return productRepository.findByUserAndCategory(user.getId(), category);

1010

}

1011

1012

// Synchronized cache access for expensive operations

1013

@Cacheable(cacheNames = "expensiveCalculations", key = "#input", sync = true)

1014

public BigDecimal performExpensiveCalculation(String input) {

1015

// This ensures only one thread calculates for the same input

1016

try {

1017

Thread.sleep(5000); // Simulate expensive operation

1018

return new BigDecimal(input.hashCode());

1019

} catch (InterruptedException e) {

1020

Thread.currentThread().interrupt();

1021

throw new RuntimeException(e);

1022

}

1023

}

1024

1025

// Conditional eviction

1026

@CacheEvict(

1027

cacheNames = "products",

1028

key = "#product.id",

1029

condition = "#product.isPublished"

1030

)

1031

public Product unpublishProduct(Product product) {

1032

product.setPublished(false);

1033

return productRepository.save(product);

1034

}

1035

1036

// Evict before method invocation

1037

@CacheEvict(

1038

cacheNames = "productStatistics",

1039

allEntries = true,

1040

beforeInvocation = true

1041

)

1042

public void updateProductPrices() {

1043

// Clear statistics cache before updating prices

1044

// This ensures cache is cleared even if method fails

1045

productRepository.updateAllPrices();

1046

}

1047

}

1048

```

1049

1050

**Custom Cache Configuration:**

1051

1052

```java

1053

@Configuration

1054

@EnableCaching

1055

public class CacheConfig implements CachingConfigurer {

1056

1057

@Bean

1058

@Override

1059

public CacheManager cacheManager() {

1060

ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();

1061

1062

// Pre-configure cache names

1063

cacheManager.setCacheNames(Arrays.asList(

1064

"users", "products", "categories", "orders"

1065

));

1066

1067

cacheManager.setAllowNullValues(false);

1068

return cacheManager;

1069

}

1070

1071

@Bean

1072

@Override

1073

public KeyGenerator keyGenerator() {

1074

return new CustomKeyGenerator();

1075

}

1076

1077

@Bean

1078

@Override

1079

public CacheErrorHandler errorHandler() {

1080

return new LoggingCacheErrorHandler();

1081

}

1082

1083

// Additional cache manager for specific use cases

1084

@Bean("simpleCacheManager")

1085

public CacheManager simpleCacheManager() {

1086

SimpleCacheManager manager = new SimpleCacheManager();

1087

1088

// Create custom caches

1089

List<Cache> caches = new ArrayList<>();

1090

caches.add(new ConcurrentMapCache("temp"));

1091

caches.add(new ConcurrentMapCache("session"));

1092

1093

manager.setCaches(caches);

1094

return manager;

1095

}

1096

}

1097

1098

// Custom key generator

1099

public class CustomKeyGenerator implements KeyGenerator {

1100

1101

@Override

1102

public Object generate(Object target, Method method, Object... params) {

1103

StringBuilder keyBuilder = new StringBuilder();

1104

keyBuilder.append(target.getClass().getSimpleName()).append(".");

1105

keyBuilder.append(method.getName()).append("(");

1106

1107

for (int i = 0; i < params.length; i++) {

1108

if (i > 0) {

1109

keyBuilder.append(",");

1110

}

1111

1112

Object param = params[i];

1113

if (param == null) {

1114

keyBuilder.append("null");

1115

} else if (param instanceof String || param instanceof Number) {

1116

keyBuilder.append(param);

1117

} else {

1118

keyBuilder.append(param.hashCode());

1119

}

1120

}

1121

1122

keyBuilder.append(")");

1123

return keyBuilder.toString();

1124

}

1125

}

1126

```

1127

1128

**Multiple Cache Managers:**

1129

1130

```java

1131

@Configuration

1132

@EnableCaching

1133

public class MultiCacheConfig {

1134

1135

@Bean

1136

@Primary

1137

public CacheManager primaryCacheManager() {

1138

ConcurrentMapCacheManager manager = new ConcurrentMapCacheManager();

1139

manager.setCacheNames(Arrays.asList("users", "products"));

1140

return manager;

1141

}

1142

1143

@Bean("secondaryCacheManager")

1144

public CacheManager secondaryCacheManager() {

1145

ConcurrentMapCacheManager manager = new ConcurrentMapCacheManager();

1146

manager.setCacheNames(Arrays.asList("sessions", "temp"));

1147

manager.setAllowNullValues(true);

1148

return manager;

1149

}

1150

1151

@Bean

1152

public CacheManager compositeCacheManager() {

1153

CompositeCacheManager compositeManager = new CompositeCacheManager();

1154

compositeManager.setCacheManagers(

1155

primaryCacheManager(),

1156

secondaryCacheManager()

1157

);

1158

compositeManager.setFallbackToNoOpCache(true);

1159

return compositeManager;

1160

}

1161

}

1162

1163

@Service

1164

public class MultiCacheService {

1165

1166

// Use primary cache manager

1167

@Cacheable(cacheNames = "users")

1168

public User getUser(Long id) {

1169

return userRepository.findById(id);

1170

}

1171

1172

// Use specific cache manager

1173

@Cacheable(cacheNames = "sessions", cacheManager = "secondaryCacheManager")

1174

public Session getSession(String sessionId) {

1175

return sessionRepository.findById(sessionId);

1176

}

1177

}

1178

```

1179

1180

**Programmatic Cache Usage:**

1181

1182

```java

1183

@Service

1184

public class ProgrammaticCacheService {

1185

1186

@Autowired

1187

private CacheManager cacheManager;

1188

1189

public User getUserWithFallback(Long id) {

1190

Cache userCache = cacheManager.getCache("users");

1191

1192

// Try to get from cache first

1193

Cache.ValueWrapper wrapper = userCache.get(id);

1194

if (wrapper != null) {

1195

return (User) wrapper.get();

1196

}

1197

1198

// Load from database if not in cache

1199

User user = userRepository.findById(id);

1200

1201

// Put in cache for future requests

1202

if (user != null) {

1203

userCache.put(id, user);

1204

}

1205

1206

return user;

1207

}

1208

1209

public void updateUserCache(User user) {

1210

Cache userCache = cacheManager.getCache("users");

1211

1212

// Update cache entry

1213

userCache.put(user.getId(), user);

1214

1215

// Also update related caches

1216

Cache usersByEmailCache = cacheManager.getCache("usersByEmail");

1217

if (usersByEmailCache != null) {

1218

usersByEmailCache.put(user.getEmail(), user);

1219

}

1220

}

1221

1222

public void invalidateUserCaches(Long userId) {

1223

// Evict from multiple caches

1224

cacheManager.getCache("users").evict(userId);

1225

1226

// Clear related caches if needed

1227

Cache statisticsCache = cacheManager.getCache("userStatistics");

1228

if (statisticsCache != null) {

1229

statisticsCache.clear();

1230

}

1231

}

1232

1233

public void warmUpCache() {

1234

Cache userCache = cacheManager.getCache("users");

1235

1236

// Pre-load frequently accessed users

1237

List<User> frequentUsers = userRepository.findFrequentlyAccessed();

1238

for (User user : frequentUsers) {

1239

userCache.put(user.getId(), user);

1240

}

1241

}

1242

}

1243

```