DEV Community

DevInsights Blog
DevInsights Blog

Posted on • Originally published at devinsights.blog on

Introducing JCacheX: a high‑performance Java caching library for modern apps

JCacheX

High‑performance Java caching — profile‑based, from in‑memory to distributed (Kubernetes), with Kotlin DSL and Spring Boot integration.

Getting StartedDocsExamplesBenchmarksStar ★


Why JCacheX?

  • Profile‑based simplicity: one‑liners for common workloads (READ_HEAVY, WRITE_HEAVY, API, SESSION, ZERO_COPY)
  • Production‑ready: async loaders, rich stats, listeners, health/metrics
  • Evolves with you: same API from local in‑memory to distributed on Kubernetes
  • Developer‑friendly: fluent Java API, idiomatic Kotlin DSL, Spring annotations

Deep benchmarks, profiles and trade‑offs are on the website to keep this README focused.


Quick Start


1) Install

Use the latest version from Maven Central (see badge):

<dependency>
  <groupId>io.github.dhruv1110</groupId>
  <artifactId>jcachex-core</artifactId>
  <version>2.0.1</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode
implementation "io.github.dhruv1110:jcachex-core:2.0.1"
Enter fullscreen mode Exit fullscreen mode

Optional modules: jcachex-spring (Spring Boot), jcachex-kotlin (Kotlin DSL).

2) Create a cache (Java)

Cache<String, User> cache = JCacheXBuilder.forReadHeavyWorkload()
    .name("users")
    .maximumSize(1000L)
    .build();

cache.put("user:123", new User("Alice"));
User u = cache.get("user:123");
System.out.println(cache.stats());
Enter fullscreen mode Exit fullscreen mode

3) Kotlin DSL

val users = createReadHeavyCache<String, User> {
    name("users"); maximumSize(1000)
}
users["user:1"] = User("Alice")
println(users.stats().hitRate())
Enter fullscreen mode Exit fullscreen mode

4) Spring Boot (annotations)

@JCacheXCacheable(cacheName = "users", profile = "READ_HEAVY")
public User findUser(String id) { return repo.findById(id); }
Enter fullscreen mode Exit fullscreen mode

More: ExamplesSpring Guide


Distributed on Kubernetes

Same API, pod‑aware discovery and consistent hashing for clusters. See the website’s Kubernetes section and example/distributed/kubernetes.


Links


Comprehensive Usage Examples

Basic Usage

// Simple cache with smart defaults
Cache<String, String> cache = JCacheXBuilder.create()
    .name("simple")
    .maximumSize(100L)
    .build();

cache.put("key1", "value1");
String value = cache.get("key1");
Enter fullscreen mode Exit fullscreen mode

Advanced Configuration

// Custom configuration with async loading
Cache<String, User> userCache = JCacheXBuilder.forReadHeavyWorkload()
    .name("users")
    .maximumSize(1000L)
    .expireAfterWrite(Duration.ofMinutes(30))
    .expireAfterAccess(Duration.ofMinutes(10))
    .loader(userId -> loadUserFromDatabase(userId))
    .recordStats(true)
    .build();
Enter fullscreen mode Exit fullscreen mode

Multi-Language Support

Java

// Profile-based approach
Cache<String, Product> productCache = JCacheXBuilder.fromProfile(ProfileName.READ_HEAVY)
    .name("products")
    .maximumSize(5000L)
    .build();

// Convenience method
Cache<String, UserSession> sessionCache = JCacheXBuilder.forSessionStorage()
    .name("sessions")
    .maximumSize(2000L)
    .build();

// Smart defaults
Cache<String, Order> orderCache = JCacheXBuilder.withSmartDefaults()
    .workloadCharacteristics(WorkloadCharacteristics.builder()
        .readToWriteRatio(6.0)
        .build())
    .build();
Enter fullscreen mode Exit fullscreen mode

Kotlin

// DSL style with convenience methods
val readHeavyCache = createReadHeavyCache<String, Product> {
    name("products")
    maximumSize(5000L)
}

val sessionCache = createSessionCache<String, UserSession> {
    name("sessions")
    maximumSize(2000L)
}

// Profile-based with DSL
val profileCache = createCacheWithProfile<String, Data>(ProfileName.HIGH_PERFORMANCE) {
    name("high-perf")
    maximumSize(10000L)
}
Enter fullscreen mode Exit fullscreen mode

