Una dintre principalele probleme în dezvoltarea și utilizarea ulterioară a microservicelor este configurarea corectă și atentă a instanțelor acestora. Acest lucru poate fi ajutat, în opinia mea, de noul cadru . Acesta permite rezolvarea destul de elegantă a unor sarcini de rutină legate de configurarea aplicațiilor.
Dacă aveți multe microservicii și fiecare dintre acestea vine cu propriul fișier/fisiere de configurare, atunci există o mare probabilitate de a face o greșeală în unul dintre ele, care, fără pregătirea adecvată și un sistem de logare, poate fi foarte greu de depistat. Principala sarcină pe care și-o propune cadrul este de a reduce la minimum parametrii duplicat ai configurării instanței, diminuând astfel riscul introducerii unei erori.
Să luăm un exemplu. Să presupunem că avem o aplicație simplă cu un fișier de configurare yaml. Acesta poate fi orice microserviciu într-un limbaj oarecare. Să vedem cum poate fi aplicat cadrul acestui serviciu.
Dar înainte, pentru mai multă comoditate, să creăm un proiect gol în Idea IDE, instalând mai întâi pluginul microconfig.io:

Configurăm configurația de lansare a pluginului, se poate utiliza configurația implicită, așa cum este în captura de ecran de mai sus.
Serviciul nostru se numește order, așa că în noul proiect să creăm o structură similară:

În folderul numit după serviciu, plasăm fișierul de configurare — application.yaml. Toate microserviciile rulează într-un mediu, așa că, pe lângă crearea configurației serviciului, trebuie să descriem și mediu: pentru aceasta, să creăm un folder envs și să adăugăm într-un fișier cu numele mediului nostru de lucru. Astfel, cadrul va crea fișiere de configurare pentru servicii în mediu dev, deoarece în setările pluginului este setat acest parametru.
Structura fișierului dev.yaml va fi destul de simplă:
mainorder:
components:
- orderCadrul lucrează cu configurații care sunt grupate. Pentru serviciul nostru, vom alege un nume pentru grupă mainorder. Cadrul găsește fiecare astfel de grupă de aplicații în fișierul mediu și creează configurații pentru toate acestea pe care le găsește în folderele corespunzătoare.
În fișierul de configurare al serviciului order vom specifica până acum doar un parametru:
spring.application.name: orderAcum să lansăm pluginul, iar acesta ne va genera configurația necesară a serviciului nostru conform căii specificate în proprietăți:

Se poate și fără a instala un plugin, doar descărcând distribuția framework-ului și rulând-o din linia de comandă.
Această soluție este potrivită pentru utilizarea pe serverul de compilare.
Merită menționat că framework-ul înțelege excelent property sintaxa, adică fișierele property obișnuite, care pot fi folosite împreună în yaml configurații.
Să adăugăm încă un serviciu payment și să complicăm în același timp ceea ce există.
În order:
eureka:
instance.preferIpAddress: true
client:
serviceUrl:
defaultZone: http://192.89.89.111:6782/eureka/
server.port: 9999
spring.application.name: order
db.url: 192.168.0.100În payment:
eureka:
instance.preferIpAddress: true
client:
serviceUrl:
defaultZone: http://192.89.89.111:6782/eureka/
server.port: 9998
spring.application.name: payments
db.url: 192.168.0.100Problema principală a acestor configurații este cantitatea mare de cod repetat în setările serviciilor. Să vedem cum poate framework-ul să ne ajute să scăpăm de ea. Să începem cu cea mai evidentă — existența configurației eureka în descrierea fiecărui microserviciu. Vom crea un nou director cu un fișier de configurare și vom adăuga în el o nouă configurație:

Și în fiecare dintre proiectele noastre acum vom adăuga linia #include eureka.
Framework-ul va găsi automat configurația eureka și o va copia în fișierele de configurare ale serviciilor, fără a crea o configurație eureka separată, deoarece nu o vom specifica în fișierul de mediu dev.yaml. Serviciul order:
#include eureka
server.port: 9999
spring.application.name: order
db.url: 192.168.0.100De asemenea, putem scoate setările bazei de date într-o configurație separată, schimbând linia de import în #include eureka, oracle.
Merită menționat că fiecare modificare în timpul regenerării fișierelor de configurare este urmărită de framework și plasată într-un fișier special lângă fișierul principal de configurare. Înregistrarea din jurnal arată astfel: “Stored 1 property changes to order/diff-application.yaml”. Acest lucru permite detectarea rapidă a modificărilor în fișierele mari de configurare.
Scoaterea părților comune ale configurației permite eliminarea multor copiări inutile, dar nu permite crearea flexibilă a configurației pentru diferite medii — endpoint-urile serviciilor noastre sunt unice și sunt codate în mod hard, ceea ce este rău. Să încercăm să o eliminăm.
O soluție bună ar fi să avem toate endpoint-urile într-o singură configurație, la care celelalte ar putea face referire. Pentru aceasta, framework-ul a fost dotat cu suport pentru placeholder-uri. Iată cum se va schimba fișierul de configurare eureka:
client:
serviceUrl:
defaultZone: http://${endpoints@eurekaip}:6782/eureka/Acum să vedem cum funcționează acest placeholder. Sistemul găsește componenta numită endpoints și caută în ea valoarea eurekaip, după care îl introduce în configurația noastră. Dar cum facem cu diferitele medii? Pentru aceasta, vom crea un fișier de setări în endpoints următoarea formă application.dev.yaml. Framework-ul decide automat, în funcție de extensia fișierului, la ce mediu aparține această configurație și o încarcă:

Conținutul fișierului dev:
eurekaip: 192.89.89.111
dbip: 192.168.0.100O astfel de configurație o putem crea și pentru porturile serviciilor noastre:
server.port: ${ports@order}.Toate setările importante se află într-un singur loc, ceea ce reduce astfel riscul de eroare din cauza parametrelor împrăștiate în fișierele de configurație.
Framework-ul oferă multe placeholder-uri gata făcute, de exemplu, putem obține numele directorului în care se află fișierul de configurație și să-l atribuim:
#include eureka, oracle
server.port: ${ports@order}
spring.application.name: ${this@name}Datorită acestui lucru, nu trebuie să specificăm numele aplicației în configurație și poate fi, de asemenea, mutată într-un modul comun, de exemplu, în aceeași eureka:
client:
serviceUrl:
defaultZone: http://${endpoints@eurekaip}:6782/eureka/
spring.application.name: ${this@name}Fișierul de configurație order se va reduce la o linie:
#include eureka, oracle
server.port: ${ports@order}În cazul în care o setare din configurația părinte nu ne este necesară, putem să o specificăm în configurația noastră, iar aceasta va fi aplicată la generare. Adică, dacă din vreun motiv avem nevoie de un nume unic pentru serviciul order, pur și simplu lăsăm parametrul spring.application.name.
Să presupunem că în serviciu trebuie să adăugăm setări de logare personalizate, care sunt stocate într-un fișier separat, de exemplu, logback.xml. Vom crea pentru acesta un grup de setări separat:

În configurația de bază, vom indica framework-ului unde să plaseze fișierul de setări pentru logare necesar, folosind placeholder-ul @ConfigDir:
microconfig.template.logback.fromFile: ${logback@configDir}/logback.xmlÎn fișierul logback.xml configurăm appendere standard, care pot conține, de asemenea, placeholder-uri, pe care framework-ul le va modifica în timpul generării configurațiilor, de exemplu:
logs/${this@name}.logAdăugând în configurațiile serviciilor importul logback, obținem automat logare configurată pentru fiecare serviciu:
#include eureka, oracle, logback
server.port: ${ports@order}A sosit timpul să ne familiarizăm mai în detaliu cu toate placeholder-urile disponibile ale framework-ului:
${this@env} — returnează numele mediului curent.
${…@name} — returnează numele componentei.
${…@configDir} — returnează calea completă către directorul config al componentei.
${…@resultDir} — returnează calea completă către directorul destinație al componentului (fișierele obținute vor fi plasate în acest director).
${this@configRoot} — returnează calea completă către directorul rădăcină al depozitului de configurații.
De asemenea, sistemul permite obținerea variabilelor de mediu, de exemplu calea către java:
${env@JAVA_HOME}
Sau, deoarece cadrul este scris în JAVA, putem obține variabilele sistemului similare apelului System::getProperty folosind o construcție de acest tip:
${system@os.name}
Merită menționat suportul pentru limbajul de extensie Spring EL. În configurație, se aplică astfel de expresii:
connection.timeoutInMs: #{5 * 60 * 1000}
datasource.maximum-pool-size: #{${this@datasource.minimum-pool-size} + 10} și se pot utiliza variabile locale în fișierele de configurație folosind expresia #var:
#var feedRoot: ${system@user.home}/feed
folder:
root: ${this@feedRoot}
success: ${this@feedRoot}/archive
error: ${this@feedRoot}/errorAstfel, cadrul se dovedește a fi un instrument destul de puternic pentru reglarea fină și flexibilă a configurațiilor microservicelor. Cadrul își îndeplinește excelent sarcina principală — eliminarea copierii codului în setările, consolidarea configurațiilor și, ca urmare, minimizarea erorilor posibile, permițând în același timp combinarea ușoară a configurațiilor și modificarea acestora pentru diferite medii.
Dacă sunteți interesat de acest cadru, vă recomand să vizitați pagina sa oficială și să consultați întreaga , sau să explorați codul sursă .
Sursa: habr.com
