Рубрики
Без рубрики

Микросервисы SOAP с загрузкой Spring, Часть 1 с использованием Apache CXF

Это первая часть серии статей, в которых мы создаем микросервисы SOAP с помощью Spring Boot us… С тегами java, микросервисы, весенняя загрузка, мыло.

Это первая часть серии статей, в которых мы создаем микросервисы SOAP с загрузкой Spring, используя несколько библиотек для реализации SOAP. В этой статье объясняется реализация с помощью библиотеки Apache CXF. Я создал WSDL с импортированным XSD-файлом, представляющим службу из устаревшей системы, которую мы хотим обновить до архитектуры микросервиса. Я покажу вам шаги по созданию кода и внедрению сервиса.

Если вы хотите пропустить введение и перейти непосредственно к коду, то вы можете найти его в моем репозитории GitHub ws-employee-soapcxf

jpontdia/ws-сотрудник-soapcxf

Микросервисы SOAP с Spring Boot 2.3 и Apache CXF 3.4

Контейнер docker, созданный с помощью Spring Boot, предоставляющий конечную точку SOAP для устаревшего клиента

Технический стек для этого POC – это:

  • Пружинный ботинок 2.3.4
  • Ява 15
  • Apache CXF 3.4
  • БУДЬТЕ Уверены 4.3
  • Докер

Требования к программному обеспечению

Рабочая станция должна быть правильно настроена с помощью следующих инструментов:

Дополнительные инструменты

WSDL и модель домена

В нашем примере мы собираемся работать в вымышленном сервисе SOAP для сотрудников с 2 операциями:

  • Получить employeebyid
  • Получить имя пользователя

Для демонстрации я отделил XSD от WSDL. В реальном сценарии это будет наиболее распространенный шаблон, но ожидается, что в разных папках будет более одного XSD. В employee.xsd имеет полную доменную модель для службы, на следующей диаграмме показан основной ответ, отправленный клиенту

WSDL-файл…

Вступление

Просто подожди… Микросервисы МЫЛА? В настоящее время у нас есть различные архитектуры микросервисов, основанные на таких технологиях, как веб-сервисы REST или протоколы RPC, такие как gRPC. Так почему же мы должны быть заинтересованы в реализации микросервиса с использованием старого протокола, такого как SOAP? Что ж, это может быть особенно полезно, когда вы находитесь на пути миграции из старого устаревшего монолитного приложения, где у вас есть другие системы, подключенные к нему через службы SOAP. Существует множество сценариев, в которых эти системы (клиенты) не могут быть обновлены, поэтому их нельзя подключить к новой инфраструктуре, например:

  • У компании нет исходного кода этих клиентов, поверьте мне, это происходит очень часто или она не знает исходную версию, развернутую на производстве.
  • Нет никаких людских ресурсов или технической поддержки для применения изменений и тестирования устаревших клиентов.
  • Стоимость их обновления чрезвычайно высока по причине, упомянутой ранее, или из-за необходимости уплаты лицензионных сборов
  • Обновление этих клиентов не приносит никакой пользы для бизнеса организации, поэтому нет необходимости менять что-то, что работает правильно, только потому, что вы внедряете новую архитектуру.

Среди этих и других причин нам необходимо предоставить один и тот же интерфейс для этих старых клиентов.

Получите WSDL для службы

Получить WSDL из существующего веб-сервиса SOAP очень просто; стандартизированный способ сделать это (хотя это может зависеть от структуры, используемой для создания веб-сервиса), заключается в последующей фиксации URL-адреса с помощью ? WSDL-файл или .WSDL пример:

http://mywebservice.domain:8080/endpoint?WSDL

Этот подход обычно известен как “сначала контракт”; мы начинаем с контракта WSDL, а затем используем Java для его реализации. Много раз WSDL поставляется с моделью домена в отдельных Xsd-файлах.

В нашем примере мы собираемся работать в вымышленном сервисе SOAP для сотрудников с 2 операциями:

  • Получить employeebyid
  • Получить имя пользователя

Для демонстрации я отделил XSD от WSDL. Это будет наиболее распространенный шаблон, но ожидается, что в разных папках будет более одного XSD. В employee.xsd имеет полную доменную модель для службы. На следующей диаграмме показан основной ответ, отправленный клиенту.

WSDL используется для описания функциональности веб-службы на основе SOAP. Наиболее важным разделом этой статьи является wsdl:Тип порта . В этом разделе определяется интерфейс для службы, которую мы хотим реализовать: операции, входные и выходные параметры:

Далее идет раздел WSDL для wsdl:Тип порта :



    
        
        
    
    
        
        
    

Полный файл WSDL находится здесь: Employee Services.wsdl

Настройка проекта

