2012-04-14 49 views
5

Có cách nào dễ dàng để sử dụng chú thích @Cacheable của Spring với bean không phải là singleton (ví dụ: phiên phạm vi) và có bộ nhớ cache có cùng phạm vi với bean đã nói không?Chú thích @Cacheable của Spring có thể có cùng phạm vi với bean của phương thức được chú thích không?

Ví dụ:

import javax.inject.Inject; 
import javax.inject.Named; 

import org.springframework.cache.annotation.Cacheable; 
import org.springframework.context.annotation.Scope; 
import org.springframework.security.core.context.SecurityContextHolder; 

@Named 
@Scope("session") 
public class UserNameRetriever { 

    @Inject private UserDao userDao; 

    @Cacheable("userName") 
    public String getUserName() { 
     return userDao.getUserByLogin((String)SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getName(); 
    } 

} 

Lý tưởng nhất, UserNameRetriever.getUserName() sẽ lấy tên người dùng từ UserDao lần mỗi phiên, nhưng mã này thực sự lưu trữ ứng dụng rộng rãi.

Trả lời

2

Tôi đã không thử nó, nhưng theo Spring reference Tôi nghĩ rằng điều này sẽ làm việc:

@Cacheable(value = "userName", key = "#root.target") 
+0

này hoạt động, nhưng có một rò rỉ bộ nhớ mà không ( \t \ @CacheEvict (value = "userName", key = "# root.target") \t \ @PreDestroy \t public void dọn dẹp() { \t} ) Ngoài ra, tôi đã quyết định không sử dụng @Cacheable sau khi tất cả, vì nó không đảm bảo rằng giá trị sẽ được tính chỉ một lần. –

+0

Bạn có ý gì khi rò rỉ bộ nhớ? Có thể bộ nhớ cache của bạn quá lớn. @Cacheable sẽ tra cứu trong bộ nhớ cache trước, do đó, nó đảm bảo rằng giá trị sẽ không được tính trong khi vẫn còn trong bộ nhớ cache. – sinuhepop

+0

Đó là một rò rỉ bộ nhớ bởi vì sau khi phiên kết thúc, giá trị vẫn còn trong bộ nhớ cache, nhưng không thể truy cập được. @PreDestroy đảm bảo rằng giá trị được lưu trong bộ nhớ cache được loại bỏ khi phiên kết thúc. –

2

Tôi nghĩ bạn đang tiếp cận vấn đề từ phía sai. Thay vì có bộ nhớ cache "local", chỉ lưu một giá trị có một bộ nhớ cache toàn cầu lưu trữ bản đồ từ tên người dùng đến các giá trị User.

Trong trường hợp của bạn thả @Cacheable trên getUserName() và đặt nó trên UserDao:

public class UserDao { 
    @Cacheable("users") 
    public User getUserByLogin(String user) { 
    //... 
    } 
} 

Đây không chỉ là việc sử dụng nhiều thành ngữ của bộ nhớ cache, nhưng cũng có thể nó sẽ chứng minh được dễ dàng hơn để duy trì và thực hiện tốt hơn.

Quay lại câu hỏi ban đầu của bạn: không, điều này không thể thực hiện được ngoài hộp. Bạn sẽ phải tự viết CacheManager của riêng mình - có thể là xung quanh việc triển khai hiện tại.

+0

RE: Tôi nghĩ rằng bạn đang tiếp cận vấn đề từ bên sai: UserDao tìm nạp người dùng từ hệ thống bên ngoài và tôi muốn tên người dùng (chỉ được sử dụng một cách thẩm mỹ) nhất quán trong suốt phiên, nhưng làm mới trong phiên mới nó đã thay đổi trong hệ thống bên ngoài nói. Cách tiếp cận của bạn sẽ không thể hiện hành vi này. –

3

Nếu bạn muốn có một bộ nhớ cache session, sử dụng phiên. Tức là, lưu trữ người dùng trong một trường riêng trong bean phiên phạm vi hoặc truy cập trực tiếp đối tượng HttpSession. @Cacheable thường có nghĩa là cho các tài nguyên trên toàn ứng dụng.

Vâng, bạn có thể sử dụng key="#user.id", và để làm mất hiệu lực bộ nhớ cache (bằng tay hoặc với @CacheEvict) trên một phương pháp @PreDestroy, nhưng nó sẽ là tốt hơn nếu bạn không pha trộn hai - bộ nhớ đệm và phiên dữ liệu.

+0

Xin chào @Bozho, bạn có thể giải thích lý do tại sao bạn nghĩ tốt hơn nên sử dụng httpsession vs Cacheable trong ứng dụng web mùa xuân? –

+0

tài nguyên trên toàn phiên so với toàn bộ tài nguyên của ứng dụng. Đó là nỗ lực bổ sung nếu bạn muốn sử dụng @Cacheable cho tài nguyên phiên – Bozho

Các vấn đề liên quan