Album ảnh

Cơ chế cache trong Spring framework


https://codersontrang.com/2013/03/04/co-che-cache-trong-spring-framework/

Bài viết này xin được phép giới thiệu với các bạn cách thực hiện cơ chế Cache trong Spring. Cache là cơ chế mà ở đó dữ liệu sẽ được lấy ra từ ổ đĩa (disk) và sau đó được lưu vào trong bộ nhớ (memory) để đảm bảo cho việc truy xuất nhanh hơn trong các lần tái sử dụng về sau. Các dữ liệu được cân nhắc để áp dụng cơ chế cache sẽ là các thông tin hay được sử dụng và có ít sự thay đổi trong quá trình hệ thống vận hành.

Spring cung cấp cho chúng ta một cơ chế cache ở mức phương thức, bằng việc sử dụng annotation trên mỗi phương thức, Spring cho phép kết quả trả về từ phương thức được cache lại trong bộ nhớ cho việc tái sử dụng sau này. Giải thích kĩ hơn một chút chính là phương thức thực tế chỉ thực hiện 1 lần duy nhất ở lần gọi đầu tiên, các lần gọi sau sẽ là kết quả trả về từ cache thay vì việc phương thức lại thực hiện lại và trả về kết quả. Ta sẽ có một ví dụ để minh họa cơ chế này

Trong Elipse IDE tạo một project có cấu trúc thư mục như sau:

codersontrang_springcache_1

Trong ví dụ này ta sẽ sử dụng các thư viện của Spring 3, ngoài ra còn có thư viện của EhCache là một cài đặt để thực hiện cơ chế cache trong Spring. File cấu hình beans.xml lưu các thông tin liên kết các thành phần. File ehcache.xml lưu các thông tin cấu hình cho cơ chế cache. Lớp Repository sẽ có chứa phương thức mà ở đó ta áp dụng cơ chế cache, lớp CacheTest là chương trình sử dụng phương thức từ Repository và ở đó sẽ cho ta thấy được cơ chế cache sẽ xảy ra như thế nào. Cụ thể các file sẽ như sau:

Repository.java


 package codersontrang.cachedemo; 

 import java.util.ArrayList;  
 import java.util.List;  
 import org.springframework.cache.annotation.CacheEvict;  
 import org.springframework.cache.annotation.Cacheable;  

 public class Repository {  

      @Cacheable("nameList")  
      public List<String> getNameList(){  
           System.out.println("Load name list....");  

           List<String> names = new ArrayList<String>();  
           names.add("Nguyen Van A");  
           names.add("Nguyen Van B");  
           names.add("Nguyen Van C");  

           return names;  
      }  

      @CacheEvict("nameList")  
      public void clearCache(){  
           System.out.println("Clear cache named nameList....");  
      }  
 }  

Bằng việc sử dụng annotation, ta có thể điều khiển được việc tạo và xóa cache. @Cacheable("nameList") được đặt bên trên phương thức getNameList() có nghĩa là bất kì khi nào phương thức được gọi ở đâu đó. Hệ thống sẽ kiểm tra xem một cache có tên là nameList đã tồn tại hay chưa, nếu đã tồn tại thì kết quả trả về sẽ được trả về từ cache này thay vì phải thực hiện phương thức. Còn nếu chưa tồn tại, một cache có tên là nameList sẽ được tạo ra, phương thức sẽ được thực hiện và kết quả trả về sẽ được lưu vào trong cache cho các lần sử dụng tiếp sau.

Ngược lại, @CacheEvict("nameList") được đặt trước phương thức clearCache() có nghĩa là bất cứ khi nào phương thức được gọi, cache có tên là nameList sẽ bị xóa bỏ.

beans.xml


  <beans xmlns="http://www.springframework.org/schema/beans"   
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xmlns:cache="http://www.springframework.org/schema/cache"   
  xmlns:p="http://www.springframework.org/schema/p"  
  xsi:schemaLocation=  
                 "http://www.springframework.org/schema/beans
                  http://www.springframework.org/schema/beans/spring-beans.xsd
                  http://www.springframework.org/schema/cache
                  http://www.springframework.org/schema/cache/spring-cache.xsd">  

      <cache:annotation-driven cache-manager="cacheManager" />  
      <bean id="repository" class="codersontrang.cachedemo.Repository"/>  

      <cache:annotation-driven />  
      <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">  
            <property name="cacheManager"><ref local="ehcache"/></property>  
      </bean>  

      <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" 
                            p:configLocation="classpath:ehcache.xml"/>  

 </beans>  