В проекте используется maven, а также свойства и зависимости pom.xml являются ли эти:


    
    
    4.3.1
    3.0.2

    
    15
    3.4.0
    2.3.3.RELEASE



    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.projectlombok
        lombok
        true
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
        
            
                org.junit.vintage
                junit-vintage-engine
            
        
    

    
        
        org.apache.cxf
        cxf-spring-boot-starter-jaxws
        ${cxf.version}
    
    
    
        org.apache.cxf
        cxf-rt-features-logging
        ${cxf.version}    
    

    
    
        io.rest-assured
        rest-assured
        test
    

Записи:

  • Будьте Уверены. На момент написания статьи мы используем последнюю версию. Для версии 4.3.1 требуется groovy 3.0.2; мы архивируем правильную конфигурацию, переопределяя родительские библиотеки pom с помощью свойств pom
  • Apache CXF. Зависимость cxf-rt-функции-ведение журнала требуется только в том случае, если нам нужно зарегистрировать запрос/ответ. Эта демонстрационная версия выводит полезную нагрузку запроса/ответа на консоль приложения.

Генерация кода

Мы создадим классы java, которые соответствуют модели предметной области и операциям, описанным в WSDL. Мы собираемся использовать плагин maven из проекта Apache CXF для генерации кода.

Файлы XSD и wsdl расположены в следующей структуре:


├───src
    └───main
        └───resources
            └───wsdl

Далее идет настройка плагина в pom.xml


    org.apache.cxf
    cxf-codegen-plugin
    ${cxf.version}
    
        
            generate-sources
            generate-sources
            
                ${project.build.directory}/generated-sources/cxf
                
                                            ${basedir}/src/main/resources/wsdl/EmployeeServices.wsdl  
                    
                
            
            
                wsdl2java
            
        
    

Плагин создаст классы java в следующем каталоге:

/target/generated-sources/cxf

Создайте классы java, запустив их в окне командной строки в корневом каталоге проекта:

mvn compile

На следующем изображении показаны сгенерированные классы и выделен тот, который мы будем использовать в качестве конечной точки для реализации веб-сервиса: EmployeeServicePortType.

  • Доменные классы. Это элементы XSD-файла, которые представляют входные и выходные параметры веб-службы. Классы: Адрес, Сотрудник, Ответ Сотрудника, Запрос Сотрудника По Идентификатору, Запрос Сотрудника По Имени.
  • Классы WSDL. Эти классы описывают операции службы и ее входные и выходные элементы: Служба сотрудников, EmployeeServicePortType.

Настройка среды выполнения Apache CXF

Конфигурация проста. В application.yml мы можем переопределить базовый путь для Apache CXF, по умолчанию это /сервисы в нашем примере мы будем использовать /мыло.

cxf:
  path: /soap

Нам нужно указать путь для выставленной службы: /служба/сотрудник . Мы предоставляем эту конфигурацию, создавая конечную точку @Bean:

import org.springframework.context.annotation.Configuration;

import javax.xml.ws.Endpoint;

@Configuration
public class ApplicationConfiguration {

    @Autowired
    private Bus bus;

    @Bean
    public Endpoint endpoint(EmployeeEndpoint employeeEndpoint) {
        EndpointImpl endpoint = new EndpointImpl(bus, employeeEndpoint);
        endpoint.publish("/service/employee");
        return endpoint;
    }
}

Внедрение сервиса

Одним из сгенерированных классов является Тип порта службы сотрудника как описано wsdl: раздел типа порта . Это интерфейс с 2 операциями и параметрами ввода/вывода. В следующем примере мы создадим класс Конечная точка сотрудника , которая реализует Тип порта службы сотрудника . В демонстрационных целях мы используем поддельный сервер, который будет предоставлять данные для сервиса. Серверной частью может быть, например, хранилище данных или другая веб-служба.

import lombok.extern.slf4j.Slf4j;
import org.apache.cxf.feature.Features;
import org.springframework.stereotype.Service;
import com.jpworks.employee.*;

@Service
@Slf4j
@Features(features = "org.apache.cxf.ext.logging.LoggingFeature")
public class EmployeeEndpoint implements EmployeeServicePortType{

    BackendService backendService;

    public EmployeeEndpoint (BackendService backendService){
        this.backendService = backendService;
    }

    @Override
    public EmployeesResponse getEmployeesByName(EmployeeByNameRequest parameters) {
        EmployeesResponse employeesResponse = new EmployeesResponse();
        try{
            employeesResponse.getEmployee().addAll(backendService.getEmployeesByName(parameters.getFirstname(), parameters.getLastname()));
        }
        catch (Exception e){
            log.error("Error while setting values for employee object", e);
        }
        return employeesResponse;
    }

    @Override
    public EmployeeResponse getEmployeeById(EmployeeByIdRequest parameters) {
        EmployeeResponse employeeResponse = new EmployeeResponse();
        try{
            employeeResponse.setEmployee(backendService.getEmployeeById(parameters.getId()));
        }
        catch (Exception e){
            log.error("Error while setting values for employee object", e);
        }
        return employeeResponse;
    }
}

