μ€νλ§ μΊμμ λν΄μ κ³ λ―Όν΄λ³΄μ
μ€νλ§ νλ μμν¬ κΈ°λ°μ μ ν리μΌμ΄μ μ μΊμ μΆμνλ₯Ό μ 곡νμ¬ μΊμ κ΄λ ¨ λͺ¨λμ λν μμ‘΄μ±μ μΆκ°νκ³ @EnableCachingκ³Ό κ°μ μ΄λ Έν μ΄μ μΌλ‘ μ μΈμ μΊμλ₯Ό κ°λ¨νκ² μ μ©ν μ μμ΅λλ€. μ€νλ§μ λ€λ£¨λ λ§μ κ°λ°μλ€μ΄ μΌλΆ λΉμ¦λμ€ λ‘μ§μ μ±λ₯ ν₯μμ μν΄μ μμ£Ό μ¬μ©λκ² μ§λ§ μκ°λ³΄λ€ λμ μ΄ κ°λ¨ν μ μΌλ‘ μΈν΄ μ¬λ¬κ°μ§ λΆλΆλ€μ μ κ²½μ°μ§ μκ³ μ¬μ©νκ³ μμ κ°λ₯μ±μ΄ λλ€κ³ μκ°ν©λλ€. κ°μΈμ μΈ κ²½νμ ν λλ‘ μ€νλ§ μΊμλ₯Ό νμ©νλ κ²½μ°μ μ΄λ€ λΆλΆλ€μ κ³ λ―Όνλ©΄ μ’μμ§ λ€λ£¨μ΄λ³΄κ³ μ ν©λλ€.
μΊμ νλ‘λ°μ΄λμ λ€μν μΊμ μ λ΅μ κ²ν ν΄μΌ
applicaiton.ymlspring.cache: type: caffeine caffeine.spec: maximumSize=1000,expireAfterAccess=PT5M cache-names: category, book
λ¨μΌ μΈμ€ν΄μ€λ‘ μ΄μ©λλ μ ν리μΌμ΄μ μμλ λ λμ€μ κ°μ μΈλΆ λ©λͺ¨λ¦¬ μ μ₯μλ₯Ό μμ‘΄νκΈ°λ νλλ° μ€μΌμΌ μμμ΄ λμ§ μμ κ°λ₯μ±μ΄ λλ€λ©΄ μ°¨λΌλ¦¬ Caffeine κ³Ό κ°μ λ‘컬 μΊμ νλ‘λ°μ΄λλ₯Ό μ ννκ³ νλ‘λ°μ΄λλ§λ€ μ μ©ν μ μλ λ€μν μΊμ μ λ΅μ κ²ν νλ κ²μ΄ μ’μ΅λλ€. Caffeineμ λμ νλλΌλ κΈ°λ³Έ μμ μμ μκ°λλ CaffeineSpecμ κ°λ° μ λΏλ§ μλλΌ μ΄μνκ²½μμ κ·Έλλ‘ μ¬μ©ν κ°λ₯μ±λ λμ΅λλ€. λν, μΊμλ§λ€ ν¨μ¨μ μΈ μ λ΅μ΄ λ€μνλ―λ‘ μ€νλ§ λΆνΈ μλ μ€μ μ μν λ¨μΌ μ λ΅λ³΄λ€λ μΊμ λ³ μ λ΅μ λ³λλ‘ μ¬μ©νλλ‘ μ§μ ꡬμ±νλκ² μ’μ κ² κ°μ΅λλ€.
@Cacheable ν€ κ΅¬μ±μ νμΈν΄μΌ
applicaiton.ymllogging.level.org.springframework.cache: trace
κΈ°λ³Έμ μΌλ‘ CacheInterceptorμ λν λ‘κ·Έ λ 벨μ TRACEλ‘ μ§μ ν΄λμ§ μκΈ° λλ¬Έμ @Cacheableμ μ μν ν€μ λν΄μ κ²ν νμ§ μκ³ μΊμλλμ§ μ¬λΆλ§ νμΈνμ¬ μλͺ»λ ν€λ‘ μΊμλμ΄λ 무μλκ³ μμ κ°λ₯μ±μ΄ λμ΅λλ€. λν, μ£Όλ‘ ν€λ₯Ό ꡬμ±ν λ #root.methodName λ§ μ¬μ©ν΄λ²λ¦¬λ©΄ ν€ μ€λ³΅ λ°μμ΄ λμμ§κ³ ClassCastExceptionμ΄ λ°μν μ μλλ° λ€μκ³Ό κ°μ΄ νμ μλΉμ€ ν΄λμ€ μ΄λ¦λ ν€ κ΅¬μ±μ ν¬ν¨νλ κ²μ μΆμ²ν©λλ€. λν, ν€ μ μ μ μ¬μ©ν΄μΌν νλΌλ―Έν° μκ° λ§λ€λ©΄ λμ΄νκΈ° 보λ€λ KeyGenerator μΈν°νμ΄μ€ ꡬν체λ₯Ό λ§λ€μ΄μ μ¬μ©νλ κ²μ΄ λ κ°λ¨ν©λλ€.
@Cacheable(cacheNames = "[cache-name]", key = "T(String).join(':', #root.targetClass.simpleName, #root.methodName)")
μΊμμ λν ν€ μ μ μ μ€λ³΅μ λν λΆλΆμ λ°νμ μμΈλ‘ λ°μνκΈ° λλ¬Έμ μ¬μ μ μΈμ§νκΈ° μ΄λ €μ΄ λΆλΆμ΄κΈ° λλ¬Έμ μ£Όμν΄μΌν λΆλΆμ λλ€.
@CacheEvict μμ μ 체 μμ λ₯Ό ν΄μΌν κΉ
@CacheEvict(cacheNames="[cache-name]", allEntries = true)
μ°λ¦¬κ° μΊμλμ΄μ§ μΌλΆ λ°μ΄ν°κ° κ°±μ λμ΄μΌν λ @CacheEvictμ ν¨κ» allEntries μμ±μ μ¬μ©νμ¬ λμΌν μΊμ μ΄λ¦μ κ°μ§ λͺ¨λ λ°μ΄ν°λ₯Ό μμ νκ² λ©λλ€. κ°λ°μ μ μ₯μμ κ°λ¨νκ³ νΈλ¦¬ν΄λ³΄μ΄μ§λ§ μΊμ μ΄λ¦μ λν΄ μ μ₯λλ ν€ ν¨ν΄μ΄ λ€μν΄μ§λ κ²½μ°μ νΉμ ν€ ν¨ν΄μΌλ‘ ꡬμ±λ μΌλΆ λ°μ΄ν°λ§ κ°±μ νλ©΄ λμ§λ§ λͺ¨λ λ°μ΄ν°κ° μμ λμ΄ GC λΆν λΏλ§ μλλΌ λλ¨Έμ§ λ°μ΄ν°μ λν DB λΆνλ λ€μ λ°μνλ€λ μ μ μκ°ν΄λ³΄κ² λ©λλ€. @CacheEvict μμ ν€ ν¨ν΄μ μν΄ μμ νλ λ°©λ²μ μ§μνμ§ μκΈ° λλ¬Έμ μ§μ λ³λλ‘ AOPλ‘ κ΅¬νν΄μΌν©λλ€.
μ체 νΈμΆμ μν μΊμκ° μ μ©λμ§ μμ
μΈν 리μ μ΄ IDE μμ μ체 νΈμΆμ λν μ½λκ° λ°μνλ κ²½μ° μΉμ νκ² @Cacheable μκΈ° νΈμΆ(μ€μ§μ μΌλ‘ νκΉ κ°μ²΄ λ΄μ λ©μλκ° νκΉ κ°μ²΄ λ΄μ λ€λ₯Έ λ©μλλ₯Ό νΈμΆ) μ λλ€. μΊμ μ΄λ Έν μ΄μ μ΄ λ°νμ μμ 무μλ©λλ€λΌλ λ¬Έκ΅¬λ‘ κ²½κ³ ν΄μ£Όκ³ μμ΅λλ€. μ΄μ κ°μ΄ μ€νλ§ μΊμ μ΄λ Έν μ΄μ μ μν μ μΈμ μΊμλ μ€νλ§ AOPλ₯Ό ν΅ν΄ νλ‘μλ‘ λμνλ―λ‘ μ체 νΈμΆ(Self Invocation)μ μν΄μλ μ μ©λμ§ μμ΅λλ€. λ°λΌμ, μ체 νΈμΆλ‘ λ¨μ§ μλλ‘ μ½λ 리뷰λ₯Ό μνν΄μΌνκ³ Self-Injection λλ μ체 νΈμΆμ΄ λμ§ μλ κ΅¬μ‘°λ‘ λ¦¬ν©ν λ§ ν΄μΌν©λλ€.
μ ν리μΌμ΄μ μΊμ λΆν λͺ¨λν°λ§
CaffeineCache cache = (CaffeineCache) cacheManager.getCache("sample");
log.info("sample - {}", cache.getNativeCache().stats());
μλΉμ€ νμ¬μ κ°λ° μ‘°μ§μ²λΌ μ ν리μΌμ΄μ λͺ¨λν°λ§μ μ§μμ μΌλ‘ μννμ§ μλ κ°λ°μ μ μ₯μμλ μ μΈμ μΊμ μ μ©μΌλ‘ μΈν΄ λ°μν μ μλ μ ν리μΌμ΄μ λΆνλ₯Ό κ²ν νμ§ μκ³ μμ°μ€λ 무μλ κ°λ₯μ±μ΄ λμ΅λλ€. μ ν리μΌμ΄μ μ λ€μν κΈ°λ₯μ μΆκ°νλ©΄μ μΊμλ₯Ό λμ νλ€λ³΄λ©΄ μλ‘ λ€λ₯Έ μΊμλ‘ μΈν΄ μ ν리μΌμ΄μ μμ μ μν μΊμ μ νλμ λμ΄μκ±°λ μΊμκ° λ¬΄μλ―Ένκ² μ μ₯λκ³ μμ λλ κ²μ΄ λ°λ³΅λ μ μμ΅λλ€. λ§μ½, Caffiene μΊμλ₯Ό λμ νλ€λ©΄ recordStats μ΅μ μ μ¬μ©νκ³ μΊμμ λν ν΅κ³λ₯Ό μ£ΌκΈ°μ μΌλ‘ λͺ¨λν°λ§ν μ μλ λ‘κ·Έλ₯Ό λ¨κΈ°λκ² μ’μ΅λλ€.
λ§μ§λ§μΌλ‘, μ ν리μΌμ΄μ μμ λ‘컬 μΊμλ‘ μΆ©λΆνλλ λΆκ΅¬νκ³ λ¬΄μμ λ λμ€λΌλ μΈλΆ μΊμ μ μ₯μ κΈ°μ μ μμ‘΄νκ³ μλμ§ λ€μνλ² μκ°ν΄λ³΄λλ‘ ν©μλ€.