how to have spring manage bean lifecycle instead of jersey - java

I'm using jersey 2.17 on tomcat 8, and I'm having a problem with what I think should be a very straightforward and common use case.
I have various beans defined in a spring XML file. I've now annotated one of them to expose some methods as rest APIs. This is a singleton bean, with a reference to another bean injected in the spring XML configuration.
My rest APIs are working, but the problem is that every time one is invoked a new instance of the bean class is created, and my bean reference is null. My understanding is that this is because jersey is managing the lifecycle instead of spring, and I need SpringComponentProvider, which will then provide the singleton.
I included jersey-spring3-2.17.jar in my application, and I specified the spring package in the servlet configuration in web.xml, as follows:
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>
org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>my.rest.package;org.glassfish.jersey.server.spring</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.tracing.type</param-name>
<param-value>ALL</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
I know that the jersey.config.server.provider.packages parameter is being picked up because the annotated class in my.rest.package gets found, but the SpringComponentProvider is apparently not being registered, because I'm still getting a new instance of my bean every time.
I tried specifying the class explicitly like this:
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.server.spring.SpringComponentProvider</param-value>
</init-param>
That didn't change the behavior either.
Any insights or debugging suggestions appreciated.
UPDATE: I realized that the version of my spring jars was behind the version expected by my jersey jars, and I think that's the problem. Once I'm able to update spring, if that fixes it I'll close this.

Jersey will create a new instance on each call regardless if you have an XML bean of the same class as singleton in spring context:
https://jersey.java.net/documentation/latest/jaxrs-resources.html#d0e2331
Also see this response on how to change that behavior:
https://stackoverflow.com/a/14739010/2879838
Within your Jersey Resource class, since you already added the jersey-spring dependency, you can simply add the #Autowire annotation on your member variable that you say is injected via XML file in spring. This will spring-inject the dependency when Jersey instantiates the resource on each request.
Hope this helps.

When I finally was able to update my spring, it turned out that was not the issue. I had to add #Component as well as #Singleton to my resource in order for jersey to recognize it as a spring-managed singleton. This problem would never have arisen if I was using annotations for spring; it happened because I was using XML to create the spring beans.

Related

What is the purpose of CXF servlet

I was going through a demo project setup for Restful webservice using Apache CXF, where I happened to come by a piece of code inside web.xml:
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
I did not really understand the use of a servlet class in this web.xml. I googled for org.apache.cxf.transport.servlet.CXFServlet and found:
The CXFServlet class, which is defined by Apache CXF, is generated and
registered to handle incoming requests.
Now, I really do not understand what that line means
Does this servlet pose as a front-controller, like in Spring MVC flow?
What is the actual purpose of using this servlet class?
How does CXF use Spring to provide XML configuration of services defined in the project?
Does org.glassfish.jersey.servlet.ServletContainer serve the same purpose in Jersey Implementation as org.apache.cxf.transport.servlet.CXFServlet with Apache CXF?
Help me clarify these questions.
The JAX-RS specification is built on top of the Servlet specification. Each implementation should have a Servlet as an entry point to the application. When a request comes in, it gets processed by that Servlet. CXFServlet is CXF's implementation of that entry point Servlet.
Does this servlet pose as a front-controller, like in Spring MVC flow?
Pretty much. It's analogous to Spring MVC's DispatcherServlet
What is the actual purpose of using this servlet class?
As mentioned above, it's the entry point to the JAX-RS (CXF) application.
How does CXF use Spring to provide XML configuration of services defined in the project?
It uses Spring to wire up components; connect all of them together. But it's not required (see also).
Does org.glassfish.jersey.servlet.ServletContainer serve the same purpose in Jersey Implementation as org.apache.cxf.transport.servlet.CXFServlet with Apache CXF?
Pretty much.

WEB-INF/myproject-servlet.xml versus WEB-INF/web.xml

