{"id":20694,"date":"2023-04-24T08:51:35","date_gmt":"2023-04-24T06:51:35","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=20694"},"modified":"2024-07-22T15:02:15","modified_gmt":"2024-07-22T13:02:15","slug":"camel-w-projekcie-czyli-o-tym-jak-wstapilem-na-sciezke-beduina","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/camel-w-projekcie-czyli-o-tym-jak-wstapilem-na-sciezke-beduina\/","title":{"rendered":"Camel w projekcie \u2013 czyli o tym, jak wst\u0105pi\u0142em na \u015bcie\u017ck\u0119 Beduina"},"content":{"rendered":"\n<p>Kilka lat temu zaanga\u017cowa\u0142em si\u0119 w tworzenie aplikacji do komunikacji mi\u0119dzy pracownikami firm kurierskich \u2013 g\u0142\u00f3wnie pomi\u0119dzy kurierami a pracownikami BackOffice. Architektura aplikacji zak\u0142ada\u0142a utworzenie kilku serwis\u00f3w. Jeden z nich mia\u0142 za zadanie komunikacj\u0119 z aplikacjami \u201ezewn\u0119trznych\u201d dostawc\u00f3w, kt\u00f3re w r\u00f3\u017cnej formie dostarcza\u0142y nam niezb\u0119dnych informacji o u\u017cytkownikach systemu. Budowany <strong>serwis mia\u0142 zapewni\u0107 funkcjonalno\u015b\u0107 ksi\u0105\u017cki adresowej<\/strong>.<\/p>\n\n\n\n<p>By zebra\u0107 i odpowiednio przygotowa\u0107 dane do tej ksi\u0105\u017cki, nale\u017ca\u0142o wykona\u0107 wed\u0142ug specjalnych regu\u0142 oko\u0142o <strong>7 r\u00f3\u017cnych \u017c\u0105da\u0144 http<\/strong>. Wybrane z nich powtarza\u0142o si\u0119 kilka razy \u2013 przez wzgl\u0105d na paginacj\u0119 i du\u017ce ilo\u015bci danych. Nast\u0119pnie trzeba by\u0142o je w jaki\u015b sensowny spos\u00f3b zagregowa\u0107.<\/p>\n\n\n\n<p>Podczas tworzeniu serwisu ksi\u0105\u017cki adresowej najwi\u0119kszym wyzwanie stanowi\u0142o to, w jaki spos\u00f3b posk\u0142ada\u0107 w sensown\u0105 ca\u0142o\u015b\u0107 wszystkie niezb\u0119dne \u017c\u0105dania. Oczekiwanym rezultatem prac by\u0142 endpoint serwisu zwracaj\u0105cy tablic\u0119 nazw u\u017cytkownik\u00f3w oraz numery ich zarejestrowanych komunikator\u00f3w. Kiedy ju\u017c dane zosta\u0142y zebrane, to nale\u017ca\u0142o \u201ewrzuci\u0107\u201d je do cache\u2019a, by nie musie\u0107 zbyt cz\u0119sto ponawia\u0107 ca\u0142ej skomplikowanej procedury.<\/p>\n\n\n\n<p>Powsta\u0142o w\u00f3wczas sporo kodu, kt\u00f3ry trzeba by\u0142o co kilka krok\u00f3w zrefaktoryzowa\u0107, by zapewni\u0107 wzgl\u0119dn\u0105 utrzymywalno\u015b\u0107 oraz czytelno\u015b\u0107. Nie wspomn\u0119 o optymalizacji dostarczanego rozwi\u0105zania pod wzgl\u0119dem z\u0142o\u017cono\u015bci czy ewentualnych wyciek\u00f3w pami\u0119ci przez lawinowo tworzone kolejne instancje obiekt\u00f3w transferowych (DTO).<\/p>\n\n\n\n<p>Cho\u0107 serwis finalnie dzia\u0142a\u0142 ca\u0142kiem przyzwoicie, to <strong>ilo\u015b\u0107 wysi\u0142ku w\u0142o\u017conego w tworzenie implementacji, a przede wszystkim w szlifowanie rozwi\u0105zania, by\u0142a niewsp\u00f3\u0142miernie du\u017ca do oczekiwanego i dostarczanego rezultatu<\/strong>. Tu\u017c pod koniec trwania projektu, gdy ju\u017c tylko uzupe\u0142niali\u015bmy ewentualne braki w dokumentacji, przy kawie odby\u0142em rozmow\u0119 z jednym ze swoich bardziej do\u015bwiadczonych w\u00f3wczas koleg\u00f3w. Opowiedzia\u0142em mu o bol\u0105czkach, o tym z jakiej skali problemami musieli\u015bmy si\u0119 mierzy\u0107, na co on skwitowa\u0142 opowie\u015b\u0107 pytaniem: \u201eA w\u0142a\u015bciwie, to dlaczego nie zdecydowali\u015bcie si\u0119 na Apache Camel?\u201d.<\/p>\n\n\n\n<p>Z artyku\u0142u dowiesz si\u0119, z jakich powod\u00f3w warto pozna\u0107 si\u0119 bli\u017cej z tym narz\u0119dziem.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Czym w\u0142a\u015bciwie jest Apache Camel?<\/strong><\/h2>\n\n\n\n<p><a href=\"https:\/\/camel.apache.org\/\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Na stronie projektu<\/a> znajdziemy informacj\u0119, \u017ce Camel to <strong>uniwersalny integracyjny framework<\/strong> dystrybuowany na licencji <strong>open-source<\/strong>, bazuj\u0105cy na znanych wzorcach EIP (Enterprise Integration Patterns). Projekt doczeka\u0142 si\u0119 kilku publikacji ksi\u0105\u017ckowych, licznych artyku\u0142\u00f3w, niema\u0142ej spo\u0142eczno\u015bci oraz co najmniej kilku powa\u017cnych firm konsultingowych.<\/p>\n\n\n\n<p>Rewelacyjnie kooperuje i wzajemnie si\u0119 uzupe\u0142nia z frameworkiem Spring oraz Spring Boot. Jest narz\u0119dziem bardzo rozbudowanym, a tworzona w oparciu o niego integracja jest \u0142atwo rozszerzalna i modyfikowalna. Definiowane przy jego pomocy endpointy budowane s\u0105 zgodnie z dostarczonymi DSL-ami (Domain Specific Language). <\/p>\n\n\n\n<p>Cho\u0107 wszystkich dost\u0119pnych jest ca\u0142kiem sporo, to najbardziej popularnymi wydaj\u0105 si\u0119 by\u0107 <strong>Rest DSL, Java DSL oraz XML DSL.<\/strong> G\u0142\u00f3wnymi obiektami definiowanymi z oparciu o sk\u0142adni\u0119 DSL s\u0105 route\u2019y. Route\u2019y korzystaj\u0105 z niezwykle bogatego pakietu komponent\u00f3w dedykowanych r\u00f3\u017cnym kana\u0142om, stylom oraz formom komunikacji. Wszystko to, by w ekstremalnie elastyczny spos\u00f3b pozwoli\u0107 na przep\u0142yw i odpowiednie dostosowanie danych z \u017c\u0105da\u0144 i z odpowiedzi.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Przejrzysty kod oraz wygodna struktura \u2013 czyli Camel DSL w praktyce<\/strong><\/h2>\n\n\n\n<p>O tym, jak istotne \u2013 z punktu widzenia zespo\u0142u java developer\u00f3w \u2013 jest tworzenie czystego kodu, zgrabnych rozwi\u0105za\u0144, przejrzystej implementacji, utrzymywanie w\u0142a\u015bciwego i wywa\u017conego poziomu abstrakcji, powsta\u0142o sporo ksi\u0105\u017cek i artyku\u0142\u00f3w. Znani i szanowani, bardzo do\u015bwiadczeni programi\u015bci, architekci i mentorzy przekonuj\u0105 czytelnik\u00f3w i s\u0142uchaczy swoich wyk\u0142ad\u00f3w oraz podcast\u00f3w, prezentuj\u0105c przyk\u0142ady na to, w jaki spos\u00f3b pisa\u0107 kod, a jak tego nie robi\u0107 oraz \u2013 rzecz jasna \u2013 czym grozi nie stosowanie si\u0119 do sugestii.<\/p>\n\n\n\n<p>Zwracaj\u0105 uwag\u0119 zainteresowanych na wa\u017cne aspekty, jednak\u017ce nieustannie z r\u00f3\u017cnym skutkiem. Je\u017celi tylko na chwil\u0119 w projekcie zabraknie osoby odpowiednio zaanga\u017cowanej w <strong>piel\u0119gnowanie i budowanie \u015bwiadomo\u015bci programistycznej<\/strong> <strong>oraz uwra\u017cliwiaj\u0105cej zesp\u00f3\u0142 na czysto\u015b\u0107 dostarczanych rozwi\u0105za\u0144<\/strong>, to poziom nieuporz\u0105dkowania i przypadkowo\u015bci w implementacjach drastycznie mo\u017ce wzrosn\u0105\u0107. Oczywi\u015bcie, nie da si\u0119 ca\u0142kiem wyeliminowa\u0107 tego problemu, ale <strong>Apache Camel mo\u017ce si\u0119 okaza\u0107 niezwykle pomocny w tym obszarze dzia\u0142ania.<\/strong><\/p>\n\n\n\n<p>Nie chc\u0105c by\u0107 go\u0142os\u0142ownym, poni\u017cej zaprezentuj\u0119 dwa fragmenty kodu. Na pierwszym z nich znajdziemy implementacj\u0119 endpointu przy u\u017cyciu frameworka Spring, a na drugim jego ekwiwalent przy wykorzystaniu Rest DSL od Apache Camel.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/Obraz1.png\"><img decoding=\"async\" width=\"356\" height=\"266\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/Obraz1.png\" alt=\"Deklaracja endpointu \/collections\/books w klasie CollectionsController przy u\u017cyciu Spring Framework\" class=\"wp-image-20695\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/Obraz1.png 356w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/Obraz1-300x224.png 300w\" sizes=\"(max-width: 356px) 100vw, 356px\" \/><\/a><figcaption>Ryc. 1 Deklaracja endpointu \/collections\/books w klasie CollectionsController przy u\u017cyciu Spring Framework<\/figcaption><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img decoding=\"async\" width=\"435\" height=\"351\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/2-9.png\" alt=\"Deklaracja endpointu \/collections\/books w klasie CollectionsController przy u\u017cyciu Apache Camel\" class=\"wp-image-20697\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/2-9.png 435w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/2-9-300x242.png 300w\" sizes=\"(max-width: 435px) 100vw, 435px\" \/><figcaption>Ryc. 2 Deklaracja endpointu \/collections\/books w klasie CollectionsController przy u\u017cyciu Apache Camel<\/figcaption><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Por\u00f3wnanie kod\u00f3w<\/strong><\/h3>\n\n\n\n<p>Jak mo\u017cemy zauwa\u017cy\u0107, w obu przypadkach tworzenie endpoint\u00f3w REST-owych jest \u2013 co do zasady \u2013\u00a0nieskomplikowane. Jestem sk\u0142onny zaryzykowa\u0107 stwierdzenie, \u017ce przyzwyczajeni do stylu Springa, jako bardziej popularnego frameworka, mo\u017cemy postrzega\u0107 zapisany w nim kod jako r\u00f3wnie czytelny jak ten z Ryc. 2. Jednak\u017ce, w mojej opinii, <strong>du\u017co bardziej deskryptywny<\/strong> jest kod zapisany przy u\u017cyciu Rest DSL, gdzie znajdziemy mniej adnotacji, kr\u00f3tkie i jasne deklaracje metod HTTP takich jak na przyk\u0142ad GET czy POST, wygodny oraz przyjemny builder, kt\u00f3rego u\u017cywamy do \u201ebudowania\u201d route\u2019\u00f3w.<\/p>\n\n\n\n<p>Rest DSL jest bardzo prosty i intuicyjny w u\u017cyciu, a czytelno\u015b\u0107 deklarowanego endpointu zosta\u0142a niejako \u201ewydestylowana\u201d do maksimum.<\/p>\n\n\n\n<p>Bez wzgl\u0119du na to, czy korzystamy z Rest DSL, Java DSL czy innego dost\u0119pnego, to <strong>czytelno\u015b\u0107, intuicyjno\u015b\u0107 i prostota zawsze b\u0119d\u0105 na tym samym poziomie<\/strong>. W moim odczuciu, niezwykle korzystne jest wykorzystanie wzorca builder do konstruowania struktury endpoint\u00f3w (czy og\u00f3lnie route\u2019\u00f3w), co wymusza konsekwencj\u0119 w definiowaniu i logiczn\u0105 sp\u00f3jno\u015b\u0107 na poziomie ca\u0142ej aplikacji.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Bardziej \u201eco\u201d ni\u017c \u201ejak\u201d<\/strong><\/h2>\n\n\n\n<p>Wyobra\u017amy sobie, \u017ce do przyk\u0142adu ze springowym kontrolerem REST-owym potrzebujemy wprowadzi\u0107 pewn\u0105 istotn\u0105 modyfikacj\u0119. Za\u0142\u00f3\u017cmy, \u017ce to co do tej pory pobierali\u015bmy z w\u0142asnej metody getBooks, zosta\u0142o przeniesione do innego serwisu i od teraz b\u0119dzie dost\u0119pne pod adresem: \u201e<em>http:\/\/innyserwis.com\/collections\/books<\/em>\u201d.&nbsp;<\/p>\n\n\n\n<p>By pobra\u0107 dane z tego endpointu nale\u017cy wcze\u015bniej albo przygotowa\u0107 komponent do wykonywania \u017c\u0105da\u0144 http, oparty na przyk\u0142ad o OkHttp, Apache Client itp., albo skorzysta\u0107 z tego, co oferuje Spring, w RestTemplate czy jakiej\u015b jego nowocze\u015bniejszej alternatywie.<\/p>\n\n\n\n<p>Nie chc\u0105c dok\u0142ada\u0107 z\u0142o\u017cono\u015bci, skorzystajmy z RestTemplate.<\/p>\n\n\n\n<p>Do klasy BooksServiceImpl dodajmy zatem pole o typie RestTemplate i przez konstruktor powi\u0105\u017cmy z utworzon\u0105 instancj\u0105. Nast\u0119pnie do metody getBooks wprowad\u017amy poni\u017cszy fragment kodu:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/3-9.png\"><img decoding=\"async\" width=\"605\" height=\"252\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/3-9.png\" alt=\"\" class=\"wp-image-20699\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/3-9.png 605w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/3-9-300x125.png 300w\" sizes=\"(max-width: 605px) 100vw, 605px\" \/><\/a><figcaption>Ryc. 3 Przyk\u0142adowa implementacja metody getBooks korzystaj\u0105cej z RestTemplate<\/figcaption><\/figure><\/div>\n\n\n\n<p>Powy\u017cszy przyk\u0142ad pokazuje, \u017ce pobieranie danych z innego endpointu nale\u017c\u0105cego do innego serwisu, musi zosta\u0107 poprzedzone ca\u0142ym szeregiem operacji, nie zapominaj\u0105c o osobliwym obiekcie typu <em>ParameterizedTypeReference<\/em>, niezb\u0119dnym by wskaza\u0107 typ spodziewanych danych z odpowiedzi.<\/p>\n\n\n\n<p>Jak mo\u017cemy zauwa\u017cy\u0107, w przypadku RestTemplate albo id\u0105c krok dalej, w przypadku Springa, musimy posiada\u0107 bardzo szczeg\u00f3\u0142ow\u0105 wiedz\u0119 o tym, w jaki spos\u00f3b nale\u017cy co\u015b zaimplementowa\u0107, aby m\u00f3c to zrealizowa\u0107 wystarczaj\u0105co dobrze. Pomimo popularno\u015bci tego podej\u015bcia, za ka\u017cdym razem musimy na takie rozwi\u0105zanie spojrze\u0107 z perspektywy nie tylko tego, co chcemy osi\u0105gn\u0105\u0107, ale przede wszystkim \u2013 <strong>jak to chcemy zrobi\u0107.<\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Wykorzystanie Apache Camel<\/strong><\/h2>\n\n\n\n<p>W Apache Camel sytuacje podobne do przedstawionej powy\u017cej nie maj\u0105 zwykle miejsca. Szczeg\u00f3lnie, gdy mamy do czynienia z typowym u\u017cyciu dostarczonych komponent\u00f3w. Sp\u00f3jrzmy zatem na poni\u017cszy fragment kodu, w kt\u00f3rym przedstawiono sytuacj\u0119, gdzie przepi\u0119to \u017ar\u00f3d\u0142o danych z metody serwisu do komponentu frameworka Camel.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/4-6.png\"><img decoding=\"async\" width=\"605\" height=\"260\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/4-6.png\" alt=\"Deklaracja endpointu \/collections\/books w klasie CollectionsController przy u\u017cyciu Apache Camel korzystaj\u0105ca z komponentu http zamiast bean\" class=\"wp-image-20701\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/4-6.png 605w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/4-6-300x129.png 300w\" sizes=\"(max-width: 605px) 100vw, 605px\" \/><\/a><figcaption>Ryc. 4 Deklaracja endpointu \/collections\/books w klasie CollectionsController przy u\u017cyciu Apache Camel korzystaj\u0105ca z komponentu http zamiast bean<\/figcaption><\/figure><\/div>\n\n\n\n<p>W powy\u017cszym fragmencie jedyn\u0105 rzecz\u0105, kt\u00f3r\u0105 nale\u017ca\u0142o zrobi\u0107, by\u0142o <strong>skorzystanie z innego komponentu<\/strong>. I tak: zamiast komponentu \u201ebean\u201d, w kt\u00f3rym wskazywali\u015bmy na obiekt klasy BookService oraz jego metody \u201egetBooks()\u201d, wybieramy na przyk\u0142ad komponent \u201ehttp\u201d, kt\u00f3ry wykona dla nas przekierowanie do wskazanego endpointu i odbierze z niego uzyskan\u0105 odpowied\u017a.<\/p>\n\n\n\n<p>Je\u017celi wiemy, jak dzia\u0142aj\u0105 komponenty Camela, z kt\u00f3rych chcemy skorzysta\u0107 oraz znamy spos\u00f3b u\u017cycia dost\u0119pnych wzorc\u00f3w EIP, to wykorzystuj\u0105c ten framework, nie musimy si\u0119 (r\u00f3wnie mocno jak w Springu) koncentrowa\u0107 na tym, jak to chcemy zrobi\u0107. Generalnie, <strong>w Camelu wystarczy wiedzie\u0107, co si\u0119 chce osi\u0105gn\u0105\u0107.<\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Mo\u017cliwo\u015bci Camela<\/strong><\/h2>\n\n\n\n<p>Chcia\u0142bym jeszcze przez chwil\u0119 skupi\u0107 si\u0119 na kilku wybranych mo\u017cliwo\u015bciach Camela. Ju\u017c bez por\u00f3wnywania alternatywnych i analogicznych rozwi\u0105za\u0144 dostarczonych przez obydwa frameworki, zaprezentuj\u0119 i pokr\u00f3tce om\u00f3wi\u0119 dwa przyk\u0142ady. Obydwa zosta\u0142y przygotowane w oparciu o fragmenty serwisu integruj\u0105cego si\u0119 z kilkoma innymi aplikacjami. <\/p>\n\n\n\n<p>Pierwszym problemem, kt\u00f3ry nale\u017ca\u0142o rozwi\u0105za\u0107 by\u0142o <strong>wys\u0142anie formularza z kilkoma indywidualnymi zestawami danych<\/strong>. Dane by\u0142y po\u0142\u0105czone wcze\u015bniej nadanym numerem serwisowym. Istotnym za\u0142o\u017ceniem by\u0142o to, <strong>by z rozbitych dw\u00f3ch \u017c\u0105da\u0144 przygotowa\u0107 jedno zbiorcze<\/strong>. Numer serwisowy nadawany by\u0142 przez zewn\u0119trzny serwis, kt\u00f3ry zapewnia\u0142 jego unikalno\u015b\u0107. Warto doda\u0107, \u017ce wysy\u0142ane zestawy danych mog\u0142y by\u0107 konsumowane pojedynczo przez wzgl\u0105d na wewn\u0119trzne ograniczenia serwisu, z kt\u00f3rym si\u0119 integrowali\u015bmy.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/5-6.png\"><img decoding=\"async\" width=\"605\" height=\"551\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/5-6.png\" alt=\"Deklaracja endpointu POST \u201e\/upload\u201d wykonuj\u0105cego seri\u0119 operacji jak \u017c\u0105danie nadania indywidualnego numeru serwisowego oraz rozdzielenie zestawu danych na kolejne \u017c\u0105dania realizowane przy wykorzystaniu wzorca Split EIP\" class=\"wp-image-20703\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/5-6.png 605w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/5-6-300x273.png 300w\" sizes=\"(max-width: 605px) 100vw, 605px\" \/><\/a><figcaption>Ryc. 5 Deklaracja endpointu POST \u201e\/upload\u201d wykonuj\u0105cego seri\u0119 operacji jak \u017c\u0105danie nadania indywidualnego numeru serwisowego oraz rozdzielenie zestawu danych na kolejne \u017c\u0105dania realizowane przy wykorzystaniu wzorca Split EIP<\/figcaption><\/figure><\/div>\n\n\n\n<p>W powy\u017cszym kodzie mo\u017cemy zobaczy\u0107 rozbicie route\u2019a z endpointu REST na dwa inne, a dla podkre\u015blenia ich kolejno\u015bci zawarte zosta\u0142y w bloku \u201epipeline \u2013 end\u201d.<\/p>\n\n\n\n<p>Route zapewniaj\u0105cy nam \u201e<em>direct:get-service-number<\/em>\u201d ma za zadanie pobra\u0107 nowo nadany numer serwisowy, za\u015b route \u201e<em>direct:upload-all-files<\/em>\u201d odpowiedzialny jest za rozdzielenie przychodz\u0105cego zestawu danych na osobne \u017c\u0105dania. Ten route korzysta z wzorca Split EIP, kt\u00f3ry rozdzieli\u0142 kolekcj\u0119 nazw i dla ka\u017cdej jednej \u2013 we w\u0142a\u015bciwy spos\u00f3b \u2013 wykona\u0142 \u017c\u0105danie \u201euploadu\u201d. \u017beby zwr\u00f3ci\u0107 u\u017cytkownikowi informacj\u0119 o tym, kt\u00f3re operacje \u201euploadu\u201d si\u0119 powiod\u0142y, a kt\u00f3re nie, wykorzystano przygotowany <em>UploadStatusAggregator<\/em> definiuj\u0105cy w\u0142a\u015bciw\u0105 strategi\u0119 agregacji.<\/p>\n\n\n\n<p>Kolejnym zadaniem, kt\u00f3re nale\u017ca\u0142o rozwi\u0105za\u0107, by\u0142o zebranie danych z trzech endpoint\u00f3w, zwracaj\u0105cych dane w trzech r\u00f3\u017cnych formatach. Dane nale\u017ca\u0142o ze sob\u0105 odpowiednio powi\u0105za\u0107 i popakowa\u0107 do wynikowej listy obiekt\u00f3w. Rozwi\u0105zanie oparto o <strong>Multicast EIP<\/strong> z odpowiednio opracowan\u0105 implementacj\u0105 obiektu odpowiedzialnego za prawid\u0142owe zagregowanie nadchodz\u0105cych danych.&nbsp; Do sterowania parsowaniem przychodz\u0105cych danych w formacie JSON, na potrzeby niniejszej analizy wykorzystano \u201eexchange properties\u201d.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/6-6.png\"><img decoding=\"async\" width=\"1024\" height=\"726\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/6-6-1024x726.png\" alt=\"Deklaracja endpointu GET \u201e\/aggregation\u201d zbieraj\u0105cego dane z trzech r\u00f3\u017cnych endpoint\u00f3w o r\u00f3\u017cnych typach odpowiedzi do jednego zbiorczego, tworz\u0105cego inna struktur\u0119 wynikow\u0105\" class=\"wp-image-20714\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/6-6-1024x726.png 1024w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/6-6-300x213.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/6-6-768x545.png 768w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/6-6.png 1104w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption>Ryc. 6 Deklaracja endpointu GET \u201e\/aggregation\u201d zbieraj\u0105cego dane z trzech r\u00f3\u017cnych endpoint\u00f3w o r\u00f3\u017cnych typach odpowiedzi do jednego zbiorczego, tworz\u0105cego inna struktur\u0119 wynikow\u0105<\/figcaption><\/figure><\/div>\n\n\n\n<p>Jak wida\u0107 na powy\u017cszym listingu, do utworzenia endpointu zosta\u0142 u\u017cyty Multicast EIP oraz wykorzystano w\u0142a\u015bciwo\u015bci (exchange property) do przesy\u0142ania odpowiednich warto\u015bci pomi\u0119dzy kolejnymi route\u2019ami.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Podsumowanie<\/strong><\/h2>\n\n\n\n<p>Ponad dwa lata temu mia\u0142em ogromne szcz\u0119\u015bcie, by trafi\u0107 do projektu, w kt\u00f3rym by\u0142 Apache Camel. Wiele rzeczy zaimplementowanych przy pomocy Camela \u2013 podej\u015bciem i pewnie wiekiem \u2013 pami\u0119ta\u0107 mog\u0142o dinozaury. Mimo tego, \u017ce wiele rzeczy by\u0142o tam zaimplementowanych niew\u0142a\u015bciwie, to wspania\u0142e jednak by\u0142o tam to, i\u017c zastany kod mog\u0142em potraktowa\u0107 jak poligon do\u015bwiadczalny. <strong>Zmiana metodyki budowania route\u2019\u00f3w i migracja konwencji<\/strong> do budowania takich o wiele \u0142atwiejszych w utrzymaniu i niepor\u00f3wnywalnie bardziej czytelnych, ni\u017c to mia\u0142o miejsce wcze\u015bniej, <strong>zako\u0144czy\u0142a si\u0119 sukcesem<\/strong>.<\/p>\n\n\n\n<p>W projekcie prowadzonym przez nasz zesp\u00f3\u0142 mog\u0142em sporo zaobserwowa\u0107 w kontek\u015bcie tego, jak nie nale\u017cy budowa\u0107 route\u2019\u00f3w. Dzi\u0119ki temu finalnie mia\u0142em mo\u017cliwo\u015b\u0107 zaproponowania najbardziej dla nas wygodnego podej\u015bcia. Z ka\u017cdym kolejnym kawa\u0142kiem implementacji z wykorzystaniem <strong>Apache Camel <\/strong>nabieram przekonania o tym, \u017ce jest to <strong>jeden z najlepiej dopracowanych framework\u00f3w do integracji <\/strong>z jakimi si\u0119 spotka\u0142em. Wspaniale dzia\u0142a razem ze Springiem czy SpringBootem.<\/p>\n\n\n\n<p>Kiedy kilka lat temu zmaga\u0142em si\u0119 z tworzeniem \u201eksi\u0105\u017cki adresowej\u201d i na pewno brakowa\u0142o mi w\u00f3wczas zrozumienia tego, jak dzia\u0142a Apache Camel w stopniu umo\u017cliwiaj\u0105cym skuteczne negocjowanie mo\u017cliwo\u015bci u\u017cycia go w jednym z mikroserwis\u00f3w. Dzi\u015b ju\u017c mam pewno\u015b\u0107, \u017ce je\u017celi projekt <strong>nosi\u0142by znamiona integracji<\/strong>, albo zwyczajnie potrzebowa\u0142bym czego\u015b, co <strong>wspar\u0142oby Springa<\/strong> w projekcie, to z ca\u0142\u0105 pewno\u015bci\u0105 si\u0119gn\u0105\u0142bym po Apache Camel.<\/p>\n\n\n\n<p>Je\u017celi w swoim projekcie masz podobne potrzeby, to nie wahaj si\u0119 ani chwili, tylko zacznij swoj\u0105 przygod\u0119 z Camelem i zyskaj czas, \u0142atwo\u015b\u0107 implementowania oraz sporo satysfakcji.<\/p>\n\n\n\n<p>***<\/p>\n\n\n\n<p>By\u0107 mo\u017ce zainteresuj\u0105 Ci\u0119 r\u00f3wnie\u017c inne artyku\u0142y naszych ekspert\u00f3w m.in.:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/sii.pl\/blog\/podejscie-do-refaktoryzacji-w-projekcie-ze-starymi-technologiami\/?category=development-na-miekko&amp;tag=architektura-it,legacy-code,refaktoryzacja\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\">Podej\u015bcie do refaktoryzacji w projekcie ze starymi technologiami<\/a><\/li><li><a href=\"https:\/\/sii.pl\/blog\/wdrazanie-aplikacji-spring-boot-z-wykorzystaniem-uslugi-azure-spring-apps\/?category=development-na-miekko&amp;tag=azure,azure-spring-apps,infrastruktura\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\">Wdra\u017canie aplikacji Spring Boot z wykorzystaniem us\u0142ugi Azure Spring Apps<\/a><\/li><li><a href=\"https:\/\/sii.pl\/blog\/angular-jasmine-testowanie-serwisow-http-czesc-i-metoda-get\/?category=development-na-twardo&amp;tag=angular,software-development,testng\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\">Angular\/Jasmine \u2013 testowanie serwis\u00f3w HTTP. Cz\u0119\u015b\u0107 I \u2013 metoda GET<\/a><\/li><\/ul>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;20694&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;4&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5 ( votes: 4)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;Camel w projekcie \u2013 czyli o tym, jak wst\u0105pi\u0142em na \u015bcie\u017ck\u0119 Beduina&quot;,&quot;width&quot;:&quot;139.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 139.5px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            5\/5 ( votes: 4)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Kilka lat temu zaanga\u017cowa\u0142em si\u0119 w tworzenie aplikacji do komunikacji mi\u0119dzy pracownikami firm kurierskich \u2013 g\u0142\u00f3wnie pomi\u0119dzy kurierami a pracownikami &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/camel-w-projekcie-czyli-o-tym-jak-wstapilem-na-sciezke-beduina\/\">Continued<\/a><\/p>\n","protected":false},"author":495,"featured_media":20708,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":7,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[2427,1669,1554,1546,276],"class_list":["post-20694","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-digital","tag-apache-camel","tag-zalety-i-wady","tag-przeglad-narzedzi","tag-framework"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/03\/Camel-w-projekcie-\u2013-czyli-o-tym-jak-wstapilem-na-sciezke-beduina.jpg","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/20694"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/495"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=20694"}],"version-history":[{"count":2,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/20694\/revisions"}],"predecessor-version":[{"id":21084,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/20694\/revisions\/21084"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/20708"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=20694"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=20694"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=20694"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}