Spring Boot

# application.yml
jcachex:
  caches:
    users:
      profile: READ_HEAVY
      maximumSize: 5000
    sessions:
      profile: SESSION_CACHE
      maximumSize: 2000
    products:
      profile: HIGH_PERFORMANCE
      maximumSize: 10000
Enter fullscreen mode Exit fullscreen mode

Spring Boot with Annotations

@Configuration
@EnableCaching
public class CacheConfig {
    @Bean
    public CacheManager cacheManager() {
        return new JCacheXCacheManager();
    }
}

@Service
public class UserService {

    // JCacheX-specific annotations with profiles
    @JCacheXCacheable(cacheName = "users", profile = "READ_HEAVY")
    public User findUserById(String id) {
        return userRepository.findById(id);
    }

    @JCacheXCacheEvict(cacheName = "users", key = "#user.id")
    public User updateUser(User user) {
        return userRepository.save(user);
    }

    // Standard Spring annotations (also supported)
    @Cacheable("sessions")
    public UserSession createSession(String userId) {
        return new UserSession(userId, System.currentTimeMillis());
    }

    @CacheEvict(value = "sessions", key = "#sessionId")
    public void invalidateSession(String sessionId) {
        sessionRepository.deleteById(sessionId);
    }
}
Enter fullscreen mode Exit fullscreen mode

🌱 Spring Boot Annotation-Based Usage

Basic Setup

Add the JCacheX Spring Boot starter:

<dependency>
    <groupId>io.github.dhruv1110</groupId>
    <artifactId>jcachex-spring</artifactId>
    <version>2.0.1</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Configuration

@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public CacheManager cacheManager() {
        return new JCacheXCacheManager();
    }
}
Enter fullscreen mode Exit fullscreen mode

JCacheX-Specific Annotations

@JCacheXCacheable - Advanced Caching

@Service
public class UserService {

    // Profile-based caching with automatic optimization
    @JCacheXCacheable(cacheName = "users", profile = "READ_HEAVY")
    public User findUserById(String id) {
        return userRepository.findById(id);
    }

    // Custom expiration and size limits
    @JCacheXCacheable(
        cacheName = "userProfiles",
        expireAfterWrite = 30,
        expireAfterWriteUnit = TimeUnit.MINUTES,
        maximumSize = 5000
    )
    public UserProfile getUserProfile(String userId) {
        return buildUserProfile(userId);
    }

    // Conditional caching with custom keys
    @JCacheXCacheable(
        cacheName = "apiResponses",
        key = "#endpoint + '_' + #version",
        condition = "#cacheable == true",
        unless = "#result.isEmpty()"
    )
    public ApiResponse callApi(String endpoint, String version, boolean cacheable) {
        return httpClient.get(endpoint + "?v=" + version);
    }

    // Session-optimized caching
    @JCacheXCacheable(
        cacheName = "userSessions",
        profile = "SESSION_CACHE",
        expireAfterWrite = 30,
        expireAfterWriteUnit = TimeUnit.MINUTES
    )
    public UserSession createSession(String userId) {
        return new UserSession(userId, System.currentTimeMillis());
    }
}
Enter fullscreen mode Exit fullscreen mode

@JCacheXCacheEvict - Advanced Eviction

@Service
public class UserService {

    // Evict specific user
    @JCacheXCacheEvict(cacheName = "users", key = "#user.id")
    public User updateUser(User user) {
        return userRepository.save(user);
    }

    // Evict multiple related caches
    @JCacheXCacheEvict(cacheName = "users", key = "#userId")
    @JCacheXCacheEvict(cacheName = "userProfiles", key = "#userId")
    @JCacheXCacheEvict(cacheName = "userPermissions", key = "#userId")
    public void deleteUser(String userId) {
        userRepository.deleteById(userId);
    }

    // Conditional eviction
    @JCacheXCacheEvict(
        cacheName = "userStats",
        condition = "#user.isActive()",
        key = "#user.id"
    )
    public void updateUserActivity(User user) {
        userRepository.updateLastActivity(user.getId());
    }