I spent few days fixing bugs in my Spring project. For really long time, my main problems in error log were:
Bean already exists
I have got two files:
WEB-INF/myproject-servlet.xml
WEB-INF/web.xml
in first one, I can put following input (let's assume I have got an application to manage animals in zoo):
<context:component-scan base-package="com.my.package.animals" />
with that (as well as I understand) we are enabling Spring beans auto-discovery. So now, when we run our application, Spring will take all classes from this package, later it will go through all config files in resources directory and will inititliaze all beans (placed in config files, which are associated with a given package).
The second one, web.xml includes lines like this
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/myproject-servlet.xml</param-value>
</context-param>
I can also put path to my config files, for instance:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:animals-config.xml</param-value>
</context-param>
So now, I have 'auto-detecting' in myproject-servlet.xml and I have got context-param in web.xml for the same objects.
My question is, is it possible, that errors "Bean already exists" are coming from this? I am almost sure that yes, I checked all beans ids and there is no duplicates.
So I have another question. What is a good approach of doing that? When I create new config file, where I should inform my application about that? In myproject-servlet.xml or web.xml. I really need to clean up my application and I will start with that.
I checked some examples and people rather do not put more than one <context-param> in web.xml file Simple example
Thank you in advance
Ok, I am really close to solve my problem.
Let's assume I have got two packages:
com.my.pckg.a
com.my.pckg.b
with classes
com.my.pckg.a.ClassA
com.my.pckg.b.ClassB
I added in myproject-servlet.xml following line:
<context:component-scan base-package="com.my.pckg.a" />
I have got a config file myconfig.xml and inside I have got beans based on classes ClassA and ClassB.
Let's say we have got beans with ids as follows:
ClassA: ida1, ida2
ClassB: idb1, idb2
So, I am running my jetty server and the question is:
Which beans will be initialized? I declared only package com.my.pckg.a, so from myconfig.xml, spring should load only ida1 and ida2 but this file includes also beans for another class.
So finally... ?
Finally, I suppose I find a problem. In web.xml file I have got a line:
<context:component-scan base-package="com.dirty.pckg" />
in this package I have got a class DirtyClass with #Controller annotation. One of the fields of this class is:
private static ApplicationContext context = new ClassPathXmlApplicationContext("dirty-config.xml");
So, when my application is getting up, Spring takes DirtyClass (because it has #) and maps it. Because os static modifier of context it triggers reading dirty-config.xml. That's way I could not understand why my code behaves in strange way.
The web.xml file is the configuration of your web application. It is not related to Spring.
The contextConfigLocation context-param is the one spring listener use to search for Spring configuration files. It is spring related.
You can have multiple spring configuration files that you register in your web.xml but these files must not define the same bean (bean id must be different). You can also have only one spring configuration file that will it self include other configuration files as described here : http://www.mkyong.com/spring/load-multiple-spring-bean-configuration-file/
Answer to the other question :
When you added the component scan, you ask spring to scan the package com.my.pckg.a for annotation like #Service, #Component, ... The component scan is not a filter for the rest of the configuration it is a configuration itself. So the fact that you added component scan, will not change the behaviour of myconfig.xml. Both ida1, ida2 and idb1, idb2 will be instanciated.
I don't really get what you are trying to accomplished with your configuration files. Maybe if you explain your needs, we could help you set up the right config for you.
web.xml is configuration file. It has classes(like listeners, filters,filter-mapping, servlet,servlet-mapping), resources and configuration(like context param, diplayname, error-page, session-config) of the application and how the web server uses them to handle web requests. When the web server receives a request for the application, it uses web.xml to map the URL of the request to the code that is supposed to handle the request.
Coming to what should be in web.xml and what should be in myproject-servlet.xml:
1)In Spring, ApplicationContext can be hierarchical. One ApplicationContext can have multiple child ApplicationContexts and can only have one parent. Beans in child ApplicationContext can access the beans in parent.
2)DispatcherServlet dispatches requests to handlers(controllers), with configurable handler mappings, view resolution configuration(what view template you use for the application for example jsp).
Keeping the two points in mind, our web.xml should be like:
<!--Root web application context(Parent context) - beans for service or persistence layer should be in this -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:service-layer-beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<!--DispatcherServlet loads its configuration into its own context(chile context) and refers Root web application context as a parent, so it have access to beans in parent context and can override it but not vice versa.-->
<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/myproject-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>

