Spring Boot Ehcache Caching | In-Memory Cache | Redis වෙනුවට SC Guide

Spring Boot Ehcache Caching | In-Memory Cache | Redis වෙනුවට SC Guide

Spring Boot Caching with Ehcache: ඔබේ Application එක Flying Star එකක් වගේ දුවවමු!

ආයුබෝවන් යාළුවනේ! කොහොමද ඉතින්? අද අපි කතා කරන්න යන්නේ ගොඩක් වැදගත් මාතෘකාවක් ගැන. අපි software applications develop කරනකොට හැම වෙලාවෙම හිතන දෙයක් තමයි, "අපේ application එක ටිකක් slow වගේ නේද?" කියලා. Users ලා කැමති නෑනේ slow application වලට. ඉක්මනට response ඕනේ එයාලට. ඉතින් මේකට තියෙන සුපිරි විසඳුමක් තමයි Caching කියන්නේ.

ඔයාලා සමහරවිට Redis, Memcached වගේ external caching solutions පාවිච්චි කරලා ඇති. ඒවා සුපිරි tools තමයි, හැබැයි පොඩි applications වලට, නැත්නම් single instance applications වලට, Redis server එකක් set up කරලා maintain කරන එක පොඩි වැඩක් නෙවෙයි. ටිකක් overhead වැඩියි වගේ දැනෙන්න පුළුවන්. එහෙමනම්, Redis වගේ external dependency එකක් නැතුව, lightweight විදියට, අපේ application එක ඇතුලෙන්ම data cache කරගන්න පුළුවන් සුපිරි tool එකක් ගැන දැනගන්න කැමතිද? ඔව්, අපි අද කතා කරන්නේ Ehcache ගැන! Spring Boot application එකක් ඇතුලටම Ehcache එක configure කරලා, performance boost කරගන්න හැටි, අපි අද විස්තරාත්මකව බලමු. විශේෂයෙන්ම, Redis වලට හොඳ lightweight විකල්පයක් විදියට Ehcache කොහොමද පාවිච්චි කරන්නේ කියලත් අපි බලමු.

Caching ඇයි වැදගත් වෙන්නේ?

හිතන්නකෝ, ඔයාගේ application එකක product details load කරනවා කියලා. හැම වෙලාවෙම user කෙනෙක් product page එකට යනකොට database එකට ගිහින් data අරන් එන්න ඕනේ නේද? එක සැරයක් දෙපාරක් නම් අවුලක් නෑ, හැබැයි users ලා දහස් ගානක් එකම වෙලාවේ එකම product details ඉල්ලනකොට database එකට ලොකු load එකක් එනවා. ඒ විතරක් නෙවෙයි, database එකෙන් data අරන් එන්නත් යම්කිසි කාලයක් ගතවෙනවා. මේක තමයි performance bottleneck වෙන්නේ.

Caching කියන්නේ මේකට තියෙන Smart Solution එක. අපි මොකද කරන්නේ, database එකෙන් අරන් ආපු data ටිකක් වෙලාවකට අපේ application එකේ memory එකේ තියාගන්නවා (ඔලුවේ තියාගන්නවා වගේ වැඩක්). ඊළඟ වතාවේ කවුරුහරි ඒ data ටිකම ඉල්ලුවොත්, ආයේ database එකට යන්නේ නැතුව, memory එකේ තියාගත්තු data ටික දීලා දානවා. හිතන්නකෝ, කොච්චර වේගවත්ද කියලා! Database load එක අඩු වෙනවා, response time එකත් පිස්සු වගේ වැඩි වෙනවා.

සරලවම කියනවා නම්, caching කියන්නේ “ඉස්සරලාම අහපු ප්‍රශ්නෙට උත්තරේ මතක තියාගෙන, ආයේ අහනකොට ඉක්මනට උත්තර දෙන එක” වගේ වැඩක්. මේකෙන් ඔයාගේ application එක users ලාට හරිම smooth experience එකක් දෙනවා.

Ehcache කියන්නේ මොකක්ද?

