Eine Anleitung zu Apache CXF mit Spring

Ein Leitfaden für Apache CXF mit Spring

1. Überblick

Dieses Tutorial konzentriert sich auf die Konfiguration undusing the Apache CXF framework together with Spring - entweder mit Java- oder XML-Konfiguration.

Es ist der zweite Teil einer Reihe zu Apache CXF. the first one konzentrierte sich auf die Grundlagen von CXF als Implementierung der JAX-WS-Standard-APIs.

2. Maven-Abhängigkeiten

Ähnlich wie im vorherigen Lernprogramm müssen die folgenden zwei Abhängigkeiten enthalten sein:


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


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

Die neuesten Versionen von Apache CXF-Artefakten finden Sie unterapache-cxf.

Darüber hinaus sind die folgenden Abhängigkeiten erforderlich, um Spring zu unterstützen:


    org.springframework
    spring-context
    4.3.1.RELEASE


    org.springframework
    spring-webmvc
    4.3.1.RELEASE

Die neuesten Versionen von Spring-Artefakten finden Sie inhere.

Da wir die Anwendung programmgesteuert mithilfe der Java Servlet 3.0+ -API anstelle des herkömmlichen Deployment-Deskriptorsweb.xmlkonfigurieren, benötigen wir das folgende Artefakt:


    javax.servlet
    javax.servlet-api
    3.1.0

InThis finden wir die neueste Version der Servlet-API.

3. Serverseitige Komponenten

Schauen wir uns nun die Komponenten an, die auf der Serverseite vorhanden sein müssen, um den Webdienst-Endpunkt zu veröffentlichen.

3.1. WebApplicationInitilizer Schnittstelle

DieWebApplicationInitializer-Schnittstelle wird implementiert, um dieServletContext-Schnittstelle für die Anwendung programmgesteuert zu konfigurieren. Wenn es im Klassenpfad vorhanden ist, wird seineonStartup-Methode automatisch vom Servlet-Container aufgerufen, und danach wirdServletContext instanziiert und initialisiert.

So wird eine Klasse definiert, um die Schnittstelle vonWebApplicationInitializerzu implementieren:

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

DieonStartup()-Methode wird mithilfe der unten gezeigten Codefragmente implementiert.

Zunächst wird ein Spring-Anwendungskontext erstellt und konfiguriert, um eine Klasse mit Konfigurationsmetadaten zu registrieren:

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

Die KlasseServiceConfiguration wird mit der Annotation@Configurationannotiert, um Bean-Definitionen bereitzustellen. Diese Klasse wird im nächsten Unterabschnitt behandelt.

Das folgende Snippet zeigt, wie der Spring-Anwendungskontext zum Servlet-Kontext hinzugefügt wird:

container.addListener(new ContextLoaderListener(context));

Die KlasseCXFServlet, die von Apache CXF definiert wird, wird generiert und registriert, um eingehende Anforderungen zu verarbeiten:

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

Der Anwendungskontext lädt die in einer Konfigurationsdatei definierten Federelemente. In diesem Fall lautet der Name des Servletscxf. Daher sucht der Kontext standardmäßig nach diesen Elementen in einer Datei mit dem Namencxf-servlet.xml.

Zuletzt wird das CXF-Servlet einer relativen URL zugeordnet:

dispatcher.addMapping("/services");

3.2. Das gute alteweb.xml

Wenn wir alternativ einen (etwas altmodischen) Bereitstellungsdeskriptor anstelle derWebApplicationInitilizer-Schnittstelle verwenden möchten, sollte die entsprechendeweb.xml-Datei die folgenden Servlet-Definitionen enthalten:


    cxf
    org.apache.cxf.transport.servlet.CXFServlet
    1

    
    cxf
    /services/*

3.3. ServiceConfiguration Klasse

Schauen wir uns nun die Dienstkonfiguration an - zunächst ein Grundgerüst, das Bean-Definitionen für den Webdienst-Endpunkt enthält:

@Configuration
public class ServiceConfiguration {
    // Bean definitions
}

Die erste erforderliche Bean istSpringBus - die Erweiterungen für Apache CXF bereitstellt, um mit dem Spring Framework zu arbeiten:

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

EineEnpointImpl-Bean muss auch mit derSpringBus-Bean und einem Webdienstimplementor erstellt werden. Diese Bean wird verwendet, um den Endpunkt unter der angegebenen HTTP-Adresse zu veröffentlichen:

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

Die KlasseexampleImplwird zum Implementieren der Webdienstschnittstelle verwendet. Seine Definition ist im nächsten Unterabschnitt angegeben.

Alternativ können wir den Server-Endpunkt auch in einer XML-Konfigurationsdatei deklarieren. Insbesondere funktioniert die folgendecxf-servlet.xml-Datei mit dem in Unterabschnitt 3.1 definierten Bereitstellungsdeskriptorweb.xmlund beschreibt genau denselben Endpunkt:

Beachten Sie, dass die XML-Konfigurationsdatei nach dem im Bereitstellungsdeskriptor definierten Servlet-Namencxf benannt ist.

3.4. Typdefinitionen

Weiter - hier ist die Definition derimplementor, die bereits im vorhergehenden Unterabschnitt erwähnt wurde:

@WebService(endpointInterface = "com.example.cxf.spring.example")
public class exampleImpl implements example {
    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;
    }
}

Diese Klasse bietet eine Implementierung für die Endpunktschnittstelle vonexample, die Apache CXF in die veröffentlichten WSDL-Metadaten aufnehmen wird:

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

Sowohl die Endpunktschnittstelle als auch dieimplementor verwenden die KlasseStudent, die wie folgt definiert ist:

public class Student {
    private String name;

    // constructors, getters and setters
}

4. Clientseitige Bohnen

Um das Spring Framework nutzen zu können, deklarieren wir eine Bean in der mit Anmerkungen versehenen Klasse@Configuration:

@Configuration
public class ClientConfiguration {
    // Bean definitions
}

Eine Bean mit dem Namenclient ist definiert:

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

Die Beanclient repräsentiert einen Proxy für den Webdienstexample. Es wird durch einen Aufruf dercreate-Methode auf einerJaxWsProxyFactoryBean-Bean erstellt, einer Factory zum Erstellen von JAX-WS-Proxys.

DasJaxWsProxyFactoryBean-Objekt wird mit der folgenden Methode erstellt und konfiguriert:

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

Die Factory-EigenschaftserviceClasskennzeichnet die Webdienstschnittstelle, während die Eigenschaftaddressdie URL-Adresse angibt, unter der der Proxy Remote-Aufrufe durchführen soll.

Auch für die Spring Beans auf der Clientseite kann auf eine XML-Konfigurationsdatei zurückgegriffen werden. Die folgenden Elemente deklarieren dieselben Beans wie die, die wir gerade programmgesteuert oben konfiguriert haben:



    
    

5. Testfälle

In diesem Abschnitt werden Testfälle beschrieben, die zur Veranschaulichung der Apache CXF-Unterstützung für Spring verwendet werden. Die Testfälle werden in einer Klasse mit dem NamenStudentTest definiert.

Zuerst müssen wir einen Spring-Anwendungskontext aus der oben genannten KonfigurationsklasseServiceConfigurationladen und im Feldcontextzwischenspeichern:

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

Als Nächstes wird ein Proxy für die Service-Endpunkt-Schnittstelle deklariert und aus dem Anwendungskontext geladen:

private example exampleProxy = (example) context.getBean("client");

Dieserexample-Proxy wird in den unten beschriebenen Testfällen verwendet.

Im ersten Testfall beweisen wir, dass beim lokalen Aufrufen der Methodehello auf dem Proxy die Antwort genau der Antwort entspricht, die der Endpunktimplementor vom Remote-Webdienst zurückgibt:

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

Im zweiten Testfall registrieren sich die Schüler beispielsweise für Kurse, indem sie lokal dieregister-Methode auf dem Proxy aufrufen, der wiederum den Webdienst aufruft. Dieser entfernte Dienst berechnet dann die Schülernummern und gibt sie an den Anrufer zurück. Das folgende Code-Snippet bestätigt, was wir erwarten:

@Test
public void whenUsingRegisterMethod_thenCorrect() {
    Student student1 = new Student("Adam");
    Student student2 = new Student("Eve");
    String student1Response = exampleProxy.register(student1);
    String student2Response = exampleProxy.register(student2);

    assertEquals("Adam is registered student number 1", student1Response);
    assertEquals("Eve is registered student number 2", student2Response);
}

6. Integrationstests

Um als Webanwendung auf einem Server bereitgestellt zu werden, müssen die Codeausschnitte in diesem Lernprogramm zuerst in eine WAR-Datei gepackt werden. Dies kann erreicht werden, indem die Eigenschaftpackagingin der POM-Datei deklariert wird:

war

Der Paketierungsjob wird vom Maven WAR-Plugin implementiert:


    maven-war-plugin
    2.6
    
        false
    

Dieses Plugin packt den kompilierten Quellcode in eine WAR-Datei. Da wir den Servlet-Kontext mithilfe von Java-Code konfigurieren, muss der Bereitstellungsdeskriptor des herkömmlichenweb.xmlnicht vorhanden sein. Infolgedessen muss die EigenschaftfailOnMissingWebXml auffalse gesetzt werden, um einen Fehler bei der Ausführung des Plugins zu vermeiden.

Wir könnenthis link für die neueste Version des Maven WAR-Plugins folgen.

Um die Funktionsweise des Webservices zu veranschaulichen, erstellen wir einen Integrationstest. Dieser Test generiert zunächst eine WAR-Datei und startet einen eingebetteten Server. Anschließend rufen Clients den Webdienst auf, überprüfen nachfolgende Antworten und stoppen den Server.

Die folgenden Plugins müssen in der Maven POM-Datei enthalten sein. Weitere Informationen finden Sie unterthis Integration Testing tutorial.

Hier ist das Maven Surefire Plugin:


    maven-surefire-plugin
    2.19.1
    
        
            StudentTest.java
        
    

Die neueste Version dieses Plugins finden Sie unterhere.

Einprofile-Abschnitt mitid vonintegration wird deklariert, um den Integrationstest zu erleichtern:


   
      integration
      
         
            ...
         
      
   

Das Maven Cargo-Plugin ist im Profil vonintegrationenthalten:


    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
            
        
    

Beachten Sie, dass die Konfigurationseigenschaftencargo.hostname undcargo.servlet.portnur der Übersichtlichkeit halber enthalten sind. Diese Konfigurationseigenschaften können ohne Auswirkung auf die Anwendung ausgelassen werden, da ihre Werte mit den Standardwerten übereinstimmen. Dieses Plugin startet den Server, wartet auf Verbindungen und stoppt schließlich den Server, um Systemressourcen freizugeben.

This link ermöglicht es uns, die neueste Version des Maven Cargo-Plugins zu testen.

Das Maven Surefire-Plugin wird innerhalb desintegration-Profils erneut deklariert, um seine Konfiguration im Hauptabschnittbuildzu überschreiben und die im vorherigen Abschnitt beschriebenen Testfälle auszuführen:


    maven-surefire-plugin
    2.19.1
    
        
            integration-test
            
                test
            
            
                
                    none
                
            
        
    

Jetzt kann der gesamte Prozess mit dem folgenden Befehl ausgeführt werden:mvn -Pintegration clean install.

7. Fazit

Dieses Tutorial zeigt die Apache CXF-Unterstützung für Spring. Insbesondere wurde gezeigt, wie ein Webdienst mithilfe einer Spring-Konfigurationsdatei veröffentlicht werden kann und wie ein Client mit diesem Dienst über einen Proxy interagieren kann, der von einer Apache CXF-Proxy-Factory erstellt wurde, die in einer anderen Konfigurationsdatei deklariert wurde.

Die Implementierung all dieser Beispiele und Codefragmente finden Sie inthe linked GitHub project.