CXF Webservice Using Embedded Jetty

3 篇文章 0 订阅


http://www.javatips.net/blog/2014/06/cxf-webservice-using-embedded-jetty

@BeforeClass
   
public static void setUp() throws Exception {

       
server = new Server();
        Connector connector =
new SelectChannelConnector();
        connector.setPort
(9000);
        server.setConnectors
(new Connector[] { connector });

        WebAppContext wactx =
new WebAppContext();
        wactx.setContextPath
("/CXFRestfulTutorial");
        wactx.setWar
("CXFRestfulTutorial.war");

        HandlerCollection handlers =
new HandlerCollection();
        handlers.setHandlers
(new Handler[] { wactx, new DefaultHandler() });
        server.setHandler
(handlers);

       
try {
           
server.start();
       
} catch (Exception e) {
           
e.printStackTrace();
       
}
    }


==========

Going REST: embedding Jetty with Spring and JAX-RS (Apache CXF)

http://www.javacodegeeks.com/2013/01/going-rest-embedding-jetty-with-spring-and-jax-rs-apache-cxf.html

For hardcore server-side Java developer the only way to ‘speak’ out to the world is by using APIs. Today’s post is all about JAX-RS: writing and exposing RESTful services using Java.

But we won’t do that using a traditional, heavyweight approach involving application server, WAR packaging and whatnot. Instead, we will use awesome Apache CXF framework and as always rely on Spring to wire all pieces together. And for sure we won’t stop on that either as we need a web server to run our services on. Using fat or one jar concept we will embed Jetty server into our application and make our final JAR redistributable (all dependencies included) and runnable.
 

It’s a lot of work so let’s get started. As we stated above, we will use Apache CXF, Spring and Jetty as a building blocks so let’s have them described in a POM file. The one additional dependency worth mentioning is excellent Jackson library for JSON processing.

002    <modelversion>4.0.0</modelversion>
003 
004    <groupid>com.example</groupid>
005    <artifactid>spring-one-jar</artifactid>
006    <version>0.0.1-SNAPSHOT</version>
007    <packaging>jar</packaging>
008 
009    <properties>
010        <project.build.sourceencoding>UTF-8</project.build.sourceencoding>
011        <org.apache.cxf.version>2.7.2</org.apache.cxf.version>
012        <org.springframework.version>3.2.0.RELEASE</org.springframework.version>
013        <org.eclipse.jetty.version>8.1.8.v20121106</org.eclipse.jetty.version>
014    </properties>
015 
016    <dependencies>  
017        <dependency>
018            <groupid>org.apache.cxf</groupid>
019            <artifactid>cxf-rt-frontend-jaxrs</artifactid>
020            <version>${org.apache.cxf.version}</version>
021        </dependency>
022 
023        <dependency>
024            <groupid>javax.inject</groupid>
025            <artifactid>javax.inject</artifactid>
026            <version>1</version>
027        </dependency>
028 
029        <dependency>
030            <groupid>org.codehaus.jackson</groupid>
031            <artifactid>jackson-jaxrs</artifactid>
032            <version>1.9.11</version>
033        </dependency>
034      
035        <dependency>
036            <groupid>org.codehaus.jackson</groupid>
037            <artifactid>jackson-mapper-asl</artifactid>
038            <version>1.9.11</version>
039        </dependency>
040      
041        <dependency>
042            <groupid>cglib</groupid>
043            <artifactid>cglib-nodep</artifactid>
044            <version>2.2</version>
045        </dependency>
046 
047        <dependency>
048            <groupid>org.springframework</groupid>
049            <artifactid>spring-core</artifactid>
050            <version>${org.springframework.version}</version>
051        </dependency>
052 
053        <dependency>
054            <groupid>org.springframework</groupid>
055            <artifactid>spring-context</artifactid>
056            <version>${org.springframework.version}</version>
057        </dependency>
058 
059        <dependency>
060            <groupid>org.springframework</groupid>
061            <artifactid>spring-web</artifactid>
062            <version>${org.springframework.version}</version>
063        </dependency>
064       
065        <dependency>
066            <groupid>org.eclipse.jetty</groupid>
067            <artifactid>jetty-server</artifactid>
068            <version>${org.eclipse.jetty.version}</version>
069        </dependency>
070      
071        <dependency>
072            <groupid>org.eclipse.jetty</groupid>
073            <artifactid>jetty-webapp</artifactid>
074            <version>${org.eclipse.jetty.version</version>
075        </dependency
076    </dependencies>
077 
078    <build>
079        <plugins>
080            <plugin>
081                <groupid>org.apache.maven.plugins</groupid>
082                <artifactid>maven-compiler-plugin</artifactid>
083                <version>3.0</version>
084                <configuration>
085                    <source>1.6</source>
086                    <target>1.6</target>
087                </configuration>
088            </plugin
089            <plugin>
090                <groupid>org.apache.maven.plugins</groupid>
091                <artifactid>maven-jar-plugin</artifactid>
092                <configuration>
093                    <archive>
094                        <manifest>
095                            <mainclass>com.example.Starter</mainclass>
096                        </manifest>
097                    </archive>
098                </configuration>
099            </plugin>
100            <plugin>
101                <groupid>org.dstovall</groupid>
102                <artifactid>onejar-maven-plugin</artifactid>
103                <version>1.4.4</version>
104                <executions>
105                    <execution>
106                        <configuration>
107                            <onejarversion>0.97</onejarversion>
108                            <classifier>onejar</classifier>
109                        </configuration>
110                        <goals>
111                            <goal>one-jar</goal>
112                        </goals>
113                    </execution>
114                </executions>
115            </plugin>
116        </plugins>
117    </build>
118     
119    <pluginrepositories>
120        <pluginrepository>
121            <id>onejar-maven-plugin.googlecode.com</id>
122            <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
123        </pluginrepository>
124    </pluginrepositories>
125  
126    <repositories>
127        <repository>
128            <id>maven2-repository.dev.java.net</id>
129            <url>http://download.java.net/maven/2/</url>
130        </repository>
131    </repositories>
132</project>

It’s a lot of stuff but should be pretty clear. Now, we are ready to develop our first JAX-RS services by starting with simple JAX-RS application.

1package com.example.rs;
2 
3import javax.ws.rs.ApplicationPath;
4import javax.ws.rs.core.Application;
5 
6@ApplicationPath( 'api' )
7public class JaxRsApiApplication extends Application {
8}

As simple as it looks like, our application defines an /api to be the entry path for the JAX-RS services. The sample service will manage people represented by Person class.

01package com.example.model;
02 
03public class Person {
04    private String email;
05    private String firstName;
06    private String lastName;
07 
08    public Person() {
09    }
10 
11    public Person( final String email ) {
12        this.email = email;
13    }
14 
15    public String getEmail() {
16        return email;
17    }
18 
19    public void setEmail( final String email ) {
20        this.email = email;
21    }
22 
23    public String getFirstName() {
24        return firstName;
25    }
26 
27    public String getLastName() {
28        return lastName;
29    }
30 
31    public void setFirstName( final String firstName ) {
32        this.firstName = firstName;
33    }
34 
35    public void setLastName( final String lastName ) {
36        this.lastName = lastName;
37    }
38}

And following bare bones business service (for simplicity, no database or any other storage are included).

01package com.example.services;
02 
03import java.util.ArrayList;
04import java.util.Collection;
05 
06import org.springframework.stereotype.Service;
07 
08import com.example.model.Person;
09 
10@Service
11public class PeopleService {
12    public Collection< Person > getPeople( int page, int pageSize ) {
13        Collection< Person > persons = new ArrayList< Person >( pageSize );
14 
15        for( int index = 0; index < pageSize; ++index ) {
16            persons.add( new Person( String.format( 'person+%d@at.com', ( pageSize * ( page - 1 ) + index + 1 ) ) ) );
17        }
18 
19        return persons;
20    }
21 
22    public Person addPerson( String email ) {
23        return new Person( email );
24    }
25}

As you can see, we will generate a list of persons on the fly depending on the page requested. Standard Spring annotation @Service marks this class as a service bean. Our JAX-RS service PeopleRestService will use it for retrieving persons as the following code demonstrates.

01package com.example.rs;
02 
03import java.util.Collection;
04 
05import javax.inject.Inject;
06import javax.ws.rs.DefaultValue;
07import javax.ws.rs.FormParam;
08import javax.ws.rs.GET;
09import javax.ws.rs.PUT;
10import javax.ws.rs.Path;
11import javax.ws.rs.Produces;
12import javax.ws.rs.QueryParam;
13 
14import com.example.model.Person;
15import com.example.services.PeopleService;
16 
17@Path( '/people' )
18public class PeopleRestService {
19    @Inject private PeopleService peopleService;
20 
21    @Produces( { 'application/json' } )
22    @GET
23    public Collection< Person > getPeople( @QueryParam( 'page') @DefaultValue( '1' ) final int page ) {
24        return peopleService.getPeople( page, 5 );
25    }
26 
27    @Produces( { 'application/json' } )
28    @PUT
29    public Person addPerson( @FormParam( 'email' ) final String email ) {
30        return peopleService.addPerson( email );
31    }
32}

Though simple, this class needs more explanations. First of all, we want to expose our RESTful service to /people endpoint. Combining it with /api (where our JAX-RS application resides), it gives as the /api/people as qualified path.

Now, whenever someone issues HTTP GET to this path, the method getPeople should be invoked. This method accepts optional parameter page (with default value 1) and returns list of persons as JSON. In turn, if someone issues HTTP PUT to the same path, the method addPerson should be invoked (with required parameter email) and return new person as a JSON.

Now let’s take a look on Spring configuration, the core of our application.

01package com.example.config;
02 
03import java.util.Arrays;
04 
05import javax.ws.rs.ext.RuntimeDelegate;
06 
07import org.apache.cxf.bus.spring.SpringBus;
08import org.apache.cxf.endpoint.Server;
09import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
10import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
11import org.springframework.context.annotation.Bean;
12import org.springframework.context.annotation.Configuration;
13 
14import com.example.rs.JaxRsApiApplication;
15import com.example.rs.PeopleRestService;
16import com.example.services.PeopleService;
17 
18@Configuration
19public class AppConfig {
20    @Bean( destroyMethod = 'shutdown' )
21    public SpringBus cxf() {
22        return new SpringBus();
23    }
24 
25    @Bean
26    public Server jaxRsServer() {
27        JAXRSServerFactoryBean factory = RuntimeDelegate.getInstance().createEndpoint( jaxRsApiApplication(), JAXRSServerFactoryBean.class );
28        factory.setServiceBeans( Arrays.< Object >asList( peopleRestService() ) );
29        factory.setAddress( '/' + factory.getAddress() );
30        factory.setProviders( Arrays.< Object >asList( jsonProvider() ) );
31        return factory.create();
32    }
33 
34    @Bean
35    public JaxRsApiApplication jaxRsApiApplication() {
36        return new JaxRsApiApplication();
37    }
38 
39    @Bean
40    public PeopleRestService peopleRestService() {
41        return new PeopleRestService();
42    }
43 
44    @Bean
45    public PeopleService peopleService() {
46        return new PeopleService();
47    }
48 
49    @Bean
50    public JacksonJsonProvider jsonProvider() {
51        return new JacksonJsonProvider();
52    }
53}

It doesn’t look complicated but a lot happens under the hood. Let’s dissect it into the peices. The two key component here are the factory JAXRSServerFactoryBean which does all heavy lifting for configuring our instance of JAX-RS server, and SpringBus instance which seamlessly glues Spring and Apache CXF together. All other components represent regular Spring beans.

What’s not on a picture yet is embedding Jetty web server instance. Our main application class Starter does exactly that.

01package com.example;
02 
03import org.apache.cxf.transport.servlet.CXFServlet;
04import org.eclipse.jetty.server.Server;
05import org.eclipse.jetty.servlet.ServletContextHandler;
06import org.eclipse.jetty.servlet.ServletHolder;
07import org.springframework.web.context.ContextLoaderListener;
08import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
09 
10import com.example.config.AppConfig;
11 
12public class Starter {
13    public static void main( final String[] args ) throws Exception {
14        Server server = new Server( 8080 );
15 
16        // Register and map the dispatcher servlet
17        final ServletHolder servletHolder = new ServletHolder( new CXFServlet() );
18        final ServletContextHandler context = new ServletContextHandler();  
19        context.setContextPath( '/' );
20        context.addServlet( servletHolder, '/rest/*' ); 
21        context.addEventListener( new ContextLoaderListener() );
22 
23        context.setInitParameter( 'contextClass', AnnotationConfigWebApplicationContext.class.getName() );
24        context.setInitParameter( 'contextConfigLocation', AppConfig.class.getName() );
25 
26        server.setHandler( context );
27        server.start();
28        server.join();
29    }
30}

Looking through this code uncovers that we are running Jetty server instance on port 8080, we are configuring Apache CXF servlet to handle all request at /rest/* path (which together with our JAX-RS application and service gives us the /rest/api/people), we are adding Spring context listener parametrized with the configuration we have defined above and finally we are starting server up. What we have at this point is full-blown web server hosting our JAX-RS services. Let’s see it in action. Firstly, let’s package it as single, runnable and redistributable fat or one jar:

1mvn clean package

Let’s pick up the bits from the target folder and run them:

1java -jar target/spring-one-jar-0.0.1-SNAPSHOT.one-jar.jar

And we should see the output like that:

012013-01-19 11:43:08.636:INFO:oejs.Server:jetty-8.1.8.v20121106
022013-01-19 11:43:08.698:INFO:/:Initializing Spring root WebApplicationContext
03Jan 19, 2013 11:43:08 AM org.springframework.web.context.ContextLoader initWebApplicationContext
04INFO: Root WebApplicationContext: initialization started
05Jan 19, 2013 11:43:08 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
06INFO: Refreshing Root WebApplicationContext: startup date [Sat Jan 19 11:43:08 EST 2013]; root of context hierarchy
07Jan 19, 2013 11:43:08 AM org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider registerDefaultFilters
08INFO: JSR-330 'javax.inject.Named' annotation found and supported for component scanning
09Jan 19, 2013 11:43:08 AM org.springframework.web.context.support.AnnotationConfigWebApplicationContext loadBeanDefinitions
10INFO: Successfully resolved class for [com.example.config.AppConfig]
11Jan 19, 2013 11:43:09 AM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
12INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
13Jan 19, 2013 11:43:09 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
14INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1f8166e5:
15defining beans [org.springframework.context.annotation.internal
16ConfigurationAnnotationProcessor,
17org.springframework.context.annotation.internalAutowiredAnnotationProcessor,
18org.springframework.context.annotation.internalRequiredAnnotationProces
19sor,org.springframework.context.annotation.internalCommonAnnotationProcessor,appConfig,
20org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,c
21xf,jaxRsServer,jaxRsApiApplication,peopleRestService,peopleService,jsonProvider]; root of factory hierarchy
22Jan 19, 2013 11:43:10 AM org.apache.cxf.endpoint.ServerImpl initDestination
23INFO: Setting the server's publish address to be /api
24Jan 19, 2013 11:43:10 AM org.springframework.web.context.ContextLoader initWebApplicationContext
25INFO: Root WebApplicationContext: initialization completed in 2227 ms
262013-01-19 11:43:10.957:INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null}
272013-01-19 11:43:11.019:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8080

Having our server up and running, let’s issue some HTTP requests to it so to be sure everything works just as we expected:

01> curl http://localhost:8080/rest/api/people?page=2
02[
03  {'email':'person+6@at.com','firstName':null,'lastName':null},
04  {'email':'person+7@at.com','firstName':null,'lastName':null},
05  {'email':'person+8@at.com','firstName':null,'lastName':null},
06  {'email':'person+9@at.com','firstName':null,'lastName':null},
07  {'email':'person+10@at.com','firstName':null,'lastName':null}
08]
09 
10> curl http://localhost:8080/rest/api/people -X PUT -d 'email=a@b.com'
11{'email':'a@b.com','firstName':null,'lastName':null}

Awesome! And please notice, we are completely XML-free! Source code: https://github.com/reta/spring-one-jar/tree/jetty-embedded

Before ending the post, I would like to mention one great project, Dropwizard, which uses quite similar concepts but pushes it to the level of excellent, well-designed framework, thanks to Yammer guys for that.
 

Reference: Going REST: embedding Jetty with Spring and JAX-RS (Apache CXF) from our JCG partner Andrey Redko at the Andriy Redko {devmind} blog.




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值