通常,我从事Java EE应用程序。今天我遇到了一个问题:在servlet上下文中序列化集合。就我而言,我的应用程序包含一个Servlet Context Listener和许多servlet。
这里是我的contextInitialized Listener的代码:
public void contextInitialized(ServletContextEvent event) {
app = event.getServletContext();
myMap = new ConcurrentHashMap<String, Catalog>();
myMap.put("FR", new Catalog());
myMap.put("UK", new Catalog());
app.setAttribute("catalogue", myMap);
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new AutomateRefresh(), 0, 60, TimeUnit.MINUTES);
}
为了显示我的问题,我创建了一个servlet,它在上下文中显示了布尔值或ConcurrentHashMap的所有内容 我发现这种结果并不奇怪:
javax.servlet.context.tempdir is equal to...
Working is equal to... true
org.apache.catalina.resources is equal to...
org.apache.tomcat.InstanceManager is equal to...
org.apache.catalina.jsp_classpath is equal to...
javax.websocket.server.ServerContainer is equal to...
org.apache.jasper.compiler.TldCache is equal to...
catalogue is equal to...
org.apache.tomcat.JarScanner is equal to...
如您所见,我的两个自定义键(布尔工作和ConcurrentHashMap目录)存在。但是,如果没有在Listener中访问, catalog 是空的。
我发现:
java.util.HashMap的序列化形式不会对桶本身进行序列化,并且哈希码不是持久化状态的一部分。
对于许多项目,可序列化和线程安全的集合很有用。我可能不是唯一一个正在寻找它的人(参见有关servlet上下文的主题数量)。
ConcurrentHashMap是线程安全的,但我无法在其他servlet中检索我的数据(在同一个应用程序中)。是否有一个Thread的实现,它是线程安全的和可序列化的(由于WebLogic服务器策略)?或者我是以错误的方式使用它?
编辑:代码&#34;显示上下文servlet&#34;
public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException{
System.out.println("List of all values in the context:");
Enumeration<?> e = getServletContext().getAttributeNames();
while (e.hasMoreElements())
{
String name = (String) e.nextElement();
System.out.print("\n" + name + " is equal to... ");
// Get the value of the attribute
Object value = this.getServletContext().getAttribute(name);
if (value instanceof ConcurrentHashMap) {
ConcurrentHashMap<String, Catalog> map = (ConcurrentHashMap<String, Catalog>) value;
Iterator<Entry<String, Catalog>> it = map.entrySet().iterator();
while (it.hasNext()) {
ConcurrentHashMap.Entry<String, Catalog> entry = (ConcurrentHashMap.Entry<String, Catalog>)it.next();
System.out.print("\t" + entry.getKey() + "=" + entry.getValue());
}
} else if (value instanceof Boolean) {
System.out.print((Boolean)value);
}
}
}
EDIT2:就像BalusC一样,HashMap可能是null(一个新手的错误?)。
这里是任务代码。任务在Listener中。 Listener使用新的空对象初始化HashMap。任务在webapp启动时刷新对象,然后每小时刷新一次。
public class AutomateRefresh implements Runnable {
public void run() {
System.out.println("Scheduler trigger");
if(app.getAttribute("catalogue") instanceof ConcurrentHashMap){
myMap = (ConcurrentHashMap<String, Catalog>) app.getAttribute("catalogue");
//Autorefresh
Iterator<Entry<String, Catalog>> it = myMap.entrySet().iterator();
while (it.hasNext()) {
ConcurrentHashMap.Entry<String, Catalog> entry = (ConcurrentHashMap.Entry<String, Catalog>)it.next();
((Catalog)entry.getValue()).setValid(false);//Set as not valid anymore for further request
try {
((Catalog)entry.getValue()).refreshdb((String) entry.getKey());//TODO rework to use REST API
} catch (SQLException e) {
e.printStackTrace();
}
it.remove(); // avoids a ConcurrentModificationException
app.setAttribute("catalogue", myMap);
app.setAttribute("Working", true);
System.out.println((String)entry.getKey() + " = " + (Catalog)entry.getValue());
}
}
else{
System.out.println("Catalogue is not an instance of ConcurrentHashMap as expected.");
app.setAttribute("Working", false);
}
}
}
当任务触发时,对于存储在Context中的每个目录,任务都会更新它们存储的数据。它还在控制台中显示数据。
结果:
Refresh Catalog for UK with DB
UK = Catalog [list size is : 0 valid=true, lastToken=notoken]
Refresh Catalog for FR with DB
FR = Catalog [list size is : 30 valid=true, lastToken=notoken]
Catalog是一个带有ArrayList,boolean和String的类。一切似乎都是正确的:英国应该是空的但不是空的,FR应该包含30种产品。
我仍然无法在其他servlet中访问此数据。
答案 0 :(得分:0)
我发现问题的根源,新手错误如预期的那样:
我试图以这种方式更新,假设它会直接在ConcurrentHashMap中更新对象
((Catalog)entry.getValue()).refreshdb((String) entry.getKey());
我将其替换为:
Catalog myCatalog = (Catalog)entry.getValue();
myCatalog.refreshdb((String) entry.getKey());
myMap.put((String)entry.getKey(), myCatalog);
它现在有效。
我仍然不知道为什么我的对象可以从监听器访问,他们不应该这样工作。也许我的服务器有一种奇怪的行为?无论如何,这个问题是固定的。
感谢BalusC的帮助。