В приведенном выше примере мы используем @Функции для регистрации запроса и ответа в журнале приложений.

Запуск приложения

В окне командной строки в корневом проекте запустите:

mvn spring-boot:run

Журнал в консоли:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.4.RELEASE)

2020-10-02 22:23:49.563  INFO 1 --- [           main] com.jpworks.datajdbc.MainApplication     : Starting MainApplication v1.0.1-SNAPSHOT on b6e50b2f461b with PID 1 (/app.jar started by root in /)
2020-10-02 22:23:49.572 DEBUG 1 --- [           main] com.jpworks.datajdbc.MainApplication     : Running with Spring Boot v2.3.4.RELEASE, Spring v5.2.9.RELEASE
2020-10-02 22:23:49.573  INFO 1 --- [           main] com.jpworks.datajdbc.MainApplication     : The following profiles are active: local
2020-10-02 22:23:51.163  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8081 (http)
2020-10-02 22:23:51.179  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-10-02 22:23:51.179  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.38]
2020-10-02 22:23:51.254  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-10-02 22:23:51.255  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1625 ms
2020-10-02 22:23:51.541  INFO 1 --- [           main] o.s.boot.web.servlet.RegistrationBean    : Servlet CXFServlet was not registered (possibly already registered?)
2020-10-02 22:23:51.885  INFO 1 --- [           main] o.a.c.w.s.f.ReflectionServiceFactoryBean : Creating Service {http://service.datajdbc.jpworks.com/}EmployeeEndpointService from class com.jpworks.employee.EmployeeService
2020-10-02 22:23:52.455  INFO 1 --- [           main] org.apache.cxf.endpoint.ServerImpl       : Setting the server's publish address to be /service/employee
2020-10-02 22:23:52.646  INFO 1 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-10-02 22:23:52.870  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path ''
2020-10-02 22:23:52.889  INFO 1 --- [           main] com.jpworks.datajdbc.MainApplication     : Started MainApplication in 4.018 seconds (JVM running for 4.625)

Чтобы получить доступные конечные точки, напишите в браузере:

http://localhost:8081/soap

Чтобы получить wsdl сервиса, напишите в браузере:

http://localhost:8081/soap/service/employee?wsdl

Мы можем протестировать приложение с помощью Http-клиента, такого как Postman или Jmeter, с помощью вызова POST (для тестовых случаев приложение использует восстановленную библиотеку). Но я буду использовать традиционный SoapUI, конечная точка для службы: http://localhost:8081/soap/service/employee .

В консоли приложения вы увидите запрос/ответ, зарегистрированный в журнале:

2020-10-06 15:36:01.396  INFO 102696 --- [           main] com.jpworks.datajdbc.MainApplication     : Started MainApplication in 3.104 seconds (JVM running for 3.988)
2020-10-06 15:36:23.958  INFO 102696 --- [nio-8081-exec-1] o.a.c.s.EmployeeServicePortType.REQ_IN   : REQ_IN
    Address: http://localhost:8081/soap/service/employee
    HttpMethod: POST
    Content-Type: text/xml;charset=UTF-8
    ExchangeId: 872e1281-4545-45ad-9871-331d96c450cf
    ServiceName: EmployeeEndpointService
    PortName: EmployeeEndpointPort
    PortTypeName: EmployeeServicePortType
    Headers: {SOAPAction="http://www.jpworks.com/employee/GetEmployeesByName", host=localhost:8081, connection=Keep-Alive, content-type=text/xml;charset=UTF-8, Content-Length=273, accept-encoding=gzip,deflate, user-agent=Apache-HttpClient/4.5.5 (Java/12.0.1)}
    Payload: 
   
   
      
   


2020-10-06 15:36:23.995  INFO 102696 --- [nio-8081-exec-1] o.a.c.s.E.RESP_OUT                       : RESP_OUT
    Address: http://localhost:8081/soap/service/employee
    Content-Type: text/xml
    ResponseCode: 200
    ExchangeId: 872e1281-4545-45ad-9871-331d96c450cf
    ServiceName: EmployeeEndpointService
    PortName: EmployeeEndpointPort
    PortTypeName: EmployeeServicePortType
    Headers: {}
    Payload: 

Вывод

В этой статье объясняется, почему по-прежнему важно рассматривать SOAP в качестве инструмента на пути миграции из любого устаревшего приложения. Мы использовали демонстрационный WSDL и рассмотрели соответствующие разделы. Мы узнали, как использовать Apache CXF для реализации и настройки SOAP.

Если у вас есть какие-либо вопросы, не стесняйтесь задавать их в комментариях; спасибо за чтение!

Оригинал: “https://dev.to/jpontdia/soap-microservices-with-spring-boot-and-cxf-on-the-monolithic-migration-path-439h”