    // Clear entire cache
    @JCacheXCacheEvict(cacheName = "temporaryData", allEntries = true)
    @Scheduled(fixedRate = 3600000) // Every hour
    public void clearTemporaryCache() {
        logger.info("Cleared temporary cache");
    }

    // Evict before method execution (for consistency)
    @JCacheXCacheEvict(
        cacheName = "criticalData",
        beforeInvocation = true,
        key = "#dataId"
    )
    public void updateCriticalData(String dataId, CriticalData data) {
        dataRepository.save(data);
    }
}
Enter fullscreen mode Exit fullscreen mode

Profile-Based Configuration

@Service
public class ProductService {

    // Ultra-high performance for read-heavy workloads
    @JCacheXCacheable(cacheName = "products", profile = "READ_HEAVY")
    public Product getProduct(String id) {
        return productRepository.findById(id);
    }

    // Memory-efficient for large datasets
    @JCacheXCacheable(cacheName = "reports", profile = "MEMORY_EFFICIENT")
    public Report generateReport(String reportId) {
        return reportGenerator.generate(reportId);
    }

    // API response optimization
    @JCacheXCacheable(
        cacheName = "apiData",
        profile = "API_CACHE",
        expireAfterWrite = 15,
        expireAfterWriteUnit = TimeUnit.MINUTES
    )
    public ApiResponse getApiData(String endpoint) {
        return apiClient.call(endpoint);
    }

    // Machine learning workload optimization
    @JCacheXCacheable(cacheName = "mlPredictions", profile = "ML_OPTIMIZED")
    public PredictionResult predict(String modelId, InputData data) {
        return mlService.predict(modelId, data);
    }
}
Enter fullscreen mode Exit fullscreen mode

Application Properties Integration

# application.yml
jcachex:
  default:
    maximumSize: 1000
    expireAfterSeconds: 1800
    enableStatistics: true

  profiles:
    users: READ_HEAVY
    sessions: SESSION_CACHE
    products: HIGH_PERFORMANCE
    reports: MEMORY_EFFICIENT

  caches:
    users:
      profile: READ_HEAVY
      maximumSize: 5000
      expireAfterSeconds: 3600

    userProfiles:
      profile: READ_HEAVY
      maximumSize: 2000
      expireAfterSeconds: 1800

    apiResponses:
      profile: API_CACHE
      maximumSize: 1000
      expireAfterSeconds: 900

    mlPredictions:
      profile: ML_OPTIMIZED
      maximumSize: 500
      expireAfterSeconds: 7200
Enter fullscreen mode Exit fullscreen mode

Spring Boot Auto-Configuration

@SpringBootApplication
@EnableCaching
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// JCacheX auto-configuration handles:
// - Automatic CacheManager creation
// - Profile-based cache optimization
// - Metrics integration
// - Health check endpoints
Enter fullscreen mode Exit fullscreen mode

Testing Annotation-Based Caching

@SpringBootTest
@TestProfile("test")
class UserServiceTest {

    @Autowired
    private UserService userService;

    @Autowired
    private CacheManager cacheManager;

    @Test
    void testCacheableBehavior() {
        // First call - should hit database
        User user1 = userService.findUserById("123");
        verify(userRepository).findById("123");

        // Second call - should use cache
        User user2 = userService.findUserById("123");
        verifyNoMoreInteractions(userRepository);

        assertEquals(user1, user2);
    }

    @Test
    void testCacheEviction() {
        // Cache user
        User user = userService.findUserById("123");

        // Update user (should evict cache)
        user.setName("Updated Name");
        userService.updateUser(user);

        // Next call should hit database again
        User updatedUser = userService.findUserById("123");
        verify(userRepository, times(2)).findById("123");
    }
}
Enter fullscreen mode Exit fullscreen mode

REST Controller Integration

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable String id) {
        User user = userService.findUserById(id); // Cached automatically
        return ResponseEntity.ok(user);
    }

    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable String id, @RequestBody User user) {
        User updated = userService.updateUser(user); // Evicts cache automatically
        return ResponseEntity.ok(updated);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable String id) {
        userService.deleteUser(id); // Evicts multiple caches
        return ResponseEntity.noContent().build();
    }
}
Enter fullscreen mode Exit fullscreen mode

Performance Optimized Examples

Ultra-Low Latency

