Vaadin 8无Spring环境下如何实现应用级全局缓存?
在Vaadin 8中实现应用级共享缓存(无需Spring)
不用Spring也完全能搞定!下面给你几个简单可靠的方案,都是针对Vaadin 8环境设计的:
方案一:单例模式+线程安全集合
这是最直接的方式,创建一个全局唯一的缓存类,所有用户共用同一个实例。关键是要保证线程安全,毕竟多用户同时访问,推荐用ConcurrentHashMap这种线程安全的集合:
public class AppSharedCache { // 全局唯一实例,类加载时初始化 private static final AppSharedCache INSTANCE = new AppSharedCache(); // 线程安全的缓存存储 private final ConcurrentHashMap<String, Object> cacheStore = new ConcurrentHashMap<>(); // 私有构造方法,禁止外部实例化 private AppSharedCache() {} // 获取单例实例 public static AppSharedCache getInstance() { return INSTANCE; } // 缓存操作方法 public void put(String key, Object value) { cacheStore.put(key, value); } public Object get(String key) { return cacheStore.get(key); } public void remove(String key) { cacheStore.remove(key); } public void clearAll() { cacheStore.clear(); } }
在Vaadin的视图或UI里直接调用就行,比如:
// 存储共享对象 AppSharedCache.getInstance().put("globalConfig", myConfigObject); // 获取共享对象 GlobalConfig config = (GlobalConfig) AppSharedCache.getInstance().get("globalConfig");
注意:如果缓存的对象本身是可变的(比如可以修改内部属性),那你要自己保证对这些对象的操作是线程安全的,比如加锁或者把对象设计成不可变的。
方案二:借助ServletContext存储
Vaadin运行在Servlet容器里,ServletContext本身就是应用级别的上下文,所有用户共享同一个实例。你可以把缓存存在这里,还能利用Servlet的生命周期管理缓存:
1. 初始化缓存
自定义一个VaadinServlet,在init方法里初始化缓存:
public class MyCustomVaadinServlet extends VaadinServlet { @Override public void init() throws ServletException { super.init(); // 创建线程安全的缓存并放入ServletContext ConcurrentHashMap<String, Object> appCache = new ConcurrentHashMap<>(); getServletContext().setAttribute("APP_LEVEL_CACHE", appCache); } }
别忘了在web.xml里配置这个自定义Servlet,替换默认的VaadinServlet。
2. 访问缓存
在Vaadin的任何能拿到VaadinSession的地方(比如视图的按钮点击事件、UI初始化方法),都可以获取缓存:
// 获取ServletContext ServletContext servletCtx = VaadinSession.getCurrent().getSession().getServletContext(); // 取出缓存 ConcurrentHashMap<String, Object> appCache = (ConcurrentHashMap<String, Object>) servletCtx.getAttribute("APP_LEVEL_CACHE"); // 存数据 appCache.put("sharedUserData", userDataObject); // 取数据 UserData sharedData = (UserData) appCache.get("sharedUserData");
这种方式的好处是缓存会跟着Web应用的生命周期走——应用重启时ServletContext销毁,缓存也会自动清空,不用额外处理。
方案三:用Guava Cache实现更智能的缓存(推荐)
如果你的项目可以引入Guava依赖,那强烈推荐用Guava的Cache组件,它自带缓存过期、内存上限、自动加载等功能,比自己实现要省心太多:
1. 引入Guava(如果还没加)
在你的依赖管理里添加Guava,比如Maven:
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.1-jre</version> <!-- 选一个兼容Vaadin8的版本 --> </dependency>
2. 创建缓存类
import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.util.concurrent.TimeUnit; public class SmartAppCache { private static final Cache<String, Object> CACHE_INSTANCE = CacheBuilder.newBuilder() .maximumSize(500) // 最多存500个条目,防止内存溢出 .expireAfterAccess(15, TimeUnit.MINUTES) // 15分钟未访问自动过期 .build(); private SmartAppCache() {} public static Cache<String, Object> getInstance() { return CACHE_INSTANCE; } }
3. 使用缓存
// 存储数据 SmartAppCache.getInstance().put("cachedData", myData); // 获取数据,支持自动加载(缓存不存在时自动执行加载逻辑) try { MyData data = (MyData) SmartAppCache.getInstance().get("cachedData", () -> { // 这里写从数据库/文件加载数据的逻辑 return loadDataFromSource(); }); } catch (ExecutionException e) { // 处理加载异常 e.printStackTrace(); }
注意事项
- 线程安全:不管用哪种方案,都必须确保缓存操作是线程安全的,优先用线程安全的集合(比如
ConcurrentHashMap)或者Guava这种经过验证的组件。 - 内存控制:应用级缓存是所有用户共用的,一定要设置合理的缓存上限或者过期策略,避免内存溢出。
- UI线程注意:如果在后台线程里访问缓存,需要确保操作不会干扰Vaadin的UI线程——如果涉及到更新UI,要用
VaadinSession.getCurrent().access(Runnable)来执行。
内容的提问来源于stack exchange,提问作者xavierz
相关产品推荐
相关产品推荐