JsonParseExceptionMapper not called by Jersey

I use Jersey and Jackson to implement RESTful services provided by my server. Data is exchanged between the client and server as JSON documents. Jackson does the mapping between the JSON documents and the POJOs. This works well.
But I ran into one issue. When calling a service with a malformed JSON document, the server returns with an 500 error. I would expect a 400 BAD-Request error instead. Some searching in the Jersey docs showed me that ExceptionMappers can be used to archive this behavior. I also found out that Jackson already has a implementation a JsonParseExceptionMapper but it never gets called.
Do I have to register the mapper and if so how can I do this outside of the source code.?
Ok I found out how to register the mapper classes.
In your web.xml where Jersery ServletContainer is registered you have to pass the Jackson package name org.codehaus.jackson.jaxrs beside your package name e.g. com.example.myapp.api;. The server then scans these packages on start up and registers the listener it find.
<servlet>
<servlet-name>Jersey</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.example.myapp.api;org.codehaus.jackson.jaxrs</param-value>
</init-param>
</servlet>

Spring MVC: Using #Autowire is getting references to different spring bean instances

I have a UserCredetnialsDatSourceAdapter defined in my Spring app context file. I also have a custom filter added to the Spring via the DelegatingFilterProxy.
This filter is using the #Autowire to get a reference to the DataSource Bean. I also #Autowire the DataSource in my DAO. When I debug I see different instance id's to the datasource in the Filter and DAO instances. Why are there 2 instances whenthese are singletons by default?
I also fired up jvisualvm and I looked at the heap and all my beans in my app context have 2 instances? Thanks for any insight maybe the bean pre/post processing has something do with it or maybe I should not be using #Autowire in a Filter. Any help is apprciated. Thanks!
EDIT
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/web-context.xml,/WEB-INF/config-context.xml</param-value>
</init-param>
Interesting I think I see what it going on. There are 2 instances because there are 2 contexts. One for the app and 1 for each request (Thread) I assume? Is there a way to specfiy which context to use? Maybe filter is not the answer and I will need to use AOP. Need to research how to inject a bean in #Aspect, if that is even possible.
Thanks!!
-Joe
You are importing your /WEB-INF/config-context.xml as part of your Root Application Context(one loaded up by ContextLoaderListener) as well as your Web Context(loaded by DispatcherServlet). You can probably remove it from the one for DispatcherServlet.

How to dynamically configure the WebLogicCluster property outside of web.xml

I have a web application deployed as war file in weblogic 10.3.3. Now I want to make this application clusterable. For this I'm using the HttpClusterServlet from Weblogic as a load balancer. According to the documentation I can put this servlet configuration into the web.xml
<servlet>
<servlet-name>HttpClusterServlet</servlet-name>
<servlet-class>weblogic.servlet.proxy.HttpClusterServlet</servlet-class>
<init-param>
<param-name>WebLogicCluster</param-name>
<param-value>server-1:7122|server-1:7123</param-value>
</init-param>
</servlet>
The problem is that this configuration is hard wired at build time and can't be reconfigured at runtime. For instance I would like to be able to add 5 more servers dynamically. I had several ideas to solve that problem:
Extend the weblogic.servlet.proxy.HttpClusterServlet with an own servlet implentation. This is not possible, the class is final.
Use a servlet filter to reconfigure the servlet. The servlet is not accessible anymore through ServletContext().getServlet(String) since Java Servlet API 2.1, with no direct replacement.
Reflection might be an option, but I couldn't figure out a reliable way to access the configuration
All of my attempts to reconfigure this init-param externally failed so far. I'm open to any solutions.
This might help How to externalize web.xml servlet init-param? Spring DelegatingFilterProxy for Servlets? Even if your not using Spring it wouldn't be too hard to port that servlet to another IoC container.

Categories