// Zero-copy optimized for HFT
Cache<String, MarketData> marketData = JCacheXBuilder.forUltraLowLatency()
    .name("market-data")
    .maximumSize(100000L)
    .build();
Enter fullscreen mode Exit fullscreen mode

Memory Constrained

// Optimized for limited memory
Cache<String, Config> configCache = JCacheXBuilder.forMemoryConstrainedEnvironment()
    .name("config")
    .maximumSize(50L)
    .build();
Enter fullscreen mode Exit fullscreen mode

Machine Learning

// ML workload optimization
Cache<String, ModelResult> mlCache = JCacheXBuilder.forMachineLearning()
    .name("ml-predictions")
    .maximumSize(1000L)
    .build();
Enter fullscreen mode Exit fullscreen mode

All 12 Convenience Methods

JCacheX provides one-liner cache creation for all common use cases:

// Core profiles
JCacheXBuilder.create()                          // Default profile
JCacheXBuilder.forReadHeavyWorkload()           // 80%+ reads
JCacheXBuilder.forWriteHeavyWorkload()          // 50%+ writes
JCacheXBuilder.forMemoryConstrainedEnvironment() // Limited memory
JCacheXBuilder.forHighPerformance()             // Maximum throughput

// Specialized profiles
JCacheXBuilder.forSessionStorage()              // User sessions
JCacheXBuilder.forApiResponseCaching()          // External APIs
JCacheXBuilder.forComputationCaching()          // Expensive computations

// Advanced profiles
JCacheXBuilder.forMachineLearning()             // ML workloads
JCacheXBuilder.forUltraLowLatency()            // HFT/Gaming
JCacheXBuilder.forHardwareOptimization()        // CPU-intensive
JCacheXBuilder.forDistributedCaching()          // Multi-node
Enter fullscreen mode Exit fullscreen mode

Module Structure

jcachex/
├── jcachex-core/        # Core caching functionality
├── jcachex-kotlin/      # Kotlin extensions and DSL
├── jcachex-spring/      # Spring Boot integration
└── examples/            # Comprehensive examples
    ├── java/           # Java examples
    ├── kotlin/         # Kotlin examples
    └── springboot/     # Spring Boot examples
Enter fullscreen mode Exit fullscreen mode

Getting Started

Installation

Maven

<dependency>
    <groupId>io.github.dhruv1110</groupId>
    <artifactId>jcachex-core</artifactId>
    <version>2.0.1</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Gradle

implementation 'io.github.dhruv1110:jcachex-core:2.0.1'
Enter fullscreen mode Exit fullscreen mode

Hello World Example

import io.github.dhruv1110.jcachex.JCacheXBuilder;

public class HelloJCacheX {
    public static void main(String[] args) {
        // Create cache with one line
        var cache = JCacheXBuilder.forReadHeavyWorkload()
            .name("hello").maximumSize(1000L).build();

        // Use it
        cache.put("hello", "world");
        System.out.println(cache.get("hello")); // "world"

        // Check performance
        System.out.println("Hit rate: " + cache.stats().hitRate() * 100 + "%");
    }
}
Enter fullscreen mode Exit fullscreen mode

Advanced Features

Distributed Caching

// Distributed cache with automatic failover
Cache<String, User> distributedCache = JCacheXBuilder.forDistributedCaching()
    .name("users")
    .maximumSize(5000L)
    .build();
Enter fullscreen mode Exit fullscreen mode

Async Operations

// Async loading with CompletableFuture
Cache<String, Data> asyncCache = JCacheXBuilder.forHighPerformance()
    .asyncLoader(key -> CompletableFuture.supplyAsync(() -> loadData(key)))
    .build();
Enter fullscreen mode Exit fullscreen mode

Event Listeners

// Monitor cache events
Cache<String, User> monitoredCache = JCacheXBuilder.forReadHeavyWorkload()
    .listener(new CacheEventListener<String, User>() {
        @Override
        public void onEvict(String key, User value, EvictionReason reason) {
            System.out.println("Evicted: " + key + " due to " + reason);
        }
    })
    .build();
Enter fullscreen mode Exit fullscreen mode

Documentation


Contributing

We welcome contributions! Please see our Contributing Guide for details.


License

This project is licensed under the MIT License - see the LICENSE file for details.


Support

Top comments (0)