I Have REST service
#Path("/rest")
#Component
public class MyRestService
{
#Inject
private MyBean bean;
#GET
#Path("/do")
public String start()
{
this.logger.info("Before do " + Thread.currentThread().getId());
String result = this.bean.do();
this.logger.info("After do " + Thread.currentThread().getId());
return result;
}
}
which calls method of injected Spring singleton bean (with some state inside)
#Service
public class MyBean
{
public String do()
{
// do something big...
}
}
When I call ".../rest/do" in browser the first call goes as expected, but if I make same call in another tab this call waits until first is finished to process second call in same thread.
If I do second call as ".../rest/do?async=true" it does not wait and processes second request in new thread, but if I do both requests as ".../rest/do?async=true" - second one again waits for the first one to finish.
What could be the reason for such behavior? Is it actually expected?
My web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<display-name>My REst</display-name>
<!-- spring configuration by annotations -->
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<!-- spring configuration class -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>app.Config</param-value>
</context-param>
<!-- to return data according to extension -->
<context-param>
<param-name>resteasy.media.type.mappings</param-name>
<param-value>json : application/json, xml : application/xml</param-value>
</context-param>
<!-- this has to match with resteasy-servlet url-pattern -->
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<!-- resteasy spring connector (to use DI in rest-resources) -->
<listener>
<listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>resteasy-servlet</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<!-- this has to match with resteasy-servlet url-pattern -->
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<!-- Bind Jboss's TransactionManager (EntityManagerFactory) to JNDI -->
<persistence-unit-ref>
<persistence-unit-ref-name>persistence/ReferenceDataDS</persistence-unit-ref-name>
<persistence-unit-name>ReferenceDataDS</persistence-unit-name>
</persistence-unit-ref>
</web-app>
You can solve this issue running your application server in debug mode. Do the test with two different clients e.g. Firefox, Chrome, IE, Opera, ... While waiting for the answer pause all the threads.
If you see only one workerthread active, then the settings of the application server are the problem.
If you see multiple workerthreads active but one of them is waiting for a semaphore, you have a problem with multiple threads accessing the same resource
If you have multiple workerthreads active but one of them is waiting for a connection to the persistence store, then you're datasource doesn't have a connection pool.
Since i just spent a whole day to fight this exact problem (without realizing that a changed parameter would have lead to parallel execution):
The culprit is the browser.
In Chrome, the calls get queued when you call the same resource from two tabs, but executed in parallel when you make the calls from different windows.
In IE11, they always get executed in parallel
In Firefox, it doesn't matter whether the calls are from different tabs or windows, they always get queued.
All of them execute them in parallel when the URLs are slightly different, by adding a different fragment or parameter.
Related
In Spring MVC, people typically build a Dispatcher Servlet that controls the other Servlets. The pipeline includes a request to web.xml which is then routed to a dispatcher of class org.springframework.web.servlet.DispatcherServlet. The URL pattern can be / or *.htm* to ensure that all requests go there.
The question is: in this pattern, what is even the purpose of web.xml? One would think that it is just useless overhead. I mean, if you're not going to use another dispatcher... or are you?
Basically in a regular Java app context will be fetched in some self-created main method, means main method is your starting point. Application will run from the main and will go other methods after.
public class FooClass{
public static void main(String[] args) {
//some code
}
But in the Spring web app,
the starting point is actually web.xml. It start from here, then flow goes to the other defined classes and methods
For example, when you write these codes, you basically give the order to the web application that you should start from here
Kind of you define your starting point. Think that it is main method in normal Java
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-mvc-validation-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
And in second part you give order to dispatcher that start from here. It means you give a url-pattern -starting point. You can give anything in here but "/" this is the common use
<!-- Step 2: Set up URL mapping for Spring MVC Dispatcher Servlet -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
I hope it is clear. Else ask for more explanations.
I coming back to Spring after spending 5 years doing other things. I have an initial projects which is designed to provide a HTTP REST service that returns JSON.
My problem is that I cannot get the service to convert the response to JSON. Instead I get errors like this:
javax.servlet.ServletException: Circular view path [hello]: would dispatch back to the current handler URL [/hello] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
at org.springframework.web.servlet.view.InternalResourceView.prepareForRendering(InternalResourceView.java:205) ~[spring-webmvc-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:145) ~[spring-webmvc-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303) ~[spring-webmvc-4.1.4.RELEASE.jar:4.1.4.RELEASE]
...
My web.xml looks like this:
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>au.com.abc.service</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>fxServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>au.com.abc.controller</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>fxServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
And my Controller class looks like this:
#RestController
public class FXRESTController {
#RequestMapping(value = "/hello")
public Map<String,Object> rootContextHandler() {
Map<String,Object> data = new HashMap<>();
data.put("X", "abc");
return data;
}
}
It really cannot get any simpler. I've been passing the request header Accept='application/json', but it's still not working. I have had this type of thing working in the past, but I don't have that code anymore. I can also see this in the logs:
... Invoking request handler method: public java.util.Map au.com.abc.controller.FXRESTController.rootContextHandler()
... Service responding
... Invoking afterPropertiesSet() on bean with name 'hello'
... Rendering view [org.springframework.web.servlet.view.JstlView: name 'hello'; URL [hello]] in DispatcherServlet with name 'fxServlet'
... Added model object 'X' of type [java.lang.String] to request in view with name 'hello'
... Error rendering view [org.springframework.web.servlet.view.JstlView: name 'hello'; URL [hello]] in DispatcherServlet with name 'fxServlet'
Which suggests to me that it's trying to render a JSTL view. Why - I don't know considering I've asked for JSON.
Any ideas what I've done wrong?
I've read a ton of blogs and so far I cannot see any differences between what they have done and what I've done.
Oh and here are my gradle resolved dependencies:
You only have a controller, that doesn't do anything for enabling JSON.
You have to have a #Configuration annotated class which is also annotated with #EnableWebMvc to have automatic JSON conversion enabled. See also this section of the reference guide.
#Configuration
#EnableWebMvc
public class WebConfiguration {}
You are running with the DispatcherServlet defaults which are very basic.
Use #ResponseBody.
ALso donot direct all request to spring
<servlet-mapping>
<servlet-name>fxServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
ALways better to add a layer like this:
<servlet-mapping>
<servlet-name>fxServlet</servlet-name>
<url-pattern>/webapp/*</url-pattern>
</servlet-mapping>
FOr a given project only following request will be directed to spring
http://localhost:8080/Proj/app/hello
Other request can be handled different..thus you can handle request in a different way and not dependent on spring..like
http://localhost:8080/Proj/servlethandler
The above request will not go to spring and can be intercepted by a servlet etc..
Could you help to check why doFilter not getting called
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/log4j.properties</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<filter>
<filter-name>roseFilter</filter-name>
<filter-class>net.paoding.rose.RoseFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>roseFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
</web-app>
class signature:
import org.springframework.web.filter.GenericFilterBean;
public class RoseFilter extends GenericFilterBean {
404 is returned while call http://localhost:8080/hello/world, I set the breakpoints at
doFilter, it seems doFilter not called?(I tried tomcat 6.0.18, 6.0.29, jdk1.6)
The filter won't be invoked when:
The filter class is missing in the classpath and/or is not loadable or instantiable. You should however have noticed it in the server's startup logs. Solution is to be found based on the interpretation of the exceptions/errors found in the server logs.
There's another filter running before in the chain which isn't calling FilterChain#doFilter(), but rather RequestDispatcher#forward() or include() which caused the subsequent filters in the chain being completely skipped (when they do not listen on FORWARD or INCLUDE dispatchers; they by default only listens on REQUEST dispatcher). Solution is either to fix the wrong filter, or to add <dispatcher>FORWARD</dispatcher> etc accordingly, or to rearrange the filter declarations in web.xml so that your new filter comes before the another filter (you in turn only need to ensure that your new filter is using the FilterChain#doFilter() properly :) ).
The request URL is plain wrong. You used http://localhost:8080/hello/world. With a filter listening on /*, this means that the webapp context should be ROOT or at least /hello. Verify your webapp context. I'd just retry with an URL which points to a valid JSP/Servlet inside the same webapp which generates a non-404 response. Does the filter then get called as well?
What's the web request look like? Can you try changing your url-pattern to *.jsp instead of / * ? If you are using something other than pure JSP then change it to whatever the request ending extension is (like for struts it is usually *.do).
I've created simple jax-ws (anotated Java 6 class to web service) service and deploied it on glassfish v3. The web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app>
<servlet>
<servlet-name>MyServiceName</servlet-name>
<description>Blablabla</description>
<servlet-class>com.foo-bar.somepackage.TheService</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>MyServiceName</servlet-name>
<url-pattern>/MyServiceName</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>
There is no sun-jaxws.xml in the war.
The service works fine but I have 2 issues:
I'm using apache common configuration package to read my configuration, so i have init function that calls configuration stuff.
1. How can I configure init method for jaxws service (like i can do for the servlets for example)
2. the load on startup parameter is not affecting the service, I see that for every request init function called again (and c-tor). How can I set scope for my service?
Thanks a lot,
How can I configure init method for jaxws service (like i can do for the servlets for example)
JAX-WS endpoints, both web and EJB, can have optional life-cycle methods that are automatically called if present. Any method can be used as a life-cycle method with the correct annotation:
#PostConstruct - Called by the container before the implementing class begins responding to web service clients.
#PreDestroy - Called by the container before the endpoint is removed from operation
So annotating your init() method with #PostConstruct should do the trick.
the load on startup parameter is not affecting the service, I see that for every request init function called again
Try to use the suggested annotation first. And if you are still facing unexpected behavior, post your code.
Thanks for the quick answer, Pascal.
BTW, I warmly suggest to use a "valid" servlet 2.5 or servlet 3.0 web.xml (using a version attribute in the web-app element and the xsd declaration).
I'm using 2.5 version, I just didn't paste this part in my post
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:j2ee="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<description>WebTier for the Login Manager Service</description>
<display-name>LoginManagerWAR</display-name>
<servlet>
<description>Endpoint for Login Manager Web Service</description>
<display-name>LoginManagerControllerService</display-name>
<servlet-name>LoginManagerController</servlet-name>
<servlet-class>loginmanager.controller.LoginManagerController</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>LoginManagerController</servlet-name>
<url-pattern>/LoginManagerControllerService</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>54</session-timeout>
</session-config>
The PostConstruct works fine , thank you, but load-on-startup still didn't happen.
#WebService(
name="LoginManagerController",
serviceName="LoginManagerControllerService"
)
public class LoginManagerController {
private ILoginManager manager;
#Resource
private WebServiceContext wsContext;
#PostConstruct
private void init(){
.....
}
More over, now every client request makes 2 init() calls of the webservice:
like I can see in chainsaw, first called init() of the service, then it called again and then the actually client's function (I print the hash code of the webservice class instance and it the same instance for both calls!!!):
> Message Inside init() method ... controller=31641446
> Message login manager = 11229828
> .....init of elements....blablabla.....
> Message Exiting init() method
> Message Inside init() method ... controller=31641446
> Message login manager = 32361523
The controller is the service and the manager (wich hash code has been changed from first call to the second) created inside the init () of the controller.
I failed to understand what is wrong ....
UPDATE
It seems like a to glassfish v3 related issue (maybe my env setup or glassfish configuration). I tried this war on Sailfin and Glassfish V2 and its perfectly working ....
This question already has answers here:
Change default homepage in root path to servlet with doGet
(2 answers)
Closed 7 years ago.
I want my SampleServlet to be called first whenever my java web application is accessed in this manner :
http://server:8080/appname/
Is there any way to implement this?
Use a Servlet filter to call your Servlet.
If you want to make a servlet your homepage then this worked for me on http://feelitlive.com/
<welcome-file-list>
<welcome-file>homepage</welcome-file>
</welcome-file-list>
...
<servlet>
<description>Shows stuff on the homepage</description>
<display-name>Homepage Servlet</display-name>
<servlet-name>HomepageServlet</servlet-name>
<servlet-class>com.cantorva.gigcalendar.servlets.HomepageServlet</servlet-class>
</servlet>
...
<servlet-mapping>
<servlet-name>HomepageServlet</servlet-name>
<url-pattern>/homepage</url-pattern>
</servlet-mapping>
That means that that users arriving at your application via the URL you specified will be welcomed by your servlet. It also creates an alias for the homepage at "/homepage" but you don't have to use that.
If you want to run some code on start-up then asalamon74's answer looks right.
Not sure what you mean but you need to map your servlet to "/"
<servlet-mapping>
<servlet-name>SampleServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Not sure what is your aim, but web application initialization can be achieved by ServletContextListener:
public class AppListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
// place your code here
}
public void contextDestroyed(ServletContextEvent event) {
}
}
and later in web.xml:
<web-app>
<listener>
<listener-class>
package.AppListener
</listener-class>
</listener>
...
</web-app>
If you want to run code on start-up indeed asalamon74's answer should be fine. If you have a legacy situation and you must use a servlet, the parameter load-on-startup can do the trick for you:
<servlet>
<servlet-name>SampleServlet</servlet-name>
<display-name>SampleServlet</display-name>
<description>Sample Servlet</description>
<servlet-class>...</servlet-class>
<init-param>...</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
The load-on-startup tag specifies that the servlet should be loaded automatically when the web application is started; the number value just gives a loading order to those loading on startup. If no value is specified, the servlet will be loaded when the container decides it needs to be loaded - typically on it's first access.