I wonder if anyone can advise: I have a scenario where a scheduled job being run by Quartz will update an arraylist of objects every hour.
But I need this arraylist of objects to be visible to all sessions created by Tomcat. So what I'm thinking is that I write this object somewhere every hour from the Quartz job that runs so that each session can access it.
Can anyone say how best this may be achieved? I was wondering about the object being written to servlet context from the Quartz job? The alternative is having each session populate the arraylist of objects from a database table.
Thanks
Mr Morgan.
Yes, I would store the list in the ServletContext
as an application-scoped attribute. Pulling the data from a database instead is probably less efficient, since you're only updating the list every hour. Creating a ServletContextListener
might be necessary in order to give the Quartz task a reference to the ServletContext
object. The ServletContext
can only be retrieved from JavaEE-related classes like Servlets and Listeners.
EDIT: In the ServletContextListener, when you create the job, you can pass the list into the job by adding it to a JobDataMap.
public class MyServletContextListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent event){
ArrayList list = new ArrayList();
//add to ServletContext
event.getServletContext().setAttribute("list", list);
JobDataMap map = new JobDataMap();
map.put("list", list);
JobDetail job = new JobDetail(..., MyJob.class);
job.setJobDataMap(map);
//execute job
}
public void contextDestroyed(ServletContextEvent event){}
}
//Quartz job
public class MyJob implements Job{
public void execute(JobExecutionContext context){
ArrayList list = (ArrayList)context.getMergedJobDataMap().get("list");
//...
}
}
You can try some caching solution, like EhCache to store you values, and update them every hour. It will handle concurrency issues. The cache object itself can be stored in the ServletContext
A good way to write to the ServletContext
from the Quartz job is to register listeners to your job that get notified about the changed value. So for example:
public class JobListener {
public void updateValue(Object newValue);
}
public class ServletContextCacheJobListener implements JobListener {
private ServletContext ctx;
public ServletContextJobListener(ServletContext ctx) {
this.ctx = ctx;
}
public void updateValue(Object newValue) {
Cache cache = (Cache) ctx.getAttribute("cache");
cache.update("yourKey", newValue);
}
}
Your Job will have a List<JobListener>
and when you schedule the job, you instantiate the concrete listener and add it to the job.
Well, if you use static fields they will be visible to all classes loaded by the same class loader. I think that at least the servlets of one app should end up qualifying. However, this is admittedly dirty.
An object that is defined and guaranteed to be (more) global is the ServletContext. This is shared between all servlets forming part of one application, i.e. loaded from the same web.xml
. There are put
and get
calls for ServletContext that allow you treat it essentially as a Map.
Beyond that, you'll need to find classes common to all Web apps inside one Tomcat server. Tomcat does a lot of footwork with loaders, and I think different Web apps will have distinct loaders. You can get around this by writing a class of your own and placing that class in Tomcat's common
or shared
directories. If I understand this description correctly, those classes will be made available, ONCE, to all Web apps.
Finally, beyond the confines of a single Tomcat server, you'll need some TCP/IP based mechanism for communicating between JVMs. But as I understood your question, that shouldn't be necessary.
来源:https://stackoverflow.com/questions/3215988/how-to-get-and-set-a-global-object-in-java-servlet-context