Ehcache කියන්නේ open-source, standards-based, Java application වලට ගොඩක්ම ගැලපෙන in-process cache එකක්. "In-process cache" කියන්නේ මොකක්ද? ඒ කියන්නේ, මේ cache එක ඔයාගේ application එක ඇතුලෙන්ම, ඒකේම memory එක ඇතුලෙන්ම operate වෙනවා කියන එක. ඒකට වෙනම server එකක්, container එකක්, නැත්නම් process එකක් ඕනේ නෑ. ඒක තමයි Ehcache වල ලොකුම වාසියක්!

Benefits ටිකක් බැලුවොත්:

  • Simple and Fast: Setup කරන්න, පාවිච්චි කරන්න හරිම ලේසියි, වේගවත්.
  • Embedded: Application එක ඇතුලෙන්ම තියෙන නිසා external dependencies අඩුයි.
  • Good for Single-Instance Apps: ඔයාගේ application එක එක server එකක විතරක් run වෙනවා නම්, Ehcache සුපිරි choice එකක්. (Distributed systems වලට එච්චර හොඳ නෑ, මොකද cache එක share වෙන්නේ නෑනේ instances අතර).
  • Lightweight: Memory footprint එක අඩුයි.

Redis වගේ distributed cache එකක් එක්ක බලද්දී Ehcache වෙනස් වෙන්නේ, Ehcache කියන්නේ application එකේ JVM එක ඇතුලේම තියෙන cache එකක් නිසා. ඒ කියන්නේ, ඔයාට complex setup, networking, security, data consistency across multiple nodes වගේ දේවල් ගැන කරදර වෙන්න ඕනේ නෑ. පොඩි applications වලට, නැත්නම් database calls අඩු කරගන්න ඕනේ තැන් වලට, Ehcache කියන්නේ නියම විසඳුමක්. Redis container එකක් දාලා, config කරන්න ඕනෙ නෑ!

Spring Boot එකට Ehcache ගලපගමු

හරි, දැන් අපි ප්‍රායෝගිකව වැඩේට බහිමු. Spring Boot application එකකට Ehcache configure කරලා, පාවිච්චි කරන්නේ කොහොමද කියලා අපි step-by-step බලමු.

Step 1: Dependencies එකතු කරමු

මුලින්ම ඔයාගේ pom.xml file එකට Ehcache සහ Spring Boot Cache starter dependencies එකතු කරන්න ඕනේ. මේවා තමයි අපිට caching functionality එකයි, Ehcache library එකයි දෙන්නේ.

<dependencies>
    <!-- Spring Boot Cache Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>

    <!-- Ehcache Core -->
    <dependency>
        <groupId>org.ehcache</groupId>
        <artifactId>ehcache</artifactId>
        <version>3.10.8</version> <!-- Replace with the latest stable version -->
    </dependency>

    <!-- JSR-107 Annotations (Optional, but good practice) -->
    <dependency>
        <groupId>javax.cache</groupId>
        <artifactId>cache-api</artifactId>
    </dependency>
</dependencies>

ehcache version එක දානකොට ඔයාලා ලේටස්ට් stable version එක බලලා දාගන්න පුරුදු වෙන්න.

Step 2: Caching Enable කරමු

ඊළඟට, ඔයාගේ Spring Boot main application class එකේ @EnableCaching annotation එක add කරන්න ඕනේ. මේකෙන් තමයි Spring framework එකට කියන්නේ, "හලෝ, මේ application එකේ caching functionality එක use කරන්න ඕනේ හොඳේ" කියලා.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching
public class EhcacheDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(EhcacheDemoApplication.class, args);
    }
}

Step 3: Ehcache Configuration එක ලියමු

Ehcache configure කරන්න ක්‍රම දෙකක් තියෙනවා: XML file එකක් පාවිච්චි කරන එක නැත්නම් Java code එකෙන් configure කරන එක. අපි මෙතනදී XML file එකක් පාවිච්චි කරන එක බලමු, ඒක ගොඩක් වෙලාවට ලේසියි.

