Say, I have a TestServlet class which declared as a global string variable. If there are simultaneous calls to TestServlet class, will this 'message' string variable safe to print without crossing from concurrent threads?
public class TestServlet extends HttpServlet {
private String message;
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
OutputStream os = response.getOutputStream();
message = UUID.randomUUID().toString();
os.write(message.getBytes());
}
}
A servlet is shared across requests, so no, it is not thread-safe. A servlet object is scoped to a <servlet> declaration in web.xml.
The container creates an instance of the <servlet-class> for each servlet and calls its init method.
Some references here:
http://www.coderanch.com/t/473015/Servlets/java/Servlet-thread-safe
http://docs.oracle.com/javaee/5/tutorial/doc/bnafu.html
Generally, if you are storing state in a servlet, you should consider alternatives. Why store state there? What is the state tied to? Is it tied to the request? If so, use request.setAttribute. If it is meant to be shared across multiple requests by the same user, use request.getSession().setAttribute. If it should be shared by all requests, then request.getServletContext().setAttribute.
If the state is specific to a single request and only within the execution of this servlet, then it should just be a local variable in your method. For example:
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
OutputStream os = response.getOutputStream();
String message = UUID.randomUUID().toString();
os.write(message.getBytes());
}
Notice there are no non-local variables here. That is fairly thread-safe.
No, servlets are not thread-safe. Servlets should not expose any sort of mutable state in this manner.
Related
This question already has answers here:
How do servlets work? Instantiation, sessions, shared variables and multithreading
(8 answers)
Passing an object from JSP page back to Servlet
(3 answers)
How can I store state for an individual browser tab/window?
(2 answers)
Closed 5 years ago.
This is the sample code, illustrating the usage of instance variable and request attribute:
#WebServlet(name = "Upload", urlPatterns = {"/upload"})
#MultipartConfig()
public class Upload extends HttpServlet {
private String txt;
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try{
String txt2 = (String) request.getAttribute("txt2");
//txt and txt2 variables are available for processing.
..........
} finally {
txt = null;//Prepare variable for next request.
}
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
.....
request.setAttribute("txt2", someValue);
//vs
txt = someValue;
processRequest(request, response);
}
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
.....
processRequest(request, response);
}
}
Now I know that instance variables should be never declared in servlets, because the same servlet is shared between concurent requests. But what about request attributes? Is it safe to use them?
Not sure what you mean by initializing variables. On a servlet you mean or where?
Depending on what you need to do, maybe there are APIs involved in which you don't have control about the contracts (since they are not your APIs).
For example, when requesting is being processed by a filter chain. Maybe one filter is interested on data being set by a filter executed previously in the chain. You don't have means to pass data on the filter chain contract. Request attribute might be an option. Playing with ThreadLocal might be another, but it has performance implications and is not always suitable.
Another example, maybe you forward one request from a servlet to another. Again, you will not have an option to play with whatever member variable you define.
Also, if you were thinking on adding member variables on a servlet, remember Servlets are not thread-safe. What would you do? synchronize request processing, only one request being processed per servlet?
Your servlet is going to serve hundreds on concurrent request each one of them will use same shared instance of the servlet, therefore using private instance variable will lead to inconsistent behavior. Unless you synchronize access to it, which will lead to greater contention on access to this private field, therefore slowing down response time, producing bottleneck.
While storing attribute within binded to single request will allow you to avoid such problem, moreover it was designed to overcome issues similar to yours.
public void doGet(HttpServletRequest req,HttpServletResponse res) throws ServletException,IOException
{
String param1 = req.getParameter("x");
String param2 = req.getParameter("y");
String param3 = req.getParameter("z");
int x = Integer.parseInt(param1);
int y = Integer.parseInt(param2);
int z = Integer.parseInt(param3);
Why do you want more that one doGet in the same servlet, that kind of defeats the point. You would either have one Servlet that dispatches control to the appropriate controller (Prefered), or you would have one Servlet per request.
The doGet is an inherited method from HttpServlet, so you can overload the doGet method, but that those overloads can not be called. Since your implementation will be injected into the client, the client has coded using the HttpServlet class and your implementation is called polymorphically. As such, the client will only have access the the methods defined in HttpServlet and your overloaded implementations will not be known.
I hope this helps.
doGet(HttpServletRequest req,HttpServletResponse res) is picked by the servlet container.So Yes You can have overloaded versions of doGet but they wont be recognized by Servlet Container.So it does not make sense to have multiple doGet.
Instead Overriding the doGet and doPost Methods in servlet makes sense.
Refer this for more info.
I did a simple test, and executed my test servlet below from different browsers and command line tools. Regardless where I execute it, it displays the same "hohoho time". I am absolutly fine with this, I just want to know two things:
a) if I can rely on this on different versions of tomcat (today I use version 7.54)
b) does this mean a servlet is never executed parallel in different threads (i.e. two users are requesting the very same servlet at the very same time)
#WebServlet(name="test servlet 2", urlPatterns={"/test2"}, loadOnStartup=1)
public class Test2 extends HttpServlet {
private String test = "baaa .. :-(";
#Override
public void init(ServletConfig config) throws ServletException {
DEBUG("Server starts");
this.test = "hohoho " + System.currentTimeMillis();
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletOutputStream out = resp.getOutputStream();
out.write(test.getBytes());
out.flush();
out.close();
}
}
Indeed servlet container creates only one instance of each servlet. This helps you to hold state in servlet member variables. This however does not mean that servlet container cannot use the same servlet instance to process serveral requests simultaneously. This is what servlet contains (including Tomcat) does. Therefore your servlet must be thread safe. Please refer to this article for details: http://tutorials.jenkov.com/java-servlets/servlet-concurrency.html
I have below view on your question.
a) Yes,atleast from tomcat 7 onwards.For tomcat 6(annotation support),you will have to check the specs.
b) Regarding execution in parallel thread,servlet not threadsafe by default,to ensure thread safety,Servlet service() method should not access any member variables, unless these member variables are thread safe themselves.
For more on thread safety : Servlet Thread Safety
There is only one instance of each HttpServlet and its init() method is only called once when the HttpServlet is constructed. However the doGet() is called in a different thread for each request and can happen in parallel.
I have 2 java classes and I want to transfer data between them.
I take user id as parameter in a previous jsp form, and in a java class, using setAttribute I create a atribute named st_id.
then in another java clas I want to retrieve this data, but I get null.pointer exception.
first java file;
public class Signin implements Action {
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
Student stu = new StDAO().getUser(request.getParameter("st_id").toString());
request.setAttribute("st_id", request.getParameter("st_id").toString());
...
second;
public class addCourseStu implements Action{
#Override
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
TakeCourseDAO pf = new TakeCourseDAO();
String s= (String) request.getAttribute("st_id");
So s is null, it's not my intention.
A request exists from the time the web browser sends it to the web server until the web server (via the servlet) has made its response.Every request for a servlet has its own accessibilty scope. From a servlet, you can:
add new attributes to the request's scope
obtain exisiting attributes from the request's scope
remove exisiting attributes from the request's scope
As you are getting null it is quite obvious that the attribute is not accessed within the scope.
You can try alternatives like Session scope or Application scopes which ever suits you
It is not entirely clear what you want to do but I gather that you want to maintain some state on the server between two requests right?
Look into sessions & cookies for this.
What you do here is weird as it seems you are setting an attribute on an incoming request in the first file.
I have few questions.
Can i have a Servlet without these two methods?
Can i call my form directly to Service method... Like
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FormServlet extends HttpServlet {
protected void doService (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
No, it's not mandatory. Since HttpServlet is an abstract class, there are abstract implementations of all doXXX methods, and you don't have to implement them if you don't want to.
Yes, you can have a servlet without either of these methods (they have no implementation). Still having a HttpServlet without having doGet/doPost seems a bit pointless, since servlet can only communicate with the a limited number of request methods such as GET, POST, DELETE, PUT (for more see specification section 5.1.1 ).
HttpServlet don't have doService methods. If you meant void service() then I advise you not to mess with it unless you really know what you're doing.
If all you need is to use doService call it from doGet, doPost (as someone already suggested).
Ok, examples:
public class DoesNothingServlet extends HttpServlet {} //does what the name implies
public class FormServlet extends HttpServlet { //what you want to do
protected doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doService(request,response)
}
protected void doService (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Do something
}
}
Read http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.6/api/javax/servlet/http/HttpServlet.html
Provides an abstract class to be subclassed to create an HTTP servlet suitable for a Web site. A subclass of HttpServlet must override at least one method, usually one of these:
doGet, if the servlet supports HTTP GET requests
doPost, for HTTP POST requests
doPut, for HTTP PUT requests
doDelete, for HTTP DELETE requests
init and destroy, to manage resources that are held for the life of the servlet
getServletInfo, which the servlet uses to provide information about itself
From your doGet and doPost methods, you can call your doService(..,..) method if you wish.
You will note that the service() method originates from the javax.servlet.GenericServlet and not javax.servlet.http.HttpServlet.
If you want to do something with a servlet which doesn't involve the http protocol, I would say go ahead.
In the Head First Servlets and JSP they explain this in detail. 99% You will make use of the HttpServlet.
By extending GenericServlet, the servlet would run regardless of the content submitted. As long as the URL is fired the service() method will execute.
My understanding, if I got you correct, is you want your HTTP GET, POST, (PUT, DELETE) to call your doService method. If that's the case, you can do this.
protected doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doService(request,response)
}
protected doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doService(request,response)
}
If you extends HttpServlet you don't have to override doGet and doPost as it's already implemented by HttpServlet. Servlet request get handled by the service() method which then (based on the HTTP request method) calls its relevant doXXX method.
I wouldn't mess with the service() method though, unless you know what you're doing.