I am using jersey client to send POST requests to a third party webservice. Since creating jersey clients is expensive, I am doing this inside the constructor of a service client class which is Spring managed. My thinking is that when my server starts up, Spring will create my service client bean, which in turn will cause the constructor to be invoked and so my jersey client will be created once. As long as the server is up, this jersey client will be responsible for sending out the requests and no further client initializations are required. However, I will be creating a new webresource for each call as creating jersey webresources is much cheaper.
package com.mypackage;
//Bunch of imports
class MyWebserviceClient {
//jersey client member variable
private Client jClient;
public MyWebserviceClient(){
//Create jersey client
jClient = Client.create();
//Other stuff
}
public void sendRequest(){
WebResource wr = jClient.resource(someUrl);
//Use the webresource to make webservice call
}
}
MyWebserviceClient is spring managed as such in the Spring config xml:
<bean id="myClient" class="com.mypackage,MyWebserviceClient"></bean>
The bean myClient will then be injected into the appropriate place where the service call needs to be made.
My questions
1) If my application is dealing with thousands of requests per hour is it efficient enough to handle all the requests with just one jersey client.
2) Do I need some kind of jersey client pool so that a large number of requests are taken care of more efficiently. If so, is there a way to do it?
3) I would like to know in general how multiple requests coming in from the end users are handled on the server side. Each request is a separate thread of execution on the server and all of them have access to the same jersey client object. If the jersey client object is busy with one such request, are the other requests from different end users going to wait till a response is received for the ongoing request?
4) Any better alternative to the one I am using.
Your thinking is right on track.
1 - Yes, and it is recommended to reuse a client instance:
from https://jersey.java.net/documentation/1.18/client-api.html#d4e623:
Client instances are expensive resources. It is recommended a configured instance is reused for the creation of Web resources. The creation of Web resources, the building of requests and receiving of responses are guaranteed to be thread safe. Thus a Client instance and WebResource instances may be shared between multiple threads.
2 - No need, the client itself can handle the requests. In the case of asynchronous requests, it internally uses a thread pool that is configurable.
3 - The Jersey client is thread safe, so threads will not block each other
4 - You can also consider providing the client as a dependency to MyWebserviceClient, and possibly reuse the same client between multiple classes
Related
It`s possible to register one filter in RestEasy that will works for any instance? Today I have a lot of services thats use one client
for example:
Client client = ClientBuilder.newClient();
WebTarget target = client.target(ulrBase);
ResteasyWebTarget rtarget = (ResteasyWebTarget) target;
this.servico = rtarget.proxy(UsuarioServiceClient.class);
but now I have to pass one header prop, so I create this:
public class AuthHeadersRequestFilter implements ClientRequestFilter {
#Override
public void filter(ClientRequestContext requestContext) throws IOException {
requestContext.getHeaders().add("xx-Authorization", ((IntegraUI) UI.getCurrent()).getSessionToken());
}
}
but for all Client I need to insert this line:
client.register(new AuthHeadersRequestFilter());
So, can I configure to every place i create one client, this filter will be registered automatic?
tks
A step back
How many Client instances are you playing with?
Client instances are heavy-weight objects and you are supposed to have only a small number of instances and reuse them when possible. Have a look at the documentation:
Clients are heavy-weight objects that manage the client-side communication infrastructure. Initialization as well as disposal of a Client instance may be a rather expensive operation. It is therefore advised to construct only a small number of Client instances in the application. Client instances must be properly closed before being disposed to avoid leaking resources.
Registering filters and interceptors
RESTEasy won't register filters and interceptors automatically on your Client. It happens on server side when a filter or interceptor is annotated with #Provider. But on client side, you must register the filters and interceptors manually.
Instead of registering filters and interceptors in the Client instance, you could register them in a Configuration instance and use it to create the Client instance:
Configuration config = new Configuration();
config.register(MyClientResponseFilter.class);
config.register(new AnotherClientFilter());
Client client = ClientBuilder.newClient(config);
It might be useful when creating more than one client with the same configuration.
Create a javax.ws.rs-ap.jar client and send the request to the server:
javax.ws.rs.client.Client client = ClientBuilder.newBuilder().build();
I have writtten the above code to call multiple api(get user by id, get all users and deleteUser).
My question is here.
I am creating a new Client for each api cal.
Just wanted to know i can create a single instance of Client and make multiple calls ?
Yes, a Client can be reused as long as it's lifecycle is managed properly. This means when a client instance is created, it should be closed properly as well using the close() method, once it's purpose is served. Refer to the Client API documentation.
Note that multiple client instances would be needed if each client has a different client configuration.
i am creating a http REST service that consumes other http REST services.
I am using Jersey Client to call other services and i have many doubt about which creation pattern of the http client is the best.
Currently i am using EJB with injection of the client that is a Singleton shared by every methods, but i would like to remove java ee dependency and use Jetty as embedded application server.
I see from the doc that Client creation is an expensive operation so i cannot create one every time i need it.
I think about creating 1 in the constructor of every Servlet/Rest class is the simpler solution but i am not sure about the lifecycle of the servlet (if an instance is created for every request, this method is quite the same as the previous)
Or maybe is better to create a Singleton shared by every Servlet/Rest class
Or maybe better a pool of N client.
About this last two solution i need some advice... What do you think it's the better solution?
Thanks
According to you, there is a REST Service deployed in some environment and there is one application, a client or consumer, which wants to access that service.
If i am writing a normal Java class as client using Jersey API, then i will write something lime this :
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
Client client = Client.create();
WebResource webResource = client
.resource("http://localhost:8080/rest/example/employees");
ClientResponse response = webResource.accept("application/json")
.get(ClientResponse.class);
String result = response.getEntity(String.class);
Now say you are writing a servlet, which does some defined job in you application, also it makes a call to the REST Service using client block of code, everytime you access the servlet it will create a instance of com.sun.jersey.api.client.Client each time.
If you want to avoid this then you can create a initial class that will create an instance of com.sun.jersey.api.client.Client, one and only, and make it static and use the same reference where ever you want. WebResource should be created as and when required, because you might be interested to call different URIs.
I would have followed this approach, if i were in your situation.
I use Servlet/EJB model. When the user requests for a statement report for his past transactions, it takes hours for the server to generate the report. So the response is not sent from the server till the request is processed.
For eg.
Client requests report -> Servlet receives request -> Calls EJB to process it , EJB generates the report after hours -> sends response to servlet -> responds to Client.
But is it possible to respond to the user as soon as the request is received in the servlet.
For eg.
Client requests report -> Servlet receives request -> Servlet responds
'Report will be available soon'
Servlet -> Calls EJB to process it , EJB generates the report
after hours -> sends response to servlet ->responds to Client when
client requests the report again.
That is , can I create a thread from Servlet and use that for calling the EJB, while the Servlet responds to the user stating that the request will be processed soon
Your scenario screams for the asynchronous communication. That is, you should rewrite your application to have three different methods:
first one receives a request, generates unique ID which is immediately returned to the client and invokes EJB to generate the report; its signature would be something like:
public String generateReportRequest(Object requestParameter) { .. }
second one receives a unique ID and checks with EJB whether the report generation is done; its signature would be:
public boolean isReportGenerated(String uniqueID) { .. }
third one actually returns the report, but it should be invoked only when the second one returned that the report is ready:
public Object returnReport(String uniqueID) { .. }
Since we are dealing with three methods, I would not recommend mixing servlets and EJBs, but instead turning EJBs into Web services, if that's suitable (just annotate your stateless bean with #WebService annotation and adjust the client).
In case that you need to have Servlets for some reason, don't create a new thread - read this answer to see why it is highly discouraged in Java EE application server. Instead, you can use message-driven beans - just put the request on the message queue and return the answer to the client; MDB will process it asynchronously.
Third option is to check asynchronous method invocation in Java EE.
I am developing a very simple REST web service with Eclipse, Tomcat7 and Jersey implementation, with a connection to MySQL.
Looking to the jersey documentation i know that every request create a new object of the root resource class. But i dont know if every request is independet, for example if one request have to wait a long time, the server will accept more request normaly?
The problem is :
I have 2 main classes, 1 class implements Jersey with annotations(Proxy.java), and other class that connects to a BD(Notificator.java), there is only one instance of this class (Singleton) in order to use only 1 Connection object. The classes who implements Jersey use this class. So, if one of the request is blocked , i dont know if the others will run because they are using the same (Notificator.java) instance.
The relation is N instances of(Proxy.java) uses the only one (Notificator.java) witch have one Connection to a MySQL.
Jersey is developed on top of servlets. There is a new thread for each of the incoming request. Your code is creating a bottleneck for all the threads as there is a contention for single available connection object. If you have multiple requests then only one request will be using that connection and others have to wait. If the wait is not too long then there is no problem. But if wait is more than the HTTP REQUEST TIMEOUT then your other requests may end up as TIMED OUT.
I understand that you may be having single connection bottleneck due to some business requriement/ complication. So in all such cases where we cannot process all the requests simulataneously and there can be variety of reasons for it, then we should create our web services as Asynchronous. Asynchronous web services work on the model of SUBMIT REQUEST-> REQUEST ACCEPTED(will be processed asynchronously) and JOB URL returned for polling-> CLIENT POLLS till the JOB IS NOT COMPLETED.
Hope it helps!
Try database connection pooling, more on this here:
http://en.wikipedia.org/wiki/Connection_pool
How to establish a connection pool in JDBC?