You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:11:03