Như thông thường, file beans.xml là nơi khai báo và liên kết các thành phần. Ở đây, hai thành phần quan trọng cần được khởi đạo đó là hai đối tượng của các lớp EhCacheCacheManager EhCacheManagerFactoryBean. Thông tin về cache sẽ được lưu trong file cấu hình có tên là ehcache.xml

ehcache.xml


 <?xml version="1.0" encoding="UTF-8"?>  
 <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
 xsi:noNamespaceSchemaLocation="http://ehcache.sf.net/ehcache.xsd">  

      <diskStore path="java.io.tmpdir" />   
      <defaultCache   
        eternal="false"   
        maxElementsInMemory="1000"  
        overflowToDisk="false"   
        diskPersistent="false"   
        timeToIdleSeconds="0"  
        timeToLiveSeconds="0"   
        memoryStoreEvictionPolicy="LRU"/>  

      <cache name="nameList"  
            maxElementsInMemory="10000"  
            maxElementsOnDisk="1000"  
            eternal="false"  
            overflowToDisk="true"  
            diskSpoolBufferSizeMB="20"  
            timeToIdleSeconds="300"  
            timeToLiveSeconds="600"  
            memoryStoreEvictionPolicy="LFU"  
            />  

 </ehcache>  

File ehcache.xml lưu các thông tin cấu hình về cache, ở đây mỗi một thành phần trong cache sẽ được biểu diễn bởi một thẻ <cache> mà trong đó có các thuộc tính khác nhau liên quan đến thông tin hoặc hành vi mà cơ chế cache sẽ đối xử với thành phần đó.

CacheTest.java


 package codersontrang.cachedemo;  

 import java.util.List;  
 import org.springframework.beans.factory.BeanFactory;  
 import org.springframework.context.ApplicationContext;  
 import org.springframework.context.support.ClassPathXmlApplicationContext;  

 public class CacheTest {  
      public static void main(String [] args){  
           ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");  
           BeanFactory factory = (BeanFactory) context;  
           Repository repository = (Repository) factory.getBean("repository");  

           for(int i =0; i<10;i++){  
                if(i==5){  
                     repository.clearCache();  
                }  
                List<String> names = repository.getNameList();  
                System.out.println("Size: "+names.size());  
           }  
      }  
 }  

Khi chạy chương trình ta nhận được kết quả như hình dưới đây

codersontrang_springcache_2

Như ta đã thấy, ở lần gọi đầu tiên, hàm getNameList() được thực hiện từ đầu đến cuối, chính vì thế mà ta thấy xuất hiện message với nội dung “Load name list....“. Ở các lần lặp tiếp theo, kết quả này của hàm được lấy ra từ cache chứ không phải từ kết quả trả về từ việc thực hiện nội dung hàm, nên hiển nhiên ta cũng không thấy message trên hiện ra. Ở lần lặp thứ 6 (i=5), trước khi gọi hàm getNameList(), ta gọi hàm clearCache() để thực hiện việc xóa các thông tin lưu trữ trong cache có tên là nameList, điều này có thể thấy bằng việc message “Clear cache named nameList....” xuất hiện. Sau khi cache không còn tồn tại nữa, lúc này hàm getNameList() lại được gọi và lại phải thực hiện từ đầu đến cuối, nên ta lại thấy message “Load name list....“, sau bước này, việc lấy kết quả ra từ cache lại được thực hiện ở các vòng lặp tiếp sau.

Bài viết hy vọng cung cấp cho bạn đọc một chút kiến thức liên quan đến Spring caching, hay cụ thể hơn chính là ý tưởng của Spring caching. Còn có rất nhiều tùy biến khác được sử dụng trong cơ chế cache của Spring mà đòi hỏi chúng ta phải tìm tòi trong một khoảng thời gian vừa đủ nào đó mới có thể thấy được bức tranh tổng thể.

Good luck !!!

8 comments on “Cơ chế cache trong Spring framework

  1. Pingback: Spring framework 5 phiên bản mới có gì vui | Coder Sơn Trang

Bình luận về bài viết này