我将首先必须为此问题设置框架。我正在创建一个动态servlet环境,该环境使用全局可访问,易变,线程安全的内存数据缓存,该缓存存储并为环境中的每个servlet提供对自身的访问。
这样的事情:
public class CoreServlet extends HttpServlet {
protected globalCache;
public void init(ServletConfig config){
globalCache = new InMemoryCache();
}
doGet...
doPost...
}
然后,这个servlet被许多其他servlet扩展,这些servlet在globalCache上执行辅助任务(更改值等)。
public class subServletA extends CoreServlet {
doGet...
doPost...
}
和
public class subServletB extends CoreServlet {
doGet...
doPost...
}
依旧......
我通过实验发现,这样做会导致每次扩展CoreServlet时重新执行整个CoreServlet代码(包括所有全局变量实例化和init方法),这样我最终得到了正在实例化的六个globalCache副本(这是一个严重的内存密集型对象)。
我通过在第一次运行init方法后触发的ServletContext中分配一个标志来修复这个部分,这样它就会跳过所有其他实例,只留下一个globalCache,但是我遇到了Java的问题似乎在任意改变缓存值。
所以,技术问题:为什么Java会重复整个父servlet代码?
设计方面的问题越多:是否有更好的方法可以实现亚毫秒级的延迟,全局(在我的应用程序中) - 可访问的缓存?
我曾考虑使用类似memcached的解决方案,但我仍然希望将RAM缓存用于性能目的。
欢迎任何想法,想法或最佳实践指示。
答案 0 :(得分:1)
下面的代码可以解决问题,因为它会将您的全局缓存对象放入Web应用程序的ServletContext
,从而与所有servlet共享。
public class CoreServlet extends HttpServlet {
protected globalCache;
@Override
public void init(ServletConfig config){
synchronized(CoreServlet.class) {
globalCache = (InMemoryCache) config.getServletContext().getAttribute("core.cache");
if (globalCache == null) {
globalCache = new InMemoryCache();
config.getServletContext().setAttribute("core.cache", globalCache);
}
}
}
}
如果扩展CoreServlet
,则由servlet容器调用init()
方法。这就是为什么你最终得到了缓存对象的多个实例的原因。
答案 1 :(得分:0)
每个servlet实例都是一个全新的对象,这就是你的初始化代码多次运行的原因。
每个servlet实例都在一个单独的线程中工作。这就是为什么在不了解multithreading原则的情况下,您将获得损坏的数据。
关于你的问题:引入静态缓存,它将在所有这些实例中共享:
protected static final globalCache = new GlobalCache();
答案 2 :(得分:0)
当用户执行触发器ajax请求或回发操作时,会收到线程池中的一个线程,并为每个请求servlet调用get或post方法。
web.xml中有一个配置,可以使servlet在加载时处于活动状态。
<load-on-startup>Value</load-on-startup>
servlet具有最小值,在服务器启动时首先进行初始化。
其他明智的:
构造servlet,然后使用init方法初始化。 将处理从客户端到服务方法的任何调用。 servlet停止服务,然后使用destroy方法销毁,然后收集垃圾并最终确定。
在java中,如果一个类被初始化,扩展类也会自动初始化。