Spring Cache With CXF Web Service
Spring Cache With CXF Web Service explains step by step details of Creating / Developing Webservices using Apache CXF, Eclipse & Spring Cache
Spring cache is the caching implementation available in spring framework, By using cache we can reduce the response time. we can avail this feature by using spring framework 3.1 or greater.
By using caching technique, we can reduce the method invocation and reduce the response time dramatically, this is because we don't need to query the backend information for each call, but we are caching the information in memory
You can see the below example, which is demonstrate Spring Cache With CXF Web Service
Required Libraries
You need to download
Following jar must be in classpath (You need to download spring 3.1 or higher separately)
- aopalliance-1.0.jar
- commons-logging-1.1.1.jar
- cxf-2.7.3.jar
- httpasyncclient-4.0-beta3.jar
- httpclient-4.2.1.jar
- httpcore-4.2.2.jar
- httpcore-nio-4.2.2.jar
- neethi-3.0.2.jar
- org.springframework.aop-3.1.1.RELEASE.jar
- org.springframework.asm-3.1.1.RELEASE.jar
- org.springframework.beans-3.1.1.RELEASE.jar
- org.springframework.context-3.1.1.RELEASE.jar
- org.springframework.core-3.1.1.RELEASE.jar
- org.springframework.expression-3.1.1.RELEASE.jar
- org.springframework.web-3.1.1.RELEASE.jar
- wsdl4j-1.6.2.jar
- jaxb-impl-2.2.6.jar
- javax.ws.rs-api-2.0-m10.jar
- cglib-nodep-2.1_3.jar
- jettison-1.3.3.jar (JSON library)
Spring Cache With CXF Web Service
I am creating a sample restful service project that pass Student object and return with some changes on that object. The service is using simple POJO (Plain Old Java Object) bean.
Firstly create a Dynamic Web Project (File->New->Dynamic Web Project) named "CXFRestfulTutorial" according to following screenshot
Create a Student Object
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "Student")
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Create a Service Interface
This service interface will defines which methods of restful service, to be invoked by the client
Here we implement the service interface created on the previous step
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.springframework.cache.annotation.Cacheable;
@Consumes("application/json")
@Produces("application/json")
public class ChangeStudentDetailsImpl{
@Cacheable(value="student", key="#student.name")
@POST
@Path("/changeName")
public Student changeName(Student student) {
System.out.println("Inside changeName method");
student.setName("HELLO " + student.getName());
return student;
}
}
Create a cxf.xml
You need to add
for working on annotations and also need to specify which cacheManager we are using
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:cxf="http://cxf.apache.org/core" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml" /> <cache:annotation-driven /> <cxf:bus> <cxf:features> <cxf:logging /> </cxf:features> </cxf:bus> <jaxrs:server address="/rest" id="base"> <jaxrs:serviceBeans> <ref bean="StudentService" /> </jaxrs:serviceBeans> </jaxrs:server> <bean class="com.student.ChangeStudentDetailsImpl" id="StudentService" /> <!-- Spring Cache library setup --> <bean class="org.springframework.cache.support.SimpleCacheManager" id="cacheManager"> <property name="caches"> <set> <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default" /> <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="student" /> </set> </property> </bean> </beans>
Change web.xml
Change the web.xml file to find CXF servlet and cxf.xml
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 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>contextConfigLocation</param-name> <param-value>WEB-INF/cxf.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
Publishing CXF Restful Service
Deployed CXF Restful Service
Now just call "CXF Restful Client" in order to run this restful service
Need to change the code like following on client
URL url = new URL("http://localhost:8080/CXFRestfulTutorial/rest/changeName");
Here I am calling the client twice and showing the result below, From the result you can see that "Inside changeName method" is showing only once, this is because when first request is coming from client response is cached after that Student object is returned from the cache
Output
Aug 29, 2012 3:56:47 AM org.apache.cxf.interceptor.LoggingInInterceptor INFO: Inbound Message ---------------------------- ID: 2 Address: http://localhost:8080/CXFRestfulTutorial/rest/changeName Encoding: ISO-8859-1 Http-Method: POST Content-Type: application/json Headers: {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], connection=[keep-alive], Content-Length=[26], content-type=[application/json], host=[localhost:8080], user-agent=[Java/1.7.0_03]} Payload: {"Student":{"name":"Tom"}} -------------------------------------- Inside changeName method Aug 29, 2012 3:56:50 AM org.apache.cxf.interceptor.LoggingOutInterceptor INFO: Outbound Message --------------------------- ID: 2 Response-Code: 200 Content-Type: application/json Headers: {Date=[Tue, 28 Aug 2012 22:26:50 GMT]} Payload: {"Student":{"name":"HELLO Tom"}} --------------------------------------
Aug 29, 2012 4:05:19 AM org.apache.cxf.interceptor.LoggingInInterceptor INFO: Inbound Message ---------------------------- ID: 3 Address: http://localhost:8080/CXFRestfulTutorial/rest/changeName Encoding: ISO-8859-1 Http-Method: POST Content-Type: application/json Headers: {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], connection=[keep-alive], Content-Length=[26], content-type=[application/json], host=[localhost:8080], user-agent=[Java/1.7.0_03]} Payload: {"Student":{"name":"Tom"}} -------------------------------------- Aug 29, 2012 4:05:24 AM org.apache.cxf.interceptor.LoggingOutInterceptor INFO: Outbound Message --------------------------- ID: 3 Response-Code: 200 Content-Type: application/json Headers: {Date=[Tue, 28 Aug 2012 22:35:22 GMT]} Payload: {"Student":{"name":"HELLO Tom"}} --------------------------------------