ඔයාගේ src/main/resources folder එක ඇතුලට ehcache.xml කියලා file එකක් හදන්න. මේ file එකේ තමයි අපි cache වල behavior එක define කරන්නේ. උදාහරණයක් විදියට, cache එකේ නම, cache එකේ තියාගන්න පුළුවන් entries ගාන, data එක cache එකේ තියාගන්න පුළුවන් කාලය වගේ දේවල් මෙතනදී specify කරනවා.

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd"
         updateCheck="false" monitoring="autodetect"
         dynamicConfig="true">

    <cache alias="products">
        <heap unit="entries">1000</heap> <!-- Maximum 1000 entries in heap -->
        <expiry>
            <ttl unit="seconds">300</ttl> <!-- Time to live 300 seconds (5 minutes) -->
        </expiry>
    </cache>

    <cache alias="users">
        <heap unit="entries">500</heap> <!-- Maximum 500 entries in heap -->
        <expiry>
            <ttl unit="seconds">600</ttl> <!-- Time to live 600 seconds (10 minutes) -->
        </expiry&n>
    </cache>

    <!-- You can define more caches as needed -->

</ehcache>

මේ ehcache.xml file එකේ <cache alias="products"> කියන තැනින් අපි products කියලා cache එකක් define කරනවා. ඒකේ <heap unit="entries">1000</heap> කියන්නේ memory එකේ entry 1000ක් තියාගන්න පුළුවන් කියලා. <ttl unit="seconds">300</ttl> කියන්නේ, data එක cache එකේ තියාගන්න පුළුවන් උපරිම කාලය තත්පර 300යි (විනාඩි 5යි) කියන එක. මේ විදියට users cache එකකුත් අපි define කරලා තියෙනවා.

ඊළඟට, Spring Boot එකට කියන්න ඕනේ ehcache.xml file එක කොහෙන්ද හොයාගන්නේ කියලා. ඒකට ඔයාගේ application.properties file එකට මේ line එක add කරන්න:

spring.cache.jcache.config=classpath:ehcache.xml

Step 4: Service layer එකේ Cache එක පාවිච්චි කරමු

දැන් තමයි වැදගත්ම කොටස! අපි service layer එකේ අපේ methods වලට Caching Annotations එකතු කරමු. Spring Framework එකේ Caching සඳහා Annotations කිහිපයක් තියෙනවා:

  • @Cacheable: method එකේ return value එක cache කරන්න. ඊළඟ වතාවේ මේ method එකම call කරනකොට cache එකෙන් data return කරනවා.
  • @CacheEvict: cache එකෙන් data remove කරන්න. යම්කිසි update එකක් කරාම පරණ cache එක invalid කරන්න මේක පාවිච්චි කරනවා.
  • @CachePut: method එක execute කරලා, ඒකේ return value එක cache එකට update කරන්න.

හිතන්නකෝ ඔයාට ProductService එකක් තියෙනවා කියලා:

import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Service
@CacheConfig(cacheNames = "products") // Default cache name for this service
public class ProductService {

    private List<Product> products = new ArrayList<>(); // Simulate a data store

    public ProductService() {
        products.add(new Product(1L, "Laptop", 1200.00));
        products.add(new Product(2L, "Mouse", 25.00));
        products.add(new Product(3L, "Keyboard", 75.00));
    }

