- Java DevOps usklajuje razvoj, delovanje, zagotavljanje kakovosti in varnost z avtomatizacijo, neprekinjeno integracijo in neprekinjenim zagotavljanjem aplikacij Java.
- Osnovna orodja, kot so Git, Jenkins, Maven, JUnit, SonarQube, Ansible, Prometheus, Grafana in ELK Stack, podpirajo robustno CI/CD, kakovost, spremljanje in beleženje.
- Platforme v oblaku, infrastruktura kot koda in arhitekture mikroservisov olajšajo uvajanje, skaliranje in zaščito aplikacij Java znotraj delovnih tokov DevSecOps.
- Testiranje zmogljivosti, opazovalnosti in inkrementalne izdaje pomagajo ekipam zanesljivo skalirati sisteme Java, hkrati pa ohranjajo visoko kakovost in hitre povratne zanke.

Java in DevOps sta popolnoma spremenila način, kako sodobne ekipe gradijo, pošiljajo in izvajajo programsko opremo, prehod od počasnih, ročnih izdaj k hitrim, avtomatiziranim in visoko sodelovalnim izvedbam. Ko združite ekosistem Java s kulturo DevOps, dobite potek dela, kjer razvoj, zagotavljanje kakovosti, operacije in varnost delujejo skupaj kot ena enota, namesto da bi kodo metali čez steno.
Java DevOps v bistvu govori o uporabi vrednot, praks in orodij DevOps v aplikacijah Java, omogoča ekipam hitro ponavljanje, pogosto izdajanje in ohranjanje stabilnosti sistemov, tudi ko spremembe postanejo stalnica. Zajema vse od nadzora izvorne kode in CI/CD do testiranja, uvajanja, spremljanja, varnosti in skaliranja v oblaku.
Kaj je Java DevOps?
DevOps sam po sebi je kulturni in organizacijski premik, ki povezuje razvoj programske opreme in IT operacije, tako obe strani neprekinjeno sodelujeta skozi celoten življenjski cikel: načrtovanje, kodiranje, testiranje, uvajanje, delovanje in izboljšave. Ne gre za specifično orodje ali tehnološki sklad, temveč za način dela, ki močno temelji na avtomatizaciji in nenehnih povratnih informacijah.
Java DevOps je preprosto uporaba teh DevOps načel in delovnih tokov v projektih Java, Ne glede na to, ali gradite monolite, mikrostoritve ali izvorne aplikacije v oblaku. Namesto izoliranih ekip za razvoj, zagotavljanje kakovosti, operacije in varnost imate medfunkcijsko skupino, ki si deli odgovornost za kakovost, zmogljivost in zanesljivost.
V okolju Java DevOps se ročna, počasna in napakam nagnjena opravila postopoma nadomeščajo z avtomatizacijo, vključno z gradnjo artefaktov, izvajanjem enotnih in integracijskih testov, pakiranjem aplikacij, zagotavljanjem infrastrukture in uvajanjem v testna in produkcijska okolja. To ekipam omogoča, da uporabnikom dostavijo funkcije v nekaj dneh ali celo urah namesto v tednih ali mesecih.
Praktično gledano, uvedba Java DevOps pomeni uvedbo praks, kot so neprekinjena integracija, neprekinjena dobava, mikrostoritve in infrastruktura kot koda, vse optimizirano za Ekosistem JavePrav tako zahteva močno osredotočenost na opazovalnost, varnost in standardizacijo procesov, da hitre spremembe ne pridejo na račun stabilnosti.
Prednosti in temeljna načela Java DevOps
Ena največjih zmag Java DevOps je, kako sodelovanje spremeni v prvovrstno skrb, prisilijo ekipe, da razbijejo silose in delijo kontekst. Razvijalci razumejo operativne omejitve, operativni inženirji dobijo zgodnji vpogled v prihajajoče spremembe, zagotavljanje kakovosti in varnost pa postaneta del istega neprekinjenega toka, namesto da bi bila pozni nadzorniki.
Ta enoten način dela omogoča veliko lažje hitro odzivanje na poslovne potrebe, ker ne čakate več na verigo prenosov med ekipami. Kodo je mogoče razvijati, testirati, pregledovati in uvajati iterativno z majhnimi, pogostimi posodobitvami, ki so varnejše in lažje za odpravljanje težav kot množične, redke izdaje.
Hitrejše povratne zanke so osrednje načelo v Java DevOps, kar pomeni, da se težave odkrijejo čim prej v cevovodu. Avtomatizirani testi, statična analiza in preverjanja integracije se izvajajo pri vsakem zapisu, tako da se napake pojavijo v nekaj minutah namesto v tednih po izdaji. To drastično zmanjša stroške odpravljanja napak in izboljša splošno kakovost aplikacije.
Avtomatizacija je še en temeljni steber: kjer koli je delo ponavljajoče se in deterministično, bi moralo biti skriptirano, od skriptov za gradnjo in opravil uvajanja do upravljanja konfiguracije in zagotavljanja okolja. To ne le odpravlja človeške napake, temveč ljudem omogoča tudi, da se osredotočijo na kompleksne naloge, ki dejansko zahtevajo presojo in ustvarjalnost.
Ključna je tudi miselnost, osredotočena na ljudi: DevOps poudarja lastništvo, odgovornost in empatijo med različnimi vlogami, spodbujanje članov ekipe, da razumejo težavne točke drug drugega. Razvijalci lahko zgradijo boljša orodja za delovanje, medtem ko lahko operativni delavci prispevajo k izgradnji cevovodov ali infrastrukturne kode, kar vodi do bolj odpornega sistema na splošno.
Majhne, postopne posodobitve so boljše od velikih izdaj, ker zmanjšujejo radij eksplozije, poenostavljajo vračanje prejšnjih različic in ohranjajo sistem neprekinjeno uporabljiv. To se popolnoma ujema s cevovodi neprekinjene integracije in neprekinjene dostave, ki ohranjajo aplikacije Java vedno v stanju, primernem za izdajo.
Osnovne prakse DevOps v projektih Java
Neprekinjena integracija (CI) je hrbtenica Java DevOps, od razvijalcev zahteva, da kodo pogosto združujejo v skupni repozitorij, kjer se ob vsaki spremembi izvajajo avtomatizirane gradnje in testi. To se izogne integracijskemu peklu, zgodaj odkrije napake in zagotavlja, da glavna veja ostane zdrava.
Neprekinjena dostava (CD) razširja CI z avtomatskim promoviranjem uspešno preizkušenih gradenj v produkcijska okolja, in idealno v samo produkcijo, ko so opravljene ustrezne odobritve ali prehodi. Za ekipe Java to pomeni, da bi lahko vsako potrditev (commit), ki preide skozi cevovod, načeloma varno uvedli dejanski uporabniki.
Arhitekture mikroservisov se naravno združujejo s praksami DevOps v okoljih Java, razdelitev velikega monolita na manjše, neodvisno uvedljive storitve, pogosto zgrajene z ogrodji, kot so Spring Boot, MicroProfile, Micronaut, Dropwizard ali Quarkus. Vsako storitev je mogoče razviti, preizkusiti in prilagoditi neodvisno, kar se odlično ujema z avtomatiziranimi cevovodi.
Infrastruktura kot koda (IaC) je še en ključni element, kjer so strežniki, omrežja in konfiguracija definirani z uporabo kode in predlog, namesto z ročnimi kliki v konzoli. Za Java DevOps to precej olajša zagon doslednih okolij, samodejno nameščanje popravkov za sisteme, podvajanje infrastrukture ter kodifikacijo pravilnikov o skladnosti in varnosti.
Ker sistemi Java pogosto delujejo v velikem obsegu, prakse DevOps poudarjajo tudi obvladovanje kompleksnosti, zagotavljanje, da ekipe ne postanejo preobremenjene s številom okolij, storitev, odvisnosti in konfiguracij. Avtomatizacija, standardizacija in pametna orodja pomagajo ohranjati nadzor, tudi ko sistemi rastejo.
Ključna orodja za Java DevOps cevovode
Čeprav se pri DevOpsu gre za kulturo in procese, so orodja vezivo, ki zagotavlja nemoteno delovanje Java DevOps cevovodov, še posebej za sodelovanje, avtomatizacijo in opazovalnost. V skoraj vsaki zreli nastavitvi Java DevOps se običajno pojavi več kategorij orodij.
Upravljanje izvorne kode z Gitom je običajno izhodišče, kar ekipam omogoča porazdeljen nadzor nad različicami z razvejanjem, združevanjem in sledenjem zgodovine. Repozitoriji Git razvijalcem omogočajo varno eksperimentiranje, enostavno vračanje na prejšnje stanje in ohranjanje jasnega vpogleda v to, kdo je kaj spremenil in kdaj.
Za neprekinjeno integracijo je Jenkins nepogrešljiv v svetu Jave, kot odprtokodni avtomatizacijski strežnik, ki temelji na Javi in lahko orkestrira gradnje, teste, pakiranje in prilagojene delovne procese. Jenkinsovi cevovodi lahko prevajajo kodo Java, izvajajo testne pakete, ustvarjajo dokumentacijo, gradijo artefakte, kot so datoteke JAR in WAR, ter uvajajo v različna okolja.
SonarQube pogosto obravnava kakovost kode in statično analizo, ki nenehno pregleduje kodo Java za morebitne napake, ranljivosti, vonjave kode in slogovne težave. SonarQube z razvojem aplikacije posodablja poročila o kakovosti, kar ekipam omogoča vzdrževanje visokih standardov in hitro odkrivanje degradacij.
Za avtomatizacijo uvajanja in upravljanje konfiguracij imajo orodja, kot je Ansible, pomembno vlogo, kar ekipam omogoča, da infrastrukturne naloge izrazijo kot preproste, človeku berljive opise namesto zapletenih skriptov. Ansible lahko upravlja zagotavljanje, uvajanje aplikacij, spremembe konfiguracije in ponovljive večplastne uvedbe.
Poleg teh, zrele trgovine Java DevOps pogosto uporabljajo dodatna orodja, kot so skladišča artefaktov kot sta JFrog Artifactory ali Sonatype Nexus za upravljanje artefaktov, Docker in Kubernetes za kontejnerizacijo in orkestracijo ter različne storitve CI/CD, kot je CircleCI, skupaj z orodji za spremljanje, kot so nastavitve, ki temeljijo na Dynatrace ali Consulu.
Gradnja in testiranje Java aplikacij v DevOps delovnem procesu
Praktični tok Java DevOps se običajno začne z ustvarjanjem projekta z orodjem za gradnjo, kot sta Maven ali Gradle, ki upravljajo odvisnosti, prevajanje, pakiranje in integracijo s testnimi ogrodji. V mnogih ekipah se integrirana razvojna okolja, kot sta Eclipse ali IntelliJ IDEA, uporabljajo za hiter zagon novih projektov Maven.
Za projekt Java, ki temelji na Mavenu, bi najprej zagotovili, da je nameščen Java JDK, nato v svojem integriranem razvojnem okolju (IDE) ustvarite nov projekt Maven in definirajte vrednosti groupId in artifactId, ki enolično identificirata projekt. Standardna postavitev imenikov Maven (src/main/java in src/test/java) pomaga pri čisti organizaciji produkcijske kode in testov.
Podpora za testiranje je običajno vključena v gradnjo z dodajanjem odvisnosti JUnit v datoteko pom.xml, potegne potrebno knjižnico iz repozitorija Maven Central. Ko je dodana v razdelek odvisnosti, bo Maven prenesel in upravljal to različico JUnit za vse gradnje.
Z vzpostavljeno odvisnostjo lahko ustvarite testni razred v src/test/java, uvozite ustrezne opombe in trditve JUnit ter nato napišite testne metode, ki preverjajo vedenje. Test lahko na primer preveri, ali metoda vrne določen niz ali pravilno obdela vhod, neuspešni testi pa se bodo vidno prikazali v dnevnikih IDE ali CI.
Izvajanje testov je tako preprosto kot klic izvajalca JUnit – bodisi neposredno iz integriranega razvojnega okolja (IDE) bodisi prek Mavenovega testnega cilja, ki izvede testni paket in poroča o stanju uspešnosti/neuspešnosti. V kontekstu DevOps se ti testi samodejno zaženejo pri vsaki potrditvi (commit) v cevovodu neposredne izbire (CI), zaradi česar so rezultati testov mehanizem za takojšnjo povratno informacijo za razvijalce.
Nastavitev CI/CD za Javo z Jenkinsom
Za popolno uporabo Java DevOps običajno potrebujete cevovod za neprekinjeno integracijo in neprekinjeno dostavo, ki ga poganja Jenkins ali podobno orodje, tako da se gradnje, testi in uvajanja zaženejo samodejno vsakič, ko so spremembe potisnjene v repozitorij.
V okolju Linux, kot je virtualni stroj Ubuntu v oblaku, Najprej bi namestili Java JDK in nato dodali repozitorij Jenkins, uvozili njegov ključ, posodobili sezname paketov in namestili storitev Jenkins. Ko se Jenkins zažene, ga odklenete z začetnim skrbniškim geslom, shranjenim na strežniku.
Po prijavi v Jenkins se običajno namestijo osnovni vtičniki za podporo Gitu, Mavenu in različnim drugim integracijam, kar vam omogoča povezavo Jenkinsa z izvornim repozitorijem vašega projekta Java in postopkom gradnje. Ta korak je večinoma avtomatiziran v čarovniku za namestitev Jenkinsa.
Ustvarjanje opravila CI vključuje definiranje novega elementa v nadzorni plošči Jenkins, izbira ustrezne vrste opravila in konfiguriranje upravljanja izvorne kode z URL-jem Git vašega projekta Java. V konfiguraciji gradnje lahko določite cilje Maven, kot so čista namestitev ali cilji Maven najvišje ravni po meri za prevajanje kode in izvajanje testov.
Za pakiranje lahko Jenkins arhivira artefakte gradnje, kot so datoteke WAR, ki jih je ustvaril Maven, pogosto z uporabo vzorcev, kot je **/*.war, zberejo vse ustrezne pakete ne glede na njihov imenik. Te artefakte je nato mogoče uporabiti za korake uvajanja v cevovodu.
Za omogočanje neprekinjenega uvajanja lahko Jenkins integrirate z aplikacijskimi strežniki, kot je Apache Tomcat, namestitev in konfiguriranje Tomcata na ciljnem strežniku, prilagajanje vrat za preprečevanje konfliktov in zagotavljanje ustreznih uporabniških vlog in dovoljenj za omogočanje oddaljenih namestitev iz Jenkinsa.
Z namestitvijo vtičnika »Deploy to container« lahko Jenkins samodejno pošlje datoteke WAR v Tomcat, ciljanje na določene URL-je in uporaba poverilnic, varno shranjenih v Jenkinsu. Vsako uspešno gradnjo je nato mogoče namestiti v pripravljalno ali produkcijsko instanco Tomcat, kar zagotavlja celoten tok CI/CD za aplikacijo Java.
Uvajanje Java aplikacij v oblak
V Azureju se tipična uvedba Jave lahko začne z ustvarjanjem računa in dostopom do portala Azure, kjer lahko v razdelku Storitev aplikacij definirate spletno aplikacijo. Med ustvarjanjem te aplikacije izberete možnosti, kot sta različica izvajalnega okolja Java in sklad aplikacijskega strežnika, na primer Java 8 z JBoss ali drug podprt strežnik.
Ko je aplikacija omogočena, lahko uporabite Azure Cloud Shell za interakcijo z repozitorijem Git vašega projekta, kloniranje kode aplikacije Java v oblačno okolje. V imenik projekta nato integrirate vtičnik Azure Web App Maven, ki omogoča komunikacijo Mavena s storitvami Azure.
Po konfiguraciji vtičnika lahko aplikacijo Java zapakirate in namestite prek ukazov Maven, na primer mvn package, ki mu sledi azure-webapp:deploy, ali kombiniran ukaz. Ko je uvajanje končano, bo Azure izpisal URL, kjer je aplikacija Java aktivna in pripravljena za testiranje ali produkcijski promet.
Podobni vzorci veljajo za AWS, kjer lahko storitve, kot so Elastic Beanstalk, ECS ali EKS, gostijo aplikacije Java, in storitve CI/CD, kot je CodePipeline ali orodja tretjih oseb, povezujejo celotno verigo gradnje, testiranja in uvajanja na način, prijazen DevOps.
Spremljanje in beleženje v Java DevOps
V svetu DevOps je pošiljanje kode le polovica zgodbe; potrebujete tudi robustno spremljanje in beleženje, da bi razumeli, kako se aplikacije Java obnašajo v produkciji, zgodaj odkriti anomalije in odločitve utemeljiti na dejanskih podatkih in ne na ugibanjih.
Spremljanje se običajno osredotoča na metrike, kot so latenca, prepustnost, stopnje napak in izkoriščenost virov, kar vam pomaga prepoznati ozka grla v delovanju, težave z zmogljivostjo ali napake infrastrukture. Želite imeti vpogled tako v aplikacijo kot v osnovne sisteme, ki jo podpirajo.
Po drugi strani pa beleženje beleži podrobno zgodovino dogodkov, napake in spremembe stanja skozi čas, zagotavljanje konteksta, ko gre kaj narobe. Dnevniki so ključni za odpravljanje napak v incidentih, preiskovanje varnostnih dogodkov in analizo dolgoročnih trendov v delovanju sistema.
Pogost sklad za metrike v Java DevOps je Prometheus za zbiranje in Grafana za vizualizacijo. pogosto se izvaja v Dockerjevih vsebnikih ali na virtualnih strojih. Prometheus pridobiva končne točke metrik (običajno /metrics) iz aplikacij ali izvoznikov in shranjuje podatke časovnih vrst, ki jih Grafana lahko poizveduje in predstavi kot nadzorne plošče.
Za nastavitev bi morali namestiti Grafano, prenesti Prometheus in orodja, kot je node_exporter, nato konfigurirajte Prometheus za strganje metrik iz lokalnega cilja izvoznika, običajno localhost:9100. Ta konfiguracija je določena v datoteki YAML, kjer definirate opravila strganja in cilje.
Ko zaženete Prometheus s konfigurirano datoteko, lahko Grafano povežete s tem virom metrik, in po želji konfigurirajte nastavitve remote_write pri pošiljanju podatkov v upravljani primerek Grafana. Od tam zgradite nadzorne plošče, ki prikazujejo porabo procesorja, porabo pomnilnika, stopnje zahtev in vse meritve po meri, ki jih razkrivajo vaše storitve Java.
Za združevanje in analizo dnevnikov je ELK Stack – Elasticsearch, Logstash in Kibana – široko uporabljena rešitev, ponuja iskanje, preoblikovanje in vizualizacijo dnevnikov iz številnih storitev in komponent Java.
Tipičen potek dela vključuje prenos in razpakiranje Elasticsearch, Kibana in Logstash, zagon Elasticsearcha za zagotavljanje iskalnega in indeksirnega mehanizma ter njegovo preverjanje na localhost:9200. Nato zaženete uporabniški vmesnik Kibana na localhost:5601 za vizualizacijo in raziskovanje vhodnih podatkov.
Logstash je nato konfiguriran za definiranje vhodnih, filtrirnih in izhodnih cevovodov, kjer se lahko dnevniki vnašajo iz standardnega vhoda, datotek ali drugih virov, jih po možnosti obogatijo ali razčlenijo in nato posredujejo Elasticsearchu. Že preprost cevovod, ki bere iz stdin in zapisuje v stdout, je dovolj za testiranje nastavitve pred vključitvijo dejanskih dnevnikov aplikacije.
Varnost in DevSecOps v Java Pipelines
Varnost mora biti vgrajena v življenjski cikel Java DevOps, ne pa privita na koncu. zato je koncept DevSecOps pridobil toliko veljave. Vsaka faza – od načrtovanja in razvoja do testiranja, uvajanja in delovanja – potrebuje varnostne preglede in kontrole.
Med razvojem bi morale biti varne prakse kodiranja standardno pričakovanje, vključno z rednimi, osredotočenimi pregledi kode namesto obsežnih enkratnih revizij. Pregledovanje manjših kosov kode vodi do boljšega pregleda in olajša odkrivanje subtilnih varnostnih težav in funkcionalnih napak.
Razvijalci potrebujejo tudi ozaveščenost in orodja, ki jim bodo pomagala pri pisanju varne kode Java, kar lahko vključuje skenerje ranljivosti, orodja za statično analizo in ogrodja, ki so posebej zasnovana za odkrivanje pogostih slabosti. Nekatera specializirana orodja in platforme se osredotočajo na testiranje penetracije, simulacijo izkoriščanja ali skeniranje znanih CVE v odvisnostih.
Na strani uvajanja, varno upravljanje tajnih podatkov in strog nadzor dostopa je bistvenega pomena, zagotavljanje, da lahko produkcijske sisteme uvajajo ali spreminjajo le pravi ljudje in avtomatizirani sistemi. Želite dovoljenja z najmanjšimi privilegiji, izolirana okolja in močno preverjanje pristnosti okoli CI/CD in upravljanja infrastrukture.
Fizična in omrežna varnost sta še vedno pomembni, zlasti pri uporabi strežnikov s samostojnim upravljanjem, kjer zaščita podatkov, omejen dostop do strežniških sob in utrjeni omrežni perimetri igrajo vlogo v celovitem pristopu obrambe v globino.
Repozitoriji artefaktov, kot sta JFrog Artifactory ali Sonatype Nexus, lahko pomagajo tudi pri obvladovanju varnostnih tveganj, s sledenjem komponent, skeniranjem ranljivosti, uveljavljanjem pravilnikov o tem, kaj se lahko uporablja, in integracijo z orodji za avtomatizacijo izdaj za opozarjanje ali blokiranje tveganih odvisnosti kot del cevovoda.
Skaliranje in optimizacija Java aplikacij z DevOps
Prilagodljivost pomeni, da lahko vaša Java aplikacija in osnovna platforma elegantno obvladujeta povečano obremenitev, povečanje obsega med velikim povpraševanjem in zmanjšanje obsega obsega, ko povpraševanje pade, da se nadzorujejo stroški. Praksa DevOps to dinamično skaliranje naredi veliko bolj obvladljivo.
Vendar pa skaliranje sistemov Java ne pomeni le dodajanja več strežnikov, temveč vključuje tudi organizacijske in tehnične izzive, kot so uskladitev kulture podjetja z načeli DevOps, vlaganje v popolno avtomatizacijo in upravičevanje stroškov bolj dovršenih orodij in infrastrukture.
Testiranje obremenitve in spremljanje delovanja sta ključni tehniki za zagotovitev, da se vaše storitve Java lahko spopadejo s prometom iz resničnega sveta, kjer testi simulirajo sočasne uporabnike in merijo odzivne čase, prepustnost, stabilnost in stopnje napak. To vam pomaga odkriti ozka grla, počasne končne točke ali uhajanje virov, preden jih stranke občutijo.
Testiranje zmogljivosti se lahko uporablja tako za primerjavo med različnimi različicami ali sistemi kot za potrditev stabilnosti pri največji obremenitvi, tako da lahko samozavestno uvajate nove izdaje, preoblikujete kodo ali uvajate novo infrastrukturo, ne da bi ugibali o vplivu.
Obremenitveni testi dopolnjujejo orodja za spremljanje s potrditvijo, kako se sistem obnaša v specifičnih stresnih pogojih, kar je bistveno za arhitekture mikroservisov, kjer lahko interakcije med storitvami ustvarijo kompleksno dinamiko delovanja.
Kar zadeva strategije skaliranja, je avtomatizacija spet temelj, omogočanje skupin za samodejno skaliranje, posodobitve, modro-zelene uvedbe in kanarčkove izdaje. Ko cevovodi avtomatizirajo večino operativnih in razvojnih nalog, postane skaliranje novih primerkov ali regij stvar konfiguracije in pravilnika in ne ročnega dela.
Nenehne povratne informacije uporabnikov bi morale spodbujati tudi optimizacijo, kjer ekipe zbirajo in ukrepajo na podlagi uporabniških izkušenj, prilagajajo funkcije in zmogljivost ter uvajajo postopne izboljšave prek istega DevOps cevovoda, ki obravnava vse ostalo.
Tudi tukaj je pomembna izbira pravega orodja, zagotavljanje, da lahko orodja, ki jih sprejmete, definirajo natančno določene vloge in pravila, se integrirajo z orkestracijo izdaj, sledijo komponentam in ranljivostim, zagotavljajo poročanje in analitiko ter olajšajo organiziranje in iskanje artefaktov ali konfiguracijskih elementov v velikih kodnih bazah Java.
Ko se vsi ti deli – kultura, orodja, avtomatizacija, spremljanje, varnost in prakse skaliranja – združijo, Java DevOps omogoča ekipam, da zgradijo visoko produktivne in odporne delovne tokove, ki ohranjajo Java aplikacije zanesljive, varne in se nenehno izboljšujejo, hkrati pa se še vedno premikajo s hitrostjo, ki jo zahtevajo sodobna podjetja.