Panduan untuk Apache CXF dengan Spring

1. Gambaran keseluruhan

Tutorial ini memfokuskan pada mengkonfigurasi dan menggunakan kerangka Apache CXF bersama dengan Spring - sama ada dengan konfigurasi Java atau XML.

Ini adalah yang kedua dalam siri di Apache CXF; yang pertama tertumpu pada asas-asas CXF sebagai pelaksanaan API standard JAX-WS.

2. Pergantungan Maven

Sama seperti tutorial sebelumnya, dua pergantungan berikut perlu disertakan:

 org.apache.cxf cxf-rt-frontend-jaxws 3.1.6   org.apache.cxf cxf-rt-transports-http 3.1.6 

Untuk artefak versi terbaru Apache CXF, sila lihat apache-cxf.

Di samping itu, kebergantungan berikut diperlukan untuk menyokong Spring:

 org.springframework spring-context 4.3.1.RELEASE   org.springframework spring-webmvc 4.3.1.RELEASE 

Versi terbaru artifak Spring boleh didapati di sini.

Akhirnya, kerana kami akan mengkonfigurasi aplikasi secara teratur menggunakan Java Servlet 3.0+ API dan bukannya deskriptor penyebaran web.xml tradisional , kami memerlukan artifak di bawah:

 javax.servlet javax.servlet-api 3.1.0 

Di sinilah kita dapat mencari versi terbaru dari Servlet API.

3. Komponen Bahagian Pelayan

Sekarang mari kita lihat komponen yang perlu ada di sisi pelayan untuk menerbitkan titik akhir perkhidmatan web.

3.1. Antaramuka WebApplicationInitilizer

Antara muka WebApplicationInitializer dilaksanakan untuk mengkonfigurasi antara muka ServletContext secara terprogram untuk aplikasi. Apabila hadir di classpath, kaedah onStartup secara automatik dipanggil oleh servlet container dan selepas itu ServletContext disusun dan dimulakan.

Inilah cara kelas ditentukan untuk melaksanakan antara muka WebApplicationInitializer :

public class AppInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext container) { // Method implementation } }

Kaedah onStartup () dilaksanakan menggunakan coretan kod yang ditunjukkan di bawah.

Pertama, konteks aplikasi Spring dibuat dan dikonfigurasi untuk mendaftarkan kelas yang mengandungi metadata konfigurasi:

AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.register(ServiceConfiguration.class);

The ServiceConfiguration kelas adalah dijelaskan dengan @Configuration anotasi untuk memberikan definisi kacang. Kelas ini dibincangkan dalam subseksyen seterusnya.

Coretan berikut menunjukkan bagaimana konteks aplikasi Spring ditambahkan ke konteks servlet:

container.addListener(new ContextLoaderListener(context));

The CXFServlet kelas, yang ditakrifkan oleh Apache CXF, dihasilkan dan berdaftar untuk mengendalikan permintaan yang diterima:

ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new CXFServlet());

Konteks aplikasi memuat elemen Spring yang ditentukan dalam fail konfigurasi. Dalam kes ini, nama servlet adalah cxf , oleh itu konteks mencari elemen-elemen tersebut dalam fail bernama cxf-servlet.xml secara lalai.

Terakhir, servlet CXF dipetakan ke URL relatif:

dispatcher.addMapping("/services");

3.2. Laman web Old Good.xml

Sebagai alternatif, jika kita ingin menggunakan deskriptor penyebaran (agak kuno) dan bukan antara muka WebApplicationInitilizer , fail web.xml yang sesuai harus mengandungi definisi servlet berikut:

 cxf org.apache.cxf.transport.servlet.CXFServlet 1   cxf /services/* 

3.3. Kelas Konfigurasi Perkhidmatan

Sekarang mari kita lihat konfigurasi perkhidmatan - pertama kerangka asas yang merangkumi definisi kacang untuk titik akhir perkhidmatan web:

@Configuration public class ServiceConfiguration { // Bean definitions }

Kacang pertama yang diperlukan ialah SpringBus - yang menyediakan sambungan agar Apache CXF dapat berfungsi dengan Spring Framework:

@Bean public SpringBus springBus() { return new SpringBus(); }

An EnpointImpl kacang juga perlu dicipta menggunakan SpringBus kacang dan perkhidmatan web pelaksana . Kacang ini digunakan untuk menerbitkan titik akhir pada alamat HTTP yang diberikan:

@Bean public Endpoint endpoint() { EndpointImpl endpoint = new EndpointImpl(springBus(), new BaeldungImpl()); endpoint.publish("//localhost:8080/services/baeldung"); return endpoint; }

The BaeldungImpl kelas digunakan untuk melaksanakan antara muka perkhidmatan web. Definisinya diberikan dalam subseksyen berikutnya.

Sebagai alternatif, kami juga boleh menyatakan titik akhir pelayan dalam fail konfigurasi XML. Secara khusus, fail cxf-servlet.xml di bawah berfungsi dengan penerangan penyebaran web.xml seperti yang didefinisikan dalam subseksyen 3.1 dan menerangkan titik akhir yang sama:

Perhatikan bahawa fail konfigurasi XML dinamai nama servlet yang ditentukan dalam deskriptor penyebaran, yang merupakan cxf .

3.4. Jenis Definisi

Seterusnya - berikut adalah definisi pelaksana yang telah disebutkan dalam subseksyen sebelumnya:

@WebService(endpointInterface = "com.baeldung.cxf.spring.Baeldung") public class BaeldungImpl implements Baeldung { private int counter; public String hello(String name) { return "Hello " + name + "!"; } public String register(Student student) { counter++; return student.getName() + " is registered student number " + counter; } }

Kelas ini menyediakan pelaksanaan bagi Baeldung muka titik akhir yang Apache CXF akan termasuk dalam metadata WSDL yang diterbitkan:

@WebService public interface Baeldung { String hello(String name); String register(Student student); }

Kedua-dua antara muka titik akhir dan pelaksana menggunakan kelas Pelajar , yang ditakrifkan sebagai berikut:

public class Student { private String name; // constructors, getters and setters }

4. Kacang Sebelah Pelanggan

Untuk memanfaatkan Spring Framework, kami menyatakan kacang dalam kelas anotasi @Configuration :

@Configuration public class ClientConfiguration { // Bean definitions }

Kacang dengan nama pelanggan ditentukan:

@Bean(name = "client") public Object generateProxy() { return proxyFactoryBean().create(); }

The client bean represents a proxy for the Baeldung web service. It is created by an invocation to the create method on a JaxWsProxyFactoryBean bean, a factory for the creation of JAX-WS proxies.

The JaxWsProxyFactoryBean object is created and configured by the following method:

@Bean public JaxWsProxyFactoryBean proxyFactoryBean() { JaxWsProxyFactoryBean proxyFactory = new JaxWsProxyFactoryBean(); proxyFactory.setServiceClass(Baeldung.class); proxyFactory.setAddress("//localhost:8080/services/baeldung"); return proxyFactory; }

The factory's serviceClass property denotes the web service interface, while the address property indicates the URL address for the proxy to make remote invocations.

Also for the Spring beans on the client side one may revert to an XML configuration file. The following elements declare the same beans as the ones we just have programmatically configured above:

5. Test Cases

This section describes test cases used to illustrate Apache CXF support for Spring. The test cases are defined in a class named StudentTest.

First, we need to load a Spring application context from the aforementioned ServiceConfiguration configuration class and cache it in the context field:

private ApplicationContext context = new AnnotationConfigApplicationContext(ClientConfiguration.class);

Next, a proxy for the service endpoint interface is declared and loaded from the application context:

private Baeldung baeldungProxy = (Baeldung) context.getBean("client");

This Baeldung proxy will be used in test cases described below.

In the first test case, we prove that when the hello method is locally invoked on the proxy, the response is exactly the same as what the endpoint implementor returns from the remote web service:

@Test public void whenUsingHelloMethod_thenCorrect() { String response = baeldungProxy.hello("John Doe"); assertEquals("Hello John Doe!", response); }

In the second test case, students register for Baeldung courses by locally invoking the register method on the proxy, which in turn calls the web service. That remote service will then calculate the student numbers and return them to the caller. The following code snippet confirms what we expect:

@Test public void whenUsingRegisterMethod_thenCorrect() { Student student1 = new Student("Adam"); Student student2 = new Student("Eve"); String student1Response = baeldungProxy.register(student1); String student2Response = baeldungProxy.register(student2); assertEquals("Adam is registered student number 1", student1Response); assertEquals("Eve is registered student number 2", student2Response); }

6. Integration Testing

In order to be deployed as a web application on a server, code snippets in this tutorial need to be packaged into a WAR file first. This can be achieved by declaring the packaging property in the POM file:

war

The packaging job is implemented by the Maven WAR plugin:

 maven-war-plugin 2.6  false  

This plugin packages the compiled source code into a WAR file. Since we configure the servlet context using Java code, the traditional web.xml deployment descriptor does not need to be existent. As the result, the failOnMissingWebXml property must be set to false to avoid failure when the plugin is executed.

We can follow this link for the most recent version of the Maven WAR plugin.

In order to illustrate operations of the web service, we create an integration test. This test first generates a WAR file and starts an embedded server, then makes clients invoke the web service, verifies subsequent responses and finally stops the server.

The following plugins need to be included in the Maven POM file. For more details, please check out this Integration Testing tutorial.

Here is the Maven Surefire plugin:

 maven-surefire-plugin 2.19.1   StudentTest.java   

The latest version of this plugin can be found here.

A profile section with the id of integration is declared to facilitate the integration test:

  integration   ...    

The Maven Cargo plugin is included in the integration profile:

 org.codehaus.cargo cargo-maven2-plugin 1.5.0   jetty9x embedded    localhost 8080      start-server pre-integration-test  start    stop-server post-integration-test  stop    

Note that the cargo.hostname and cargo.servlet.port configuration properties are merely included for the sake of clarity. These configuration properties may be left out without any impact on the application since their values are the same as the default values. This plugin starts the server, waits for connections and finally stops the server to release system resources.

This link allows us to check out the latest version of the Maven Cargo plugin.

Plugin Maven Surefire dinyatakan lagi, dalam profil integrasi , untuk mengatasi konfigurasinya di bahagian binaan utama dan untuk melaksanakan kes ujian yang dijelaskan di bahagian sebelumnya:

 maven-surefire-plugin 2.19.1   integration-test  test    none     

Sekarang keseluruhan proses dapat dijalankan dengan perintah: mvn -Pintegration clean install .

7. Kesimpulannya

Tutorial ini menggambarkan sokongan Apache CXF untuk Spring. Secara khusus, telah ditunjukkan bagaimana perkhidmatan web dapat diterbitkan menggunakan file konfigurasi Spring, dan bagaimana klien dapat berinteraksi dengan perkhidmatan tersebut melalui proksi yang dibuat oleh kilang proksi Apache CXF, yang dinyatakan dalam fail konfigurasi lain.

Pelaksanaan semua contoh dan coretan kod ini terdapat dalam projek GitHub yang dipautkan.