    @Cacheable(key = "#id")
    public Optional<Product> getProductById(Long id) {
        System.out.println("Fetching product from database for ID: " + id); // Simulate DB call
        try {
            TimeUnit.SECONDS.sleep(2); // Simulate network/DB latency
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return products.stream()
                .filter(p -> p.getId().equals(id))
                .findFirst();
    }

    @CachePut(key = "#product.id")
    public Product updateProduct(Product product) {
        System.out.println("Updating product in database: " + product.getId());
        products.stream()
                .filter(p -> p.getId().equals(product.getId()))
                .findFirst()
                .ifPresent(p -> {
                    p.setName(product.getName());
                    p.setPrice(product.getPrice());
                });
        return product;
    }

    @CacheEvict(key = "#id")
    public void deleteProduct(Long id) {
        System.out.println("Deleting product from database: " + id);
        products.removeIf(p -> p.getId().equals(id));
    }

    // Dummy Product class for demonstration
    public static class Product {
        private Long id;
        private String name;
        private double price;

        public Product(Long id, String name, double price) {
            this.id = id;
            this.name = name;
            this.price = price;
        }

        // Getters and Setters
        public Long getId() { return id; }
        public void setId(Long id) { this.id = id; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public double getPrice() { return price; }
        public void setPrice(double price) { this.price = price; }

        @Override
        public String toString() {
            return "Product{" +
                   "id=" + id +
                   ", name='" + name + '\'' +
                   ", price=" + price +
                   '}';
        }
    }
}

මේ ProductService එකේ අපි වැදගත් දේවල් කීපයක් කරලා තියෙනවා:

  • @CacheConfig(cacheNames = "products"): මේකෙන් කියන්නේ මේ Service එකේ හැම Caching annotation එකකටම default cache එක විදියට ehcache.xml එකේ define කරපු products cache එක පාවිච්චි කරන්න කියලා.
  • getProductById method එකට @Cacheable(key = "#id") දාලා තියෙනවා. ඒ කියන්නේ, මේ method එක call කරනකොට, id එක key එක විදියට පාවිච්චි කරලා, return වෙන Product object එක cache එකේ තියාගන්නවා. ඊළඟ වතාවේ එකම id එකට request එකක් ආවොත්, method එක execute වෙන්නේ නැතුව, cache එකෙන් data එක දෙනවා. System.out.println එකයි TimeUnit.SECONDS.sleep(2) එකයි දාලා තියෙන්නේ database call එකක් simulate කරන්න.
  • updateProduct method එකට @CachePut(key = "#product.id") දාලා තියෙනවා. මේකෙන් වෙන්නේ, product එක update කරලා ඉවර වුණාම, අලුත් product object එක අදාල key එකට cache එකේ update වෙන එක. මේක @Cacheable වගේ නෙවෙයි, method එක හැමවෙලාවෙම execute වෙනවා.
  • deleteProduct method එකට @CacheEvict(key = "#id") දාලා තියෙනවා. මේකෙන් වෙන්නේ, අදාල ID එකට අදාළව cache එකේ තියෙන entry එක remove කරන එක. Product එකක් delete කරාම, cache එකේ පරණ data තියෙන එක තේරුමක් නෑනේ.

දැන් ඔබට පුළුවන් controller එකකින් මේ ProductService එක call කරලා Caching වැඩ කරනවද කියලා බලන්න. මුලින්ම Product එකක් request කරනකොට "Fetching product from database..." කියලා print වෙලා තත්පර 2ක් වගේ වෙලාවක් යයි. දෙවෙනි වතාවට request කරනකොට ඒ message එක print වෙන්නේ නෑ, මොකද cache එකෙන් data එන නිසා. Instant response එකක් ලැබෙයි!

Redis වෙනුවට Ehcache පාවිච්චි කරන එක කොහොමද?

මෙන්න මේක තමයි කතාවේ වැදගත්ම තැන. ඔයාලා දැනටමත් Spring Boot application එකක Redis caching පාවිච්චි කරනවා නම්, Ehcache වලට මාරුවෙන එක හරිම ලේසියි. කොහොමද දන්නවද?

  1. Dependencies වෙනස් කිරීම: ඔයාගේ pom.xml file එකෙන් Redis dependencies අයින් කරලා, අපි උඩ දැක්ක Ehcache dependencies ටික add කරන්න.
  2. Configuration වෙනස් කිරීම: application.properties නැත්නම් application.yml file එකේ Redis configuration (e.g., spring.redis.host) අයින් කරලා, Ehcache configuration එක (spring.cache.jcache.config=classpath:ehcache.xml) add කරන්න.
  3. XML Configuration: ehcache.xml file එක හදලා, ඔයාගේ cache definitions ටික ඒක ඇතුලට දාන්න.

වැදගත්ම දේ තමයි, ඔයාගේ service layer එකේ පාවිච්චි කරන @Cacheable, @CacheEvict, @CachePut වගේ annotations වෙනස් කරන්න ඕනේ නෑ! Spring Framework එකේ Caching abstraction එකේ තියෙන ලස්සන ඒක. ඔයා යටින් Redis පාවිච්චි කරනවද, Ehcache පාවිච්චි කරනවද කියලා service layer එකට අදාළ නෑ. ඒක Spring Boot cache starter එක බලාගන්නවා. ඒකයි "Redis නැතුව පුළුවන්" කිව්වේ.

ඉතින්, ඔයාගේ application එක distributed caching එකක් (server instances කීපයක් අතර data share කරන්න ඕනේ නම්) අවශ්‍ය නැතිනම්, Ehcache කියන්නේ Redis වලට හොඳ lightweight විකල්පයක්. විශේෂයෙන්ම Dev environment වලදී, ඉක්මනට caching test කරගන්න ඕනේ නම්, Ehcache සුපිරි විසඳුමක්. Redis container එකක් run කරන්න ඕනේ නෑ, network configuration, port mapping වගේ දේවල් ගැන හිතන්න ඕනේ නෑ. Just add the dependency, configure ehcache.xml, and you are good to go!

මතක තියාගන්න ඕන දේවල්

Ehcache පාවිච්චි කරනකොට මේ දේවල් පොඩ්ඩක් මතක තියාගන්න:

  • In-Memory Cache: Ehcache කියන්නේ in-memory cache එකක්. ඒ කියන්නේ ඔයාගේ application එක restart කරොත්, cache එකේ තියෙන data ඔක්කොම නැතිවෙලා යනවා. Persistent caching ඕනේ නම් Ehcache නෙවෙයි විසඳුම.
  • Not for Distributed Caching: ඔයාගේ application එක instances කීපයක run වෙනවා නම්, එක instance එකක cache කරපු data, අනිත් instances වලට access කරන්න බෑ. ඒ වගේ වෙලාවට Redis, Hazelcast වගේ distributed caching solutions තමයි පාවිච්චි කරන්න ඕනේ.
  • Cache Eviction Policies: cache එක පිරෙනකොට මොකද වෙන්නේ කියලා දැනගන්න. Least Recently Used (LRU), Least Frequently Used (LFU), First In First Out (FIFO) වගේ policies ගැන පොඩ්ඩක් හොයලා බලන්න. Ehcache by default LRU use කරනවා.
  • Cache Size: Cache එකට කොච්චර memory එකක් වෙන් කරනවද කියන එකත් වැදගත්. ගොඩක් විශාල memory එකක් වෙන් කරොත් application එකේ performance එකට බලපෑම් කරන්න පුළුවන්.
  • Monitoring: Cache hit / miss rates වගේ දේවල් monitor කරන එක වැදගත්. ඒකෙන් ඔයාට cache එක කොච්චර effectively වැඩ කරනවද කියලා බලන්න පුළුවන්.

අවසන් වශයෙන්

අද අපි Spring Boot application එකක් ඇතුලේ Ehcache configure කරලා, performance boost කරගන්න හැටි ඉගෙනගත්තා. Database load එක අඩු කරගෙන, response times වැඩි කරගන්න Ehcache කොච්චර ප්‍රයෝජනවත්ද කියලා දැන් ඔයාලට තේරෙනවා ඇති. Redis වගේ external service එකක් නැතුව, lightweight විදියට cache කරන්න ඕනේ නම් Ehcache කියන්නේ නියම තෝරාගැනීමක්. හැබැයි ඔයාගේ use case එකට ගැලපෙන cache type එක තෝරාගන්න එක තමයි වැදගත්ම දේ.

ඉතින්, දැන් ඔයාලටත් පුළුවන් ඔයාලගේ Spring Boot applications වලට Ehcache add කරලා, ඒවාට rocket engines වගේ වේගයක් දෙන්න! මේ concepts ටික ඔයාලාගේ project එකකට add කරලා බලන්න. මොනවා හරි ප්‍රශ්න තියෙනවා නම්, ඔයාලගේ අදහස්, ප්‍රශ්න පහළින් comment කරන්න. මට පුළුවන් විදියට උදව් කරන්නම්. ඊළඟ පෝස්ට් එකෙන් හමුවෙමු!