javascript
jax-ws cxf_走向REST:在Spring和JAX-RS(Apache CXF)中嵌入Jetty
jax-ws cxf
對于服務器核心Java開發人員來說,向世界“展示”的唯一方法是使用API??。 今天的帖子都是關于JAX-RS的 :使用Java編寫和公開RESTful服務。
但是,我們不會使用涉及應用程序服務器,WAR打包以及諸如此類的傳統的重量級方法來做到這一點。 相反,我們將使用很棒的Apache CXF框架,并且一如既往地依靠Spring將所有組件連接在一起。 當然,我們也不會停止,因為我們需要一個Web服務器來運行我們的服務。 使用胖子或一個罐子的概念,我們將Jetty服務器嵌入到我們的應用程序中,并使最終的JAR可重新分發(包括所有依賴項)并且可運行。
這是很多工作,所以讓我們開始吧。 如前所述,我們將使用Apache CXF , Spring和Jetty作為構建塊,因此讓我們在POM文件中對其進行描述。 值得一提的另一個依賴項是出色的用于JSON處理的Jackson庫。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelversion>4.0.0</modelversion><groupid>com.example</groupid><artifactid>spring-one-jar</artifactid><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><properties><project.build.sourceencoding>UTF-8</project.build.sourceencoding><org.apache.cxf.version>2.7.2</org.apache.cxf.version><org.springframework.version>3.2.0.RELEASE</org.springframework.version><org.eclipse.jetty.version>8.1.8.v20121106</org.eclipse.jetty.version></properties><dependencies> <dependency><groupid>org.apache.cxf</groupid><artifactid>cxf-rt-frontend-jaxrs</artifactid><version>${org.apache.cxf.version}</version></dependency><dependency><groupid>javax.inject</groupid><artifactid>javax.inject</artifactid><version>1</version></dependency><dependency><groupid>org.codehaus.jackson</groupid><artifactid>jackson-jaxrs</artifactid><version>1.9.11</version></dependency><dependency><groupid>org.codehaus.jackson</groupid><artifactid>jackson-mapper-asl</artifactid><version>1.9.11</version></dependency><dependency><groupid>cglib</groupid><artifactid>cglib-nodep</artifactid><version>2.2</version></dependency><dependency><groupid>org.springframework</groupid><artifactid>spring-core</artifactid><version>${org.springframework.version}</version></dependency><dependency><groupid>org.springframework</groupid><artifactid>spring-context</artifactid><version>${org.springframework.version}</version></dependency><dependency><groupid>org.springframework</groupid><artifactid>spring-web</artifactid><version>${org.springframework.version}</version></dependency><dependency><groupid>org.eclipse.jetty</groupid><artifactid>jetty-server</artifactid><version>${org.eclipse.jetty.version}</version></dependency><dependency><groupid>org.eclipse.jetty</groupid><artifactid>jetty-webapp</artifactid><version>${org.eclipse.jetty.version</version></dependency> </dependencies><build><plugins><plugin><groupid>org.apache.maven.plugins</groupid><artifactid>maven-compiler-plugin</artifactid><version>3.0</version><configuration><source>1.6</source><target>1.6</target></configuration></plugin> <plugin><groupid>org.apache.maven.plugins</groupid><artifactid>maven-jar-plugin</artifactid><configuration><archive><manifest><mainclass>com.example.Starter</mainclass></manifest></archive></configuration></plugin><plugin><groupid>org.dstovall</groupid><artifactid>onejar-maven-plugin</artifactid><version>1.4.4</version><executions><execution><configuration><onejarversion>0.97</onejarversion><classifier>onejar</classifier></configuration><goals><goal>one-jar</goal></goals></execution></executions></plugin></plugins></build><pluginrepositories><pluginrepository><id>onejar-maven-plugin.googlecode.com</id><url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url></pluginrepository></pluginrepositories><repositories><repository><id>maven2-repository.dev.java.net</id><url>http://download.java.net/maven/2/</url></repository></repositories> </project>它有很多東西,但是應該很清楚。 現在,我們準備從簡單的JAX-RS應用程序開始開發第一個JAX-RS服務。
package com.example.rs;import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application;@ApplicationPath( 'api' ) public class JaxRsApiApplication extends Application { }看起來很簡單,我們的應用程序將/ api定義為JAX-RS服務的入口路徑。 該樣本服務將管理由Person類代表的人員 。
package com.example.model;public class Person {private String email;private String firstName;private String lastName;public Person() {}public Person( final String email ) {this.email = email;}public String getEmail() {return email;}public void setEmail( final String email ) {this.email = email;}public String getFirstName() {return firstName;}public String getLastName() {return lastName;}public void setFirstName( final String firstName ) {this.firstName = firstName;}public void setLastName( final String lastName ) {this.lastName = lastName;} }并遵循基本的業務服務(為簡單起見,不包括數據庫或任何其他存儲)。
package com.example.services;import java.util.ArrayList; import java.util.Collection;import org.springframework.stereotype.Service;import com.example.model.Person;@Service public class PeopleService {public Collection< Person > getPeople( int page, int pageSize ) {Collection< Person > persons = new ArrayList< Person >( pageSize );for( int index = 0; index < pageSize; ++index ) {persons.add( new Person( String.format( 'person+%d@at.com', ( pageSize * ( page - 1 ) + index + 1 ) ) ) );}return persons;}public Person addPerson( String email ) {return new Person( email );} }如您所見,我們將根據請求的頁面動態生成人員列表。 標準的Spring注釋@Service將此類標記為服務bean。 我們的JAX-RS服務PeopleRestService將使用它來檢索人員,如以下代碼所示。
package com.example.rs;import java.util.Collection;import javax.inject.Inject; import javax.ws.rs.DefaultValue; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam;import com.example.model.Person; import com.example.services.PeopleService;@Path( '/people' ) public class PeopleRestService {@Inject private PeopleService peopleService;@Produces( { 'application/json' } )@GETpublic Collection< Person > getPeople( @QueryParam( 'page') @DefaultValue( '1' ) final int page ) {return peopleService.getPeople( page, 5 );}@Produces( { 'application/json' } )@PUTpublic Person addPerson( @FormParam( 'email' ) final String email ) {return peopleService.addPerson( email );} }雖然簡單,但該類需要更多說明。 首先,我們要向/ people端點公開我們的RESTful服務。 將其與/ api (我們的JAX-RS應用程序所在的位置)組合,則以/ api / people作為限定路徑給出。
現在,只要有人向該路徑發出HTTP GET ,就應該調用方法getPeople 。 此方法接受可選的參數頁面 (默認值為1),并以JSON形式返回人員列表。 反過來,如果有人向同一路徑發出HTTP PUT ,則應調用addPerson方法(使用必需的參數email ),并將new person作為JSON返回。
現在,讓我們看一下應用程序的核心Spring配置。
package com.example.config;import java.util.Arrays;import javax.ws.rs.ext.RuntimeDelegate;import org.apache.cxf.bus.spring.SpringBus; import org.apache.cxf.endpoint.Server; import org.apache.cxf.jaxrs.JAXRSServerFactoryBean; import org.codehaus.jackson.jaxrs.JacksonJsonProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;import com.example.rs.JaxRsApiApplication; import com.example.rs.PeopleRestService; import com.example.services.PeopleService;@Configuration public class AppConfig { @Bean( destroyMethod = 'shutdown' )public SpringBus cxf() {return new SpringBus();}@Beanpublic Server jaxRsServer() {JAXRSServerFactoryBean factory = RuntimeDelegate.getInstance().createEndpoint( jaxRsApiApplication(), JAXRSServerFactoryBean.class );factory.setServiceBeans( Arrays.< Object >asList( peopleRestService() ) );factory.setAddress( '/' + factory.getAddress() );factory.setProviders( Arrays.< Object >asList( jsonProvider() ) );return factory.create();}@Bean public JaxRsApiApplication jaxRsApiApplication() {return new JaxRsApiApplication();}@Bean public PeopleRestService peopleRestService() {return new PeopleRestService();}@Bean public PeopleService peopleService() {return new PeopleService();}@Beanpublic JacksonJsonProvider jsonProvider() {return new JacksonJsonProvider();} }它看起來并不復雜,但是在后臺卻發生了很多事情。 讓我們將其分解為香料。 這里的兩個關鍵組件是工廠JAXRSServerFactoryBean ,它為配置我們的JAX-RS服務器實例提供了所有繁重的工作,而SpringBus實例則將 Spring和Apache CXF無縫地粘合在一起。 所有其他組件代表常規的Spring Bean。
圖片上還沒有嵌入Jetty Web服務器實例。 我們的主要應用程序類Starter正是這樣做的。
package com.example;import org.apache.cxf.transport.servlet.CXFServlet; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.springframework.web.context.ContextLoaderListener; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;import com.example.config.AppConfig;public class Starter {public static void main( final String[] args ) throws Exception {Server server = new Server( 8080 );// Register and map the dispatcher servletfinal ServletHolder servletHolder = new ServletHolder( new CXFServlet() );final ServletContextHandler context = new ServletContextHandler(); context.setContextPath( '/' );context.addServlet( servletHolder, '/rest/*' ); context.addEventListener( new ContextLoaderListener() );context.setInitParameter( 'contextClass', AnnotationConfigWebApplicationContext.class.getName() );context.setInitParameter( 'contextConfigLocation', AppConfig.class.getName() );server.setHandler( context );server.start();server.join(); } }瀏覽此代碼后,我們發現我們正在端口8080上運行Jetty服務器實例,我們正在配置Apache CXF servlet來處理/ rest / *路徑上的所有請求(連同我們的JAX-RS應用程序和服務一起為我們提供了/ rest / api / people ),我們使用上面定義的配置添加了參數化的Spring上下文偵聽器,最后啟動了服務器。 此時,我們擁有的是托管我們的JAX-RS服務的功能完善的Web服務器。 讓我們來看看它的作用。 首先,讓我們將其包裝為單個,可運行和可再分配的脂肪或一個罐子 :
mvn clean package讓我們從目標文件夾中拾取位并運行它們:
java -jar target/spring-one-jar-0.0.1-SNAPSHOT.one-jar.jar我們應該看到這樣的輸出:
2013-01-19 11:43:08.636:INFO:oejs.Server:jetty-8.1.8.v20121106 2013-01-19 11:43:08.698:INFO:/:Initializing Spring root WebApplicationContext Jan 19, 2013 11:43:08 AM org.springframework.web.context.ContextLoader initWebApplicationContext INFO: Root WebApplicationContext: initialization started Jan 19, 2013 11:43:08 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing Root WebApplicationContext: startup date [Sat Jan 19 11:43:08 EST 2013]; root of context hierarchy Jan 19, 2013 11:43:08 AM org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider registerDefaultFilters INFO: JSR-330 'javax.inject.Named' annotation found and supported for component scanning Jan 19, 2013 11:43:08 AM org.springframework.web.context.support.AnnotationConfigWebApplicationContext loadBeanDefinitions INFO: Successfully resolved class for [com.example.config.AppConfig] Jan 19, 2013 11:43:09 AM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring Jan 19, 2013 11:43:09 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1f8166e5: defining beans [org.springframework.context.annotation.internal ConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalRequiredAnnotationProces sor,org.springframework.context.annotation.internalCommonAnnotationProcessor,appConfig, org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,c xf,jaxRsServer,jaxRsApiApplication,peopleRestService,peopleService,jsonProvider]; root of factory hierarchy Jan 19, 2013 11:43:10 AM org.apache.cxf.endpoint.ServerImpl initDestination INFO: Setting the server's publish address to be /api Jan 19, 2013 11:43:10 AM org.springframework.web.context.ContextLoader initWebApplicationContext INFO: Root WebApplicationContext: initialization completed in 2227 ms 2013-01-19 11:43:10.957:INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null} 2013-01-19 11:43:11.019:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8080讓我們的服務器啟動并運行,讓我們向它發出一些HTTP請求,以確保一切都按預期運行:
> curl http://localhost:8080/rest/api/people?page=2 [{'email':'person+6@at.com','firstName':null,'lastName':null},{'email':'person+7@at.com','firstName':null,'lastName':null},{'email':'person+8@at.com','firstName':null,'lastName':null}, {'email':'person+9@at.com','firstName':null,'lastName':null}, {'email':'person+10@at.com','firstName':null,'lastName':null} ]> curl http://localhost:8080/rest/api/people -X PUT -d 'email=a@b.com' {'email':'a@b.com','firstName':null,'lastName':null}太棒了! 并且請注意,我們完全不使用XML ! 源代碼: https : //github.com/reta/spring-one-jar/tree/jetty-embedded
在結束這篇文章之前,我想提到一個很棒的項目Dropwizard ,它使用了非常相似的概念,但是由于Yammer的支持,所以將其推向了出色的,精心設計的框架。
參考: 走向REST:在Andriy Redko {devmind}博客上,從我們的JCG合作伙伴 Andrey Redko 嵌入Jetty與Spring和JAX-RS(Apache CXF) 。
翻譯自: https://www.javacodegeeks.com/2013/01/going-rest-embedding-jetty-with-spring-and-jax-rs-apache-cxf.html
jax-ws cxf
總結
以上是生活随笔為你收集整理的jax-ws cxf_走向REST:在Spring和JAX-RS(Apache CXF)中嵌入Jetty的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Redis Client Lettuce
- 下一篇: gradle idea java ssm