Reputation: 357
I am going to have to setup the framework for this question first. I am creating a dynamic servlet environment that uses a globally accessible, volatile, thread-safe, in-memory data cache that stores and provides access to itself for each servlet in the environment.
Something like this:
public class CoreServlet extends HttpServlet {
protected globalCache;
public void init(ServletConfig config){
globalCache = new InMemoryCache();
}
doGet...
doPost...
}
This servlet is then extended by a number of other servlets that do subsidiary tasks on the globalCache (changing values, etc).
public class subServletA extends CoreServlet {
doGet...
doPost...
}
and
public class subServletB extends CoreServlet {
doGet...
doPost...
}
and so on...
I have found, by experimenting, that doing this causes the entirety of the CoreServlet code to be re-executed (including all global variable instantiations and the init method) for each time that I extended the CoreServlet such that I ended up with six copies of the globalCache (which is a severely memory intensive object) being instantiated.
I fixed this part by assigning a flag in the ServletContext that was triggered after the first run through the init method, such that it would skip all of the other instantiations, and just leave me with one globalCache, but I have run into issues with Java seemingly changing cache values arbitrarily.
So, the technical question: Why does Java repeat the entirety of the parent servlets code?
And the more design-side question: Is there a better way to implement a sub-millisecond-second latency, globally-(within my application)-accessible cache?
I had considered using like a memcached sort of solution, but I still would like to have the cache in RAM for performance purposes.
Any thoughts, ideas, or best practice pointers welcome.
Upvotes: 1
Views: 1322
Reputation: 1573
When user makes an action like trigger ajax request or post-back, One thread in the thread-pool is received and for each request servlet's get or post method invoked.
There is an configuration in web.xml which enables servlet to be active on load.
<load-on-startup>Value</load-on-startup>
The servlet has smallest value, has ben initialized first when server starts.
Other wise :
The servlet is constructed, then initialized with the init method. Any calls from clients to the service method are handled. The servlet is taken out of service, then destroyed with the destroy method, then garbage collected and finalized.
In java if a class is initialized, extended class is automatically initialized as well.
Upvotes: 0
Reputation: 3442
The code below should do the trick, since it will put your global cache object into the ServletContext
of the web application, thus sharing it with all servlets.
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);
}
}
}
}
If you extend CoreServlet
the init()
method is called by the servlet container. That's the reason why you ended up with multiple instances of your cache object.
Upvotes: 1
Reputation: 4601
Each servlet instance is a completely new object, this is why your initialization code runs several times.
Each servlet instance works in a separate thread. this is why without understanding of the multithreading principles you will get corrupted data.
On your problem: introduce static cache, and it will be shared across all these instances:
protected static final globalCache = new GlobalCache();
Upvotes: 0