知識庫 / Spring RSS 訂閱

使用Spring的Apache CXF 指南

Spring
HongKong
4
02:49 PM · Dec 06 ,2025

1. 概述

本教程重點介紹如何配置和使用 Apache CXF 框架與 Spring 的結合 – 無論是使用 Java 還是 XML 配置。

它是 Apache CXF 系列的第二篇,第一篇重點介紹了 CXF 作為 JAX-WS 標準 API 的實現。

2. Maven 依賴

類似於之前的教程,需要包含以下兩個依賴項:

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxws</artifactId>
    <version>4.0.5</version>
</dependency>
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-transports-http</artifactId>
    <version>4.0.5</version>
</dependency>

要查看 Apache CXF 最新版本的 Artifact,請訪問 apache-cxf

此外,以下依賴項是支持 Spring 所必需的:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>6.1.8</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>6.1.8</version>
</dependency>

最新版本的 Spring 構件可以在這裏找到:這裏

此外,由於我們將使用 Java Servlet 3.0+ API 編程方式地配置應用程序,而不是使用傳統的 web.xml 部署描述符,因此我們需要以下構件:

<dependency>
   <groupId>jakarta.servlet</groupId>
   <artifactId>jakarta.servlet-api</artifactId>
   <version>6.1.0</version>
   <scope>provided</scope>
</dependency>

此處是我們查找 Servlet API 最新版本的地點。

3. 服務器端組件

現在我們來探討一下為了發佈 Web 服務端點時,服務器端需要存在的組件。

3.1. WebApplicationInitilizer 接口

WebApplicationInitilizer 接口用於通過編程方式配置應用程序的 ServletContext 接口。當該接口在類路徑上存在時,其 onStartup 方法將由 Servlet 容器自動調用,之後 ServletContext 將被實例化並初始化。

以下是如何定義一個類來實現 WebApplicationInitializer 接口的示例:

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

onStartup() 方法的實現方式,如以下代碼片段所示。

首先,創建一個 Spring 應用上下文並配置它以註冊包含配置元數據的類:

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

ServiceConfiguration 類使用@Configuration 註解進行標註,以提供 Bean 定義。有關此類的更多信息,請參閲下一小節。

以下代碼片段展示瞭如何將 Spring 應用上下文添加到 Servlet 上下文中:

container.addListener(new ContextLoaderListener(context));

CXFServlet 類,由 Apache CXF 定義,用於處理傳入的請求並進行生成和註冊。

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

應用程序上下文加載配置文件的 Spring 定義元素。在這種情況下,servlet 的名稱是 cxf,因此上下文默認會在名為 cxf-servlet.xml 的文件中查找這些元素。

最後,CXF servlet 映射到一個相對 URL。

dispatcher.addMapping("/services");

3.2. 懷舊的 `web.xml

如果希望利用傳統的部署描述符,而不是 WebApplicationInitilizer 接口,則相應的 web.xml 文件應包含以下 Servlet 定義:

<servlet>
    <servlet-name>cxf</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
    <servlet-mapping>
    <servlet-name>cxf</servlet-name>
    <url-pattern>/services/*</url-pattern>
</servlet-mapping>

3.3. ServiceConfiguration

現在,讓我們來查看一下服務配置——首先是一個基本的骨架,它包含對 Web 服務端點的 Bean 定義:

@Configuration
public class ServiceConfiguration {
    // Bean definitions
}

第一種必需的 Bean 是 SpringBus – 它為 Apache CXF 提供擴展,使其能夠與 Spring Framework 配合工作:

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

一個 EnpointImpl Bean 也需要使用 SpringBus Bean 和一個 Web 服務 實現者 創建。該 Bean 用於在給定的 HTTP 地址上發佈 Endpoint:

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

BaeldungImpl 類用於實現 Web 服務接口。其定義將在下一節中給出。

或者,我們也可以在 XML 配置文件中聲明服務器端點。具體而言,下面的 cxf-servlet.xml 文件與在 3.1 節中定義的 web.xml 部署描述符一起使用,並描述了相同的端點:

<jaxws:endpoint
  id="baeldung"
  implementor="com.baeldung.cxf.spring.BaeldungImpl"
  address="http://localhost:8080/services/baeldung" />

請注意,XML 配置文件的名稱與部署描述文件中定義的 servlet 名稱相同,即 cxf

3.4. 類型定義

以下是先前小節中已提及的 實現者 的定義:

@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;
    }
}

此類提供了一個用於 Baeldung 端點接口的實現,Apache CXF 將在發佈的 WSDL 元數據中包含該實現:

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

端點接口以及實施者都使用學生類,該類定義如下:

public class Student {
    private String name;

    // constructors, getters and setters
}

4. 客户端 Bean

為了充分利用 Spring Framework,我們在一個帶有 @Configuration 註解的類中聲明一個 Bean:

@Configuration
public class ClientConfiguration {
    // Bean definitions
}

定義一個名為 client 的 Bean:

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

客户端 Bean 代表了 Baeldung Web 服務的代理。它通過對 create 方法在 JaxWsProxyFactoryBean Bean 上進行的調用創建的,該 Bean 是 JAX-WS 代理創建工廠。

JaxWsProxyFactoryBean 對象由以下方法創建和配置:

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

工廠的 serviceClass 屬性表示 Web 服務接口,而 address 屬性則指示代理用於遠程調用所使用的 URL 地址。

對於客户端的 Spring Bean,也可以回退到 XML 配置文件。以下元素聲明瞭與我們在上述程序性配置中剛剛配置的相同 Bean:

<bean id="client" factory-bean="clientFactory" factory-method="create" />
<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
    <property name="serviceClass" value="com.baeldung.cxf.spring.Baeldung" />
    <property name="address" value="http://localhost:8080/services/baeldung" />
</bean>

5. 測試用例

本節描述了用於演示 Apache CXF 對 Spring 的支持的測試用例。測試用例定義在一個名為 StudentTest 的類中。

首先,我們需要從上述的 ServiceConfiguration 配置類中加載 Spring 應用上下文,並將其緩存到 context 字段中:

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

接下來,聲明並從應用程序上下文加載服務端點接口的代理:

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

Baeldung 代理將在下面描述的測試用例中被使用。

在第一個測試用例中,我們證明當代理上本地調用 hello 方法時,響應與端點 implementor 從遠程 Web 服務返回的完全相同:

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

在第二個測試用例中,學生通過在代理對象上本地調用 register 方法來註冊 Baeldung 課程,這反過來又會調用 Web 服務。該 Web 服務將計算學生的學號並將其返回給調用者。以下代碼片段確認了我們的預期:

@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. 集成測試

為了將其作為 Web 應用程序部署到服務器上,本教程中的代碼片段需要首先打包成 WAR 文件。這可以通過在 POM 文件中聲明 packaging 屬性來實現:

<packaging>war</packaging>

打包任務由 Maven WAR 插件執行:

<plugin>
    <artifactId>maven-war-plugin</artifactId>
    <version>3.4.0</version>
    <configuration>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </configuration>
</plugin>

此插件將編譯後的源代碼打包成WAR文件。由於我們使用Java代碼配置servlet上下文,因此傳統的web.xml部署描述符就不需要存在。因此,在執行插件時,必須將failOnMissingWebXml屬性設置為false,以避免失敗。

可以參考這個鏈接獲取最新的Maven WAR插件。

為了説明Web服務的操作,我們創建了一個集成測試。該測試首先生成WAR文件並啓動嵌入式服務器,然後讓客户端調用Web服務,驗證後續響應,最後停止服務器。

需要包含在Maven POM文件中以下插件:有關更多詳細信息,請查看此集成測試教程。

以下是Maven Surefire插件:

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
    <configuration>
        <excludes>
            <exclude>StudentTest.java</exclude>
        </excludes>
    </configuration>
</plugin>

最新版本的此插件可以在 這裏找到。

已聲明一個 配置 部分,其 ID集成,以方便集成測試:

<profiles>
   <profile>
      <id>integration</id>
      <build>
         <plugins>
            ...
         </plugins>
      </build>
   </profile>
</profiles>

Maven Cargo 插件包含在 集成 配置文件中:

<plugin>
    <groupId>org.codehaus.cargo</groupId>
    <artifactId>cargo-maven2-plugin</artifactId>
    <version>1.5.0</version>
    <configuration>
        <container>
            <containerId>jetty9x</containerId>
            <type>embedded</type>
        </container>
        <configuration>
            <properties>
                <cargo.hostname>localhost</cargo.hostname>
                <cargo.servlet.port>8080</cargo.servlet.port>
            </properties>
        </configuration>
    </configuration>
    <executions>
        <execution>
            <id>start-server</id>
            <phase>pre-integration-test</phase>
            <goals>
                <goal>start</goal>
            </goals>
        </execution>
        <execution>
            <id>stop-server</id>
            <phase>post-integration-test</phase>
            <goals>
                <goal>stop</goal>
            </goals>
        </execution>
    </executions>
</plugin>

請注意,cargo.hostnamecargo.servlet.port 配置屬性僅用於提供清晰度。由於其值與默認值相同,因此可以省略這些配置屬性,而不會對應用程序產生任何影響。此插件啓動服務器,等待連接,並最終停止服務器以釋放系統資源。

此處 允許我們查看 Maven Cargo 插件的最新版本。

Maven Surefire 插件在 integration 配置文件中再次聲明,以覆蓋主 build 部分中的配置,並執行上一部分中描述的測試用例:

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
    <executions>
        <execution>
            <phase>integration-test</phase>
            <goals>
                <goal>test</goal>
            </goals>
            <configuration>
                <excludes>
                    <exclude>none</exclude>
                </excludes>
            </configuration>
        </execution>
    </executions>
</plugin>

現在整個過程可以通過以下命令運行:mvn -Pintegration clean install

7. 結論

本教程介紹了 Apache CXF 對 Spring 的支持。 尤其,它展示瞭如何使用 Spring 配置文件發佈 Web 服務,以及客户端如何通過 Apache CXF 代理工廠創建的代理與該服務進行交互,該代理工廠在另一個配置文件中聲明。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.