LEARNWHAOTY UNEED
ANDLEARNITWEL
LAURENŢIUCILSP Ă
FORE WORDYVBCI OT R ENTEA
MANNING
Businelogcd
T ransctio
i1gFure simuper’cTthv lair
maUciesbvrgw. oant ilyg
h te r s u l o f b i n g c d ,
hitsoynalmaplortfwhbatuildshe
pa’scompletfunciaoy.Lk
cebirgthasmotsnlyduerwaternd
idhenfromview,wedon'tsemostof
h te c o d i a n r p s b u
ti'sprodvebync.
Caching
Security
Datrnsfe
Login
Dat
r
p ersitnc
UseSpringcutyomplement
theaunico dauthrzin
configurats.
U sethSpringIoCcaet
m angeobjctisr
a ndglueiothrfncals
S pringovdes.
U seSpringMVCorSpingWebFlux
t oimplementhRESTdpoints
c aledbythcinpsore
b ackendsoluti.
U seSpringBoteash
c omplexityofurcngas
a ndwritelscodmplement
t hea
p p .
2Figure expionsucgdla ,yrbkten iSusprgofbetlTh
anmadpiclot,he sunrgapico,tdbehfunilasg
managiterohud-pmey sagebrok.
UseSpringDatocne
theSQLandNoSQLdatbse
yourbackendpustoeri
theda.
to
UseSpringItao
SpringfoAacheKfkto
moreasilyndmesage
y our
J MSorKafkt
p ics.
t
SpringtaHere
L EARN
WHAT
YOU
NEED
AND
LEARN
IT
WELL
LAURENŢIU SPILCĂ
BY V ICTOR
R ENTEA
F OREWORD
MANNING
S H EL T R
I S LA N D
For nli enformationa dordeinog fthisandotherMan ingbo pks, leavit
www.man incog. m.Thepublisherosdf icountsonthisbo kwhenorde inquantiy.
Fomor reinfomr ation,pasecol ntac
SpcialesDepartment
Man ingPubcatiol nsCo.
20BaldwinRoda
POBox761
ShlterIsandNY, 1964
Email:ordes@man inog.c m
©221b0 yMan ingPubatiolc nsCo.Allrightesvd.
No partofhpis ublicatonmayberpoducedto,s redinetravmlsy ,ortansmited,n
anof yrmobmery anelctrosnmeic, chanpicl, hot copyino,grtherwwi,ise thoupt riowriten
pmer isonohft epublishr.e
Manyofthedsignatonsuedbymanufact nres dsetolr distngushi t eirpoductsare
mclai edastr emarks.Wherthosedignatonaps earinthebo nk,a dMan ing
Publicatonswasawareotfdemclaimrk ,thde signatonshavebnprintedin italcps
olcraps.
Reoc gniz thg mie portanoce pf resvinwhg hat bs enwritenMas, n inpg’s otlicy have
thbe o kswepublishprintedonacidfre-pa ner, dwerteox urbefsot r thaend.
Reoc gniz alsog uresponibs tolyc nthserv ouorces f upr lanMaet, n inbg o earks
printedonpa pth15erlsanci eylrdt andprocdes withouthueoslmf ental
chlorine.
Thaue thorandpublisher avmadevryfot ensuthre a einformationi thisbo k
wacos retapsime.Theauthoanr dpublisherdonosuta meandherbydlaimsc any
liabtyoanpy artfony los,damge,oa rdisuptioncaueds byeros romisons,whethr
sucheros msionresuof ltmneglinacd, enoat,r yhcaueorfs, manuy sage
ohft einformioat nherin.
Man ingPubcatiol nsCo.
20BaldwinRoda
POBox761
ShlterIsandNY, 1964
Deelov pmendt ior: MarinaMichaels
Technicaldeov pmendt ior: AlScher
Reviewde itor: MihlaBae tin
Productionde itor: AndMay rinkohvic
Copdye itor: MichleMitchel
Pro adfre : KeriHales
Technicalpro adfre : Jean-FrançoisMorin
Typetrs: Gordna Sli ovic
Coverdigns er: MaTurija dor
ISBN978162
PrintedinthUne itedsSoa fAmecari
i c´
briefconts
P ART 1
FUNDAMENTALS ................................................................1
1
P ART 2
■
2
■
3
■
4
■
5
■
6
■
Spring theralworld 3
TheSpringcontex:Defin gbeans 2
TheSpringcontex:Wiringbeans 50
TheSpringcontex:Usingabstrcions 75
TheSpringcontex:Beanscopesandlifecy 9
UsingaspectwithSpringAOP 12
I MPLEMENTATIO N ......................................................... 151
7
■
8
■
9
■
10
■
1
■
12
■
13
■
14
■
15
■
UnderstandingSpringBootandSpringMVC 153
Implementi gwebap swithSpringBoot
andSpringMVC 176
UsingtheSpringwebscopes 19
Implementi gRESTserivc 24
ConsumingRESTendpoints 245
UsingdatsourcesinSpringap s 264
UsingtransctionsinSpringap s 284
Implementi gdatpersincewithSpringData 302
TestingyourSpingap 32
iii
contes
foreword
prefac
acknowledgments
abouthisk
abouther
abouthecvrilsn
xi
xi
xv
vix
xi
xi
P ART 1 FUNDAMENTALS ......................................................1
1
Spring in the real world
1.
Whyshouldweuseframeworks?
1.2
TheSpringecosytm
3
4
7
1.3
DiscoveringSpCore:ThefoundatiSprg 8
SpringDataAcesfaturoimplementhap’sric 10
TheSpringMVCcapbiltesfordvngwebaps 10
Sprintesgfau 10
Springinreal-worldscenarios
■
Using
■
■
Profjmects Sprtihnecosygm
10
12
UsingSpr thedvlomentofabckdp 12
Springatesuomationp 14
devlopmentofadskp 16
ap s 16
■
■
■
v
UsingSpr mobile
UsingSprfothe
Using
The
vi
CONTENTS
1.4
Whennot useframeworks
17
Younedthavsmalfotprin 17
cu stom cod e 1 8
frameworkimpractil 18
toafrmework 18
2
1.5
Whatwilyou learni thisbo k
■
■
Securityndsa
Aubndatexisgcomizatonsmakea
■
Youwon’tbefirmswitchng
19
The Spring context: Defining beans 22
2.1
CreatingaMavenproject
2.
Adding ewbeanstoheSpringcontex
23
29
3
Usingthe@Bean otiadbensothSprig
contex 3
S p r ci on g t e x 4 1
contex 45
Usingsteroypa indbestoh
■
■
ProgammaSprintheadgbcolys
The Spring context: Wiring beans 50
3.1
Implementi grelationshipsamongbeansdefindinthe
configuratonfile 51
Wiringthebasu dircmethodcalbewenth@Bean
methods 5
method’sparmetrs 58
3.2
Usingthe@Autowiredan otai ntoinjectbans
■
Wiringthebasu @Bean otd
61
4
Using@Autowiredtonjchvalusrgtecfid 61
Using@Autowiredtonjchvalusgtenorc 64
Usingdep cyjtionhruges 65
3.
Dealingwithciruladepndencis
6
3.4
Cho singfrommultipebansintheSpringcontex 68
The Spring context: Using abstractions
4.1
Usinginterfacsodefincontracs
76
Usingterfacsoduplingmplementaios 76
requimentofhscari 79
withousngafrmework 80
4.2
Usingdepndencyinjetonwithabsctrions
85
DecidngwhicobjetsuldparfSingcotex 85
Chosingwhatou-wirefommultipemplementaios
ofanbstrci 91
4.3
75
Focusingonobjectrsponsibltewithserotype
an otai ns
96
■
■
Implementighrqument
The
vii
CONTENTS
5
The Spring context: Bean scopes and life cycle 99
5.1
Usingthesingltonbeanscope
10
Howsingletobawork 10
esncario 107
5.2
Usingtheprot ypebanscope
■
Usingeardlzystniao
6.1
HowaspectworkinSpring
6.2
Implementi gaspectwithSpringAOP
Protypebansil-world
121
123
126
Implementigasmpleasct 127
method’sparmetrsandhu vle 135
anotedmethods 140
canuse 143
Theaspctxuionchain
■
1
Using aspects with Spring AOP
6.3
Singletobasr-world
108
Howprotyebanswork 1
esncario 15
6
■
■
Alteringhcpd
■
■
Intercpig
Otheradvicnot syu
14
P ART 2 I MPLEMENTATIO N ............................................... 151
7
Understanding Spring Boot and Spring MVC 153
7.1
Whatiswebap ?
154
A g en ralo v i w ofa w eb a p 1 5
implementigawebapwithSprng 156
contaier webapdvloment 159
7.2
ThemagicofSpringBoot
■
■
8
Usingaservlt
162
UsingapjroectlzsviaSprngBot
project 162
management 168
on d ep ci s 16 9
7.3
Diferntashio
Implementi gawebap withSpringMVC
■
Ussimtodepnargcy theplif
■
Usauintocgfverbysd
170
Implementing web apps with Spring Boot and Spring MVC 176
8.1
Implementi gwebap swithadynamicvew
17
8.2
HTtheGeon dat ing Trequst P 182
tosendafrmclientosrv 183
sendatfromclientosrv 187
UsingtheGETandPOSTHTTPmethods
Usparmequsting etrs
■
■
189
Usingpathvrbleso
viii
CONTENTS
9
01
Using the Spring web scopes 199
9.1
UsingtherquestcopeinaSpringwebap
201
9.2
UsingthesionscopeinaSpringwebap
9.3
Usingtheap licatonscopeinaSpringwebap
209
2 18
Implementing REST services 224
10.
UsingRESTservictoxhangedatbewenap s
26
10.2
Implementi gaRESTendpoint
10.3
Managi theHTTPresponse
27
231
body respn a s object Sndig 23
andhers 234
lev 237
10.4
1
21
Usingarequestbodytogedatfromtheclint
■
■
staurepon th Seing
Managiexcptoshdn
24
Consuming REST endpoints 245
1.
CalingRESTendpointsuingSpringCloudOpenFeign
1.2
CalingRESTendpointus ingRestTemplate
1.3
CalingRESTendpointsuingWebClient
249
253
256
Using data sources in Spring apps 264
12.
Whatdsourceis
265
12.
UsingJdbcTemplateoworkwithpersitd at
12.3
Customizngtheconfiguratonofthedatsource
269
278
Defingthedasourci pltnoersfi 279
UsingacustomDataSourcebn 280
31
41
Using transactions in Spring apps 284
13.
Transctions
13.2
HowtransctionsworkinSpring
13.
Usingtransctionsi Springap s
287
289
291
Implementing data persistence with Spring Data
14.
WhatSpringDatais
14.2
HowSpringDataworks
14.3
UsingSpringDataJDBC
30
306
31
302
ix
CONTENTS
51
Testing your Spring app
15.
Writngcoretlyimplementdes
15.2
Implementi gtesinSpringap s
325
327
Implementigu s 328
tes 341
apendixA
apendixB
apendixC
apendixD
apendix E
apendix F
apendixG
323
Architeualpos 347
UsingXMLforthecnxigua 358
Aquickntrod HTTP 360
UsingJSONformating 369
InstaligMySQLandcretigbs 372
Recommendetols 380
Recommendelarigmaterialsfouhdy 382
index
385
■
Implementig rao
forewd
Born as n laternative o EJBs in the arly 20s, the Spring framework quickly overto k its op one t with the simplicty of its progamming model, the varity of its eatures, and its third-party libray integraions. The Spring ecosytm grew over the
inyears tohbe roadnest dmomast tudre vlopmenfratmewoavirlkbe ina py rogramming languae. Its main competior quit he rac when Oracle stop ed the volutionofJavEE8,andthecommunityo koveritsmaintena ceviaJkrtEE.
Accordec(sunitorveyg
thisframe ewourknderlyinmog thre anhotaplfJv e licatonThs. bfactuis ldusp
anenormouscodebasthatmakesitcralfonyJavdelopertolanSpring,as
it’s inevtabl you’l encounter this technol gy in your care. I’ve ben devloping
ap licatons with Spring for 15 yeas, nd today the tams that I rin in hundre s of
companiesarlmostaluingSpring.
Ththisrealy dt espbit ensogpopupit’slar, hey ardtofindquinalty roductorymaterial.Therfncedocumentaionisthousandsofpageslong,describngal
thesubtleisand etailshatcouldbehelpfulinveryspcifsenarios, it’notan
option for a newcomer. While online videos and tuorials typical f to engae the
studenfvwryt, bo capks tuhre snoce Spf rinfamg ework, ftenspendinlog ng
pages debating topics that prove to be irelvant to the problems faced in modern
ap licaton devlopment. With this bo k, howevr, it’s evry hard to find anything to
remove; al the concepts coverd are recuing topics in the devlopment of any
Springap licaton.
hmtp/: ng.bz/l9VB
and
xi
hmtp/: ng.bz/B1Ar
Sprin), g
xii
FOREWORD
Threadisgntlybroughtoleavsuficentobecomerapidlyproductivena
project based on the Spring framework. My own exprince train g thousands of
employes howed me tha the vast majority of devlopers working with Spring today
don’t se the ideas cleary s this bo k paints hem. Furthemore, devlopers a
unaware of the many pitfals bout which this bo k warns it reads. In my opinon,
thisbo kisamust-readforanydevloperstaingon theirfstSpngproject.
The atntion with which Laurenţiu anticpaes the typical questions ocuring in
threadmi’s ndprohves xtni epsv rinteachinSpg rni g Thclas. teachis ingfluencyalowstheauthort adoptapersonal,warmtonethatmakesthisbo kan
efortls and pleasnt read. The bo k has clear, sharp struc re, and I realy oved
how complex topics were progesivly rad and explained and reitad in subsequentchapters.
This bo k shines ni tha the read is also introduced to fundamental concerns
regadinlaegpcy rojecut sinthg Spe rinfamg ewoInrk. a ecosytmdominatedby
Sprni g Boot, I find it very usef l to sneak pek under the ho d. On the other nd,
the bo k also gently introduces the rade to last-genration technol gies, lk Feign
clientsandevnreactivprogamming.
Iwishyouaplesntreading,andnevrhesitaogy urhands irtywithsome
codewhenveryouthinkthingsetcomplicated.
—V
J AVA
CHAMPION
, TRAINER
, AND
R
ICTOR
CONSULTANT
ENTEA
prefac
Sharing knowledg and creating learni g material s a hob y for me. In ad iton to
beinsaog ftwarde vlopeIr’,malsotechAser. Jtarvinesrinc2e09I,’vtaught
Jav to housands of devlopers with various lev of exprince, from universty udents to exprinced devlopers in large corporati ns. In the ptas few years, I’ve
cometoc nsiderSpring amust-learn forbegin ers.Appstoday re nol nger implementedwithvanilanguas—e almostevryhingrelisonframeworks.SinceSpring
is the most popular ap licaton framework in the Jav world today, Spring is somethingadevlopernedstolearni theirfstowaredvlopmentsep.
In teaching Spring to begin ers, ’veI realzdi that i s til tread as omething
youlearnonwhly enyoualredhy soave mexprincoe dinWhg. enstarIdwritng
Spring Star Here
topic,butmystudentsconti uedtoelmetheyfoundthosematerialshardtounderstand. Irealizd theproblem was not hathe xistnglearningmaterialwasn’t excllent, but that ther was no de icatd study guide for an absolute begin er, so I
deci d to write a bo k that doesn’t consider Spring something you learn after you
have some exprince, but instead something you can learn with minimal foundationalk owledg.
Technol gy changes quickly. But i’s not only the tchnol gy changi . We also
nedtoc nsidher owwecanimprothve wawey teach techs nol Sgies. myears
ago, one would star learni g the languae fundamentals and get employed as a
devloper without evn knowing what a framework is. But today, thes things are
difernLet. arni thal gde lanotisf guae p-fronist ol nthger watoyquickly
, ther were alredy plenty of tuorials, bo ks, and articles on the
xiii
xiv
PREFACE
devloypthskunil ewodtos inftwa rkdaevlopmentamNo. rewcomI , mend
devlopwistare thfue ndamenatls do, nthce y cofelmfortabwile thbeasic,
stalreni nag p licatonframeworSkp. insg, myopinonth, be aspt licaton
framework to star learni g. Understanding the Spring bsaic also opens do rs to
learni g other technol gies and changes the old, linear learni g ap roach into
somethinthgloat moks tre—a lik re andeachbranchaotisefwr amework
youlearni parlewithothers.
I d esig n ed
framework with. This bo k leads you step-bystep, providng you with al the sntial
theortical knowledg, acompanied by examples tha practily p ly the discued
topics. I hope this bo k wil bring sinifcant value to you, the rade, and help you
quicklybo styourSpingk owledgandopendo rsfourtherlani g.
Spring Star Here
to be the bo k you want o star learni g the Spring
acknowledgments
This bo k wouldn’t be posible without he larg number of smart, profesi nal, nd
friendlypeoplewhohelpdmethroughoutisdevlopmentproces.
First,abigthankyoutomywife,Daniela,whowasalwaystherfome,andwhose
valubleopinons,conti uous p ort,andencouragementwereahugehelptome.
I’d also like to exprs my gratiude and send special thanks to al the coleagus
and friends who helpd me from the very first table of contents and proposal with
theirvalubleadvic.
A big thank you goes to the ntire Man ing team for their huge help in making
this bo k a reality. I espcialy want to recognize Marina Michaels, Al Scher, and
Jean-François Morin for always being incredibly sup ortive and profesi nal. Your
advicehasbroughtgreavlutohisbo k.
I’d like to thank my friend Ioana Göz for the drawings he cratd for the bo k.
Sheturnedmythoughtsintohecarto nsinthebo k.
alsoIwantoexpmyrs ap reciatonthoal reviwwhers oprovide suchusef l
fedbacktevrysp.ToAlainLompo,AleksandrKarpenko,AndreaCarloGranat,
Andrea Paciol, Andres Damian Saco, Andrew Oswald, Bob y Lin, Bon ie Malec,
ChristanKreutzr-BDaeck, nCaeli Darl, vidLiOrsle penDe, UndRure’ shonHa, rinath
KuntamuHåkal, vardWaJérôl,mBae tonJim, WelchJo, ãMiguPelDiirs as, Lucian
Enache, Mat D.,Mathew Grene, Mikael Byström, Mladen Kneži
c ´ , Nathan B.
xv
xvi
ACKNOWLEDGMENTS
Crocker, Pier-Michel Ansel, Rajesh Mohann, Ricardo Di Pasquale, Sunita Chowdhury,TanWee,andZohebAinapore,y urinputhasmadethisamuchbetr o k.
Finaly, a special thank you to my friends, Maria Chţi u, Andrea Tudose, Florin
Ciuc leus ,andDanielaInafordvisngmealongtheway.
abouthisk
Since you’ve opend this bo k, I asume youre’ a software devloper in the Jav ecosytem who found out it’s usef l to learn Spring. This bo k teaches you the Spring
foundations, auming you know nothing in the first place bout frameworks and, of
course,aboutSpring.
You’l starwithwhat frmeworkis and then graduayl ern the basic of Spring
with ap lied examples. You wil not only learn to use the framework’s compone ts
andcapbiltes, uyot ua’lsoernthesntioals whf aht p enbs ehindthscens
in thes capbiltes. Knowinghow the framework peratswhenyou seaparticul
compone thelpsyoudesignbetrap s,andsolveproblemsfater.
When you finsh this bo k, you’l have learned the fol wing skl,i which are
hig lyrevantinmplementingap s:
■
■
■
■
■
■
Configurng andusinthSpg erincog na tex depndeni cy jetionwithSpring
Designi gandusingaspect
Implementingwebap s
Im p lem en tin g d at ex ch a n ge b tw e n a p s
Persitngdat
Testingmplementaions
You’lfindthisbo kisvalubleforthefol wing:
■
■
■
Workingonanap usingSpringfory urjob
SucedingnatechnicalnterviwforaJvdeloperol
Obtain gyourSpingcertifaon
xvii
xviii
ABOUT THIS BOOK
Evenifthisbo k’sfirtpurposeinot pre ayouforaSpringcertifaon,Iconsidertamust-readbefordging todetailscrfonexamtypicalrequires.
Who should read this book
This bo k is for devlopers who understand basic object-orinted progamming and
Jav concepts and want o learn Spring or efsh their Spring fundamentals knowledgYo. udonont edtohavpe riouesxprienwice thanfyramewobrk, uyot uned
utondthersalnbcuiJvwegdthsea roughothuboexamk’s ples.
Spring is one of the most encounterd technol gies in Jav ap s and wil most
likbey usedvnmoinre thfue t rFe. o Jdav elopther, mais Skpes rinmuag stknow today. Learni gwhat I echoy u in thisbo kwil help you upskil,provide you
with the Spring foundation knowledg and skil you ned to sucef ly pas Jav
interviw,andworkonanap usingSpringtechnol gies.Thebo kalso pensdo rs
tofurtherstudySpringdetailshatremorecomplex.
How this book is organized: A roadmap
This bo k is div ed into two parts hat cover 15 chapters. We’l star our discuon
(inthefirstpaofthebo k)withsraightforwardexmplestohowyouhowtomake
Sprinawg oare yf uapr licatonWe. th’l enbuildexampthles nat byole utounderstand the core of any real-world Spring ap . Once we finsh with Spring Core bacsi,
we’ldiscuSpringDatandSpringBootbaics.
From chapter 2 to the end of this bo k, you’l find tha theortical aspect are
acompaniedbyprojectsinwhichweap lythenoti nswediscu.Iexplainthecode
in thes xamples nip et by snip et. My recommendation is you build thes xampleswithmewhilerading.Then,youcancompareyoures wilt thmysolution.
As presnted in the fol wing fiure, I designed the bo k’s chapters o be rad in
the given orde. In chapters 2 through 5, wher we discu the Spring contex, you
mighfint dthexamples rdomina thly eortFical. onr yonwie thlioe nr oexprience with Spring, it’s ential o tsar his way. Don’t wory! I presnt he foundations in the easit posible way, and then our examples and discuons gradualy
becomemoresophistcaedoreftlca-world,production-readycode.
Spring aspects
Chapter 6
REST services
Chapters 10 and 11
Introduction
Chapter 1
Persisting data
Chapters 12 through 14
The Spring context
Chapters 2 through 5
Spring Web
Chapters 7 through 9
Testing
Chapter 15
Figure 1 If you st art with no (or very litt le) knowledge about Spring, t he best way to
read t he book is t o st art wit h the first chapt er and read everything in order.
xix
ABOUT THIS BOOK
yoIf ualreduy nderstandthSpe rincog natex d SprinAOP
g weyol, ucanskip 1art
andgodirectlyopart2,“Implementaion”(chapters7–15),apresntedinthenext
figure.
Persisting data
Spring Web
Chapters 7 through 9
REST services
Chapters 10 and 11
Chapters 12 through 14
Testing
Chapter 15
Figure 2 If you already underst and the Spring framework’s foundat ion and know how t o
use t he Spring cont ext and design aspect s, you can start with part 2, where we use Spring
capabilities t o implement apps mirroring scenarios you face in real-world systems.
Onceyoufinshreadingthisbo k,you’lhavelrnedpelntyofskil devlopa ps
like a profesi nal. You’l earn to con ect o datbse using the most encounterd
techniques today, nd you’l earn how to make ap s communicate with each other.
We’lendthebo kwithteachingacritlopic:tesng.I’lseaonthe texherand
therbyad ingstorie fmyexprinceandnoteswithvalublepicsofadvice.
Remembethr Sapt rinvgasut niversa,ndonbe o wok n’teachyouevrything
abouti.Withthisbo k,yougetsardwiththeframeworkandlearnthefundamentalski ofusingSpring’s valublecomponents.Throughout hebo k,I ref wher
ap ropriate, o ther sources and bo ks tha detail he topics we discu. I strongly
recommend youread thosead itonalresources andbo ksto broadenyour pers ctiveonthediscuedtopics.
About the code
The bo k provides about 70 projects, which we’l work on in chapters 2 through 14.
When working on a specif example, I mention the project’s name, which implementshatexmple.Myrecommendationis tory writeyourexamplefromscrath
and then use the provide project only to compare your solution with mine. This
ap roachwilhelpyoubetrunderstandtheconceptsyou’relani g.
Each of the projects i bulit with Maven, makni g it easy to mi port into any IDE. I
used InteliJ IDEA to write he projects, but you can cho se to run them in Eclipse,
Netbeans, or any other to l of your choice. Appendix F gives you an overiw of the
recommende to ls.
Thisbo kcontai smanyexamplesof urceode,bothinnumberdlistngsand
in nli e with normal tex. In both case, source code is formated in
font like this tosepartifomordinarytex.Sometimescodeisalo
a fixed-width
in bold to
xx
ABOUT THIS BOOK
hig light code that has changed from previous teps in the chapter, such as when a
new featur ad s to an existng line of code. In many case, the orignal os urce ode
has ben refomated; we’ve ad ed line bearks nd reworked indentaion to acommodateheavilb pagespaceinthebo k.Inraecs, vnthiswasnotenough,
and sltings include line-conti uation markes (
sourceodehaveoftnbenremovedfromthelitsngswhenthecodeisdecribdin
the tex. Code an otai ns acompany many of the listngs, highlighting importan
concept.s
➥). Additonaly, comments in the
liveBook discussion forum
Purchase of Spring ta Here includes fr aces to a private web forum run by Manni gPublicatonswheryoucanmakecommentsabouthebo k,astechnicalquestionas, drechiv lpfromthaue thoanr dfromothuer Tos. athces forumgo,
to hlivebotp/s: k.man ing.com/#! bo k/spring-starher/discuon
elarn more about Man ing’s forums and the rules of conduct at
.man ing.com/#! discuon
Man ing’s commitment o our eadrs i to provide a venue wher a meani gful
d i a l o g u e b e t w e n i n d i v u a l r e a d s a n d b e t we n r e a d s a n d t h e a u t h o r c a n t a k e
place. It is not a commitment o any specif amount of partic on on the part of
thaue thowhr, ocse ntributiontohfoe rumremainvos lun(atry dunpaidWe). suggest you try asking the author some chalenging questions let his nters ay! The
forum andthearchives ofprevious discuons wil be acsible from the publisher’s
websitealongasthebo kisnprint.
Yo. u canlso
.
hlivebtpo/s: k
abouther
L AURENŢIU SPILCĂ si a de icatd devol pment lead and trainer at
Endav, wher he leads the devlopment of projects in the fina cial market with user in Europe, the US, and Asia. He has over 10
years of exprince. Laurenţiu belivs it’s important to not only
delivr hig -quality software, but also share knowledg and help
otheros upskThil. ebs lhif adve rinhimtodesigna dtecah
course relatd to Jav technol gies and delvir presntaions and workshops. His
Twiterhandleis@laursplcai.
xxi
abouthecvrilsn
The figure on the cover of Spring Star Here is captioned “Femme d’ajcio isle de
Cowoaorse,” manfromAjacoi nthisla e dof CoThrsica. iluestraoknfris m
a coleti n of dres costumes from various countries by Jacques Graset de SaintSauve r (175–80), tiled Costumes´rnt de Pays,Dipfe ublished in France in 179.
Each ilustraion is fnely drawn and col red by hand. The rich variety of Graset de
Saint-Sauve r’scoleti nremindsusvidlyofhowcult raypartheworld’stowns
andregionswerejust20 yeargo.Is latedfromeachother,peoplespokedifernt
danilects dlanguInaes. thosrine thcoe untrysidwae,toidasy enwhtify er
theylivdandwhtaheir tradeorsita ni lfewasjutbyheirds.
Thwae ywedreshaschangedsincethena dthedivrstybegon,sorichathe
time, has fda e away. It is now hard to tel aprt the ni habitns of difernt contine alots,nde ifrntownregios, nos,cr untPries. hapwes htradve cult ra
diversty for a more varied personal life—certainly for a more varied and fast-pced
t e c h n o l gc ia f e .
At a time when it s hard to tel one computer bo k from another, Man ing celbrates the inve tivens and intaive of the computer busines with bo k covers
basedonthrice diversoty fg nal lifeotwocenturiageos b, roughbt oack libfe y
GrasetdSaint-Sauve r’spictures.
xxii
Part1
Fundamentals
A
ny budil ng stands on a foundation. A framework is no difernt in this
regad. In part 1, you’l learn to use the basic components that enable the
Spring framework. Thes components are the Spring contex and Spring
aspect. Further in the bo k, you’l discover that l Spring capbiltes rly on
thesntialcomponents.
Springthealword
This chapter covers
What a framework is
When to use and when to avoid using frameworks
What the Spring framework is
Using Spring in real-world scenarios
TheSpringframework(shortl,ySpring)isanap licatonframeworktha ispartof
theJavcosytem.Anaplictonfrmeworkisaetofc mmonsoftwarefunctionalthies pat rovidfoaesundationstruc foredevlopinag p licatonAn. ap licationframeworkeasthefort fwritnganap licatonbytakingouthefort f
writngaltheprogamcodefromscrath.
We use Spring in the devlopment of many kinds of ap licatons nowadys,
from large backend solutions to automation tesing ap s. According to many survey reports on Jav technol gies (like this one of JRebl from 20:
; or this one from JAXEnter:
mng.bz/N4V7
mostuedJavfrmeworkt day.
Spring is popular, nd devlopers have strd to use it more often with other
JVM languaes than Jav as wel. In the stla few years, we observd an impresiv
htp/:
hmtp/: ng.bz/DK9a
3
), Spring is the
4
CHAPTER 1
Spring in the real world
growth of devlopers using Spring with Kotlin (another ap reciatd languae from
theJVMfamily).Inthisbo k, we’lfocuson thefoundationsofSpring,andI’lteach
youesntialskforusingSpringinreal-worldexamples.Tomakethesubjectmore
comfobrta le for you and alow you to focus on Spring, we’l use only Jav exmples.
Throughouthebo k,we’ldsicuandap ,lywithexamples,ntialsk econnecting to a datbse, establihng communicaton betwen ap licatons, and securin ga n dte s in g a n a p .
Before divng into more tchnical details n the next chapters, l’ ak bout he
Spring framework and wher you’l actuly use it. Why is Spring so ap reciatd, and
whenshouldyouevnuseit?
In this chapter, we’l focus on what framework is, refing in partciul to the
Spring framework. In section 1., we discu the advntages of using a frmework. In
sectionwe1.2, discuthSpe rinecog sytmwith coe mpone yots unedtolearnto
get stared with Spring. Then I’l take you through posible usage of the Spring
framework—in particul, rea-world scenarios n section 1.3 In section 1.4, we’l discus when using frameworks might not be the right ap roach. You ned to understand al thes things about he Spring framework befor tying to use it. Otherwise,
youmightryouseahammertodgiyourgaden.
Depending on your lev, you might fel this chapter difcult. I might introduce
somneoti nhyosuat venh’teardbouant,hdaspmiiect ghdtisuyorbBuu. dton’t
worevy;noif udonu’t nderstandsomoe fthe ings owth, wiey bl cearifdlt
in the bo k. Sometimes, throughout he bo k, I’l ref to something said in earli
chapters.Iuethisap roachbecauslrningafrmewoklrieSpngdoesn’talways
linear uinopsferathgnso,dmetimyonueswatodmonyoit geul piecrs
of the puzle befor you se the complet picture. But in the nd, you’l get a cler
image,ndyou’lgethevalubleskiyounedtodevlopa pslikea rofesi nal.
1.1
Why should we use frameworks?
In this ecton, we discu frameworks. What re they? How di this concept ap ear,
and why? To be motivaed to use omething, you ned to know how tha something
brings you value. And that’s also the case with Spring. I’l teach you thes esntial
detailsbyharingtheknowledgIatherdfommyownexprinceandbystudying
andusingvariousframeworksinreal-worldscenarios,ncludingSpring.
Anap licatonframeworkaiset functionaliteos ntopofwhichwebuildap licatoi nThs. ape licatonframewoprk oviduesba rodoset f anls dfunctionailtes
tha you can use to build ap s. You don’t ned to use al the fatures the framework
ofers. Depending on the rquirements of the ap you make, you’l cho se the right
partsofheframeworkt use.
Here’s an anlogy I like for ap licaton frameworks. Did you evr buy a piec of
furnitufroe mDIa stoY ylSIiakre? ubuwaay rdobe—youwongae’t smbledwardobe, uthrige cot mponenyots unedtobuildant dmaa nuoal nhowto
asemble your piec of urniture. Now imagine you orde a wardobe, but instead
Why should we use frameworks?
5
of geting only the right components you ned, you get al the posible components
you can use to asemble any piec of urnitue:r a tble, a wardobe, and so n. If you
wanwaat rdobyoe, uhtoavefindthrige pt anrs dasembthle manliIkt’es. p lication framework. The ap licaton framework ofers you various piecs of software
you ned to build your ap . You ned to know what featurs to cho se and how to
asemblethemtoachievtherightesul(fig re1.)
Figure 1.1 David ordered a wardrobe from the UAssemble st ore. But the store (framework) doesn’t
deliver to David (t he programmer) just the components (soft ware capabilit ies) he needs t o build his new
wardrobe (the app). The st ore ships him all the possible part s he might need t o build t he wardrobe. It ’s
David’s (t he programmer’s) choice on which components (soft ware capabilit ies) are right and how to
assemble them to get t he right result (t he application).
The idea of a rmework isn’t new. Throughout he history f sotware devlopment,
progammeors bervdthcoey uldreups oartcf dthe y’dwriten multipae plications. Initaly, when not s manypa licatons were mi plementd,each ap licaton
was unique and devloped from scrath using a specif progamming languae.
When the software devlopment domain extnde , and more and more ap licatons
staredtobepublishedonthemarket,ibecameasir to bserv thatmanyofthes
ap shadsimilarequirements.Let’snameafwofthem:
Logingero,warning,andinfomesagehap eninevryap .
Mostap licatonsuetransctionstoprocesdatchanges.Transctionsrepsent an important mechanism that kes car of dat consitency. We’l discu
thisubjectindetailnchapter13.
6
CHAPTER 1
Spring in the real world
Most ap licatons use proteci n mechanisms aginst the same common
vulnerabilts.
Mostap licatonsueimilarwaystoc mmunicatewitheachother.
Most ap licatons use similar mechanisms to improve their perfomance, like
cahingordatcompresion.
And the list conti ues. It turns out tha the busines logic code implemented in an
ap is signifcantly smaler than the whels and belts tha make the engi e of the
ap licaton(also ftenrefdtoas“heplumbing”).
WhenIsay“busineslogic de,”Irf tohecodethaimplementshebusines
requiremenots hf ape licatonTh. cois dwhise imat plemenths ue xpsr’ ectaions
inanap licaton.Forexample,“cikngonaspeciflnkwilgeneratninvoice”s
something user xpect o hap en. Some code of the ap licaton you devlop implemenths fui nctionality, dthpis oartcf dwhise dat evlopthcalers businloes gic
codeHo. wevr,anyp takescrofvmol raespct:urli,oy gngd, atconsi te n cy,a n dso n (fig ur e1 .2)
Business logic code
Transactions
Security
Caching
Data transfer
Logging
Data persistence
Figure 1.2 The user’s perspect ive is like an iceberg. The users mainly observe the
result s of the business logic code, but this is only a small part of what builds the app’s
complete funct ionality. Like an iceberg has most of it underwater, in an ent erprise app
we don’t see most of the code because it ’s provided by dependencies.
Moreov, the busines logic code is what makes an ap licaton difernt from
anotherfomthefunctionalitypointofview.Ifyoutakewodiferntap s,ayridesharingsytemandasocilnetworkingap ,they avdiferntuseca.
NOTE
aridesharingap ,ausecai“rquestingacr.”Foranap managingfo d
delivry,auseci“ordeingapiz.”
You take difernt actions, but they both ned dat storing, dat transfer, loging,
security configuratons, proba ly cahing, and so on. Various ap licatons can reus
thnes onbusinmes plementaoi nthiIs. enfice torewthrie samfue nctoi nalitesvryme?Ofcoursenot:
Aucaserpnts threasonpa ersonutsehap .Foexrampinle,
The Spring ecosystem
Yousploaretimf ane dmonbeyrusinog methinrathg er andevloping
ityourself.
An existng implementaion tha many ap s alredy use has fewer chances to
introducebugs,aothershavetsdi.
You benfit from the advice of a community becaus you now have a lot of
devlopersunderstandinthg esamfeunctionalyoitIf. uhadimplementdyour
owncode,onlyafewpoe plewouldknowit.
A st ory of t ransit ion
One of the first applications I worked on was a huge system developed in Java. This
system was composed of multiple applications designed around an old-fashioned
architecture server, all of them written from scratch using Java SE. The development
of this application started with the language about 25 years ago. This was the main
reason for its shape. And almost no one could have imagined how big it would
become. At that time, more advanced concepts of system architectures didn’t exist,
and things in general worked differently from the individual systems due to the slow
internet connection.
But time passed, and years later, the app was more like a big ball of mud. For valid
reasons I won’t cover here, the team decided they had to go to a modern architecture.
This change implied first cleaning up the code, and one of the main steps was using
a framework. We decided to go with Spring. At that time, we had as an alternative
Java EE (now named Jakarta EE), but most members of the team considered it’s better to go with Spring, which offered a lighter alternative that was easier to implement
and that we also considered easier to maintain.
The transition wasn’t an easy one. Together with a few colleagues, experts in their
domain and knowledgeable about the application itself, we invested a lot of effort into
this transformation.
The result was amazing! We removed over 40% of the lines of code. This transition
was the first moment I understood how significant the impact of using a framework
could be.
NOTE
Cho sing and using a frmework is nl ked to the design and architec-
tureofanap licaton.You’lfinditusef ltoearnmoreabouthesubjects
aol nwig thlearni thg Spe rinfamg ewoInrk. ap endA,ix youfin’l da iscusion about software chitecurs with exclnt resources if you’d like to go
intodetails.
1.2
The Spring ecosystem
In this ecton, we wil discu Spring and relatd projects lik Sprni g Boot or Spring
Data. You’l learn al about thes in this bo k, and the links among them. In realworldcsenarioct’s, mmontoudse ifrnfamt eworks togehwher, earchfmeworkisdegnedtohelpyouimplementaspecif artofheap faster.
7
8
CHAPTER 1
Spring in the real world
WereftoSpringasfrmework,butismuchmorecomplex.Springisanecosytem of rameworks. Usualy, when devlopers f to the Spring framework, they
reftoaprtofhesoftwreacpbilteshatincludethfol wing:
1
2
3
4
SCpring oe —Onoethf ue ndamenptal orsSf rinthg inat cludfoes undational
capbiltes.Oneotfhefsatuhri eSprincgontexAs. you’learni detail
inchapth2,erSprincog nfuaistexndamencaptl boiltyhf Spe rinfamg ework that enables Spring to manage instances of your ap . Also, as part of
SprinCog oy re,ufindthSperinaspfug ect nctionAsality. phesct lpS ring tercepant dmanipumelate thody sudefineyouapr We. discumodore tailsf
the aspect in chapter 6. The Spring Expresion Languae (SpEL) is another
capbiltyou’lfindasprtofSpringCore,whichenablesyoutodescribonfiguratons for Spring using a specif languae. All of thes are new noti ns,
andI onexp’tyocuknowthemBuyet. sot nyou’l nderstandthSpa ring
CoreholdsthemechanismsSpringusetointegraintoy urap .
Spring model-viw-contrle (MVC) —The part of the Spring framework that
enables you to devlop web pa licatons that serv HTTP request. We’l use
Sprni gMVCstaringinchapter7.
Spring Data Aces —Also one of the fundamental parts of Spring. It provides
basic to ls you can use to con ect to SQL datbse to implement the persitencelayrof urap .We’luseSpringDataAccestaringi chapter13.
Spterinsg —Thpe hart oldinthg oe yls unedtowrfotesiyr uSpr ing
ap licaton.We’ldiscuthisubjectinchapter15.
You can intialy magine the Spring framework as solar sytem, wher Spring Core
repsnths iaenr thmie d whle, ich oldthas frme ewotrk geh(efirgu1.3)
Spring MVC
Spring Core
Spring testing
Spring Data Access
1.2.1
Discovering Spring Core: The foundation of Spring
SpringCoretishepartohf eSpringframeworkthaprovidetshefoundationalmechanisms to integra into ap s. Spring works based on the principle invrso f contrl
(IoCWh). enusinthg pis rncipnle, steadoalf winthg ape toc ntrohl excution,
we give control to some other piec of software—in our case, the Spring framework.
Through configuratons, we instruc the framework on how to manage the code we
Figure 1.3 You can imagine
t he Spring framework as a
solar system with t he Spring
Core in the center. The soft ware
capabilities are planet s around
Spring Core kept close t o it by
its gravit at ional field.
The Spring ecosystem
9
write, which defins the logic of the ap . Here’s wher the “inversion” in oI C comes
from:youdon’tle heap controlhexcutionbyitsowncodeandusedpendencies. Instead, we alow the framework (the depndency) to control the ap and its
code(figure1.4)
NOTE
In this contex the trm “contros”l refs to actions like “creating an
instance”or“alingamethod.”Aframeworkcancreatobjectsofheclas
you define in your ap . Based on the configuratons that you write, Spring
intercps the method to augment it with various featurs. For example,
Spring can intercp a specif method to log any ero that might ap ear
duringthemethod’sexcution.
Without IoC
The application executes
and controls (uses) the
dependencies it needs.
Dependency
Dependency
Dependency
Controls
Application
The application executes
being controlled by the
framework (dependency).
With IoC
Application
Controls
Framework (dependency)
Figure 1.4 Inversion of control. Instead of execut ing it s own code, which makes use of several ot her
dependencies, in case of an IoC scenario, the app execution is controlled by the dependency. The Spring
framework controls an app during its execution. Therefore, it implement s an IoC scenario of execut ion.
Youwilstareni gSpringwithSpringCorebydiscungtheSpringIoCfunctionality n chapters 2 through 5. The IoC container glues Spring components and compone ts of your ap licaton to the framework togehr. Using the IoC container, to
which you often ref as the Spring contex, you make certain objects known to
Spring,whichenablestheframeworkt usetheminthewayouconfigured.
In chapter 6, we’l continue our discuon with Spring aspect-orinted progamming(AOP).Springcancontrolinstancesad edtoisIoCcontainer,andoneofthe
things it can do is ntercp methods that repsnt he behavior of thes instances.
Thiscapbiltyscaedaspectinhg emethod.SpringAOPisoneofthemostcommon
wathframys e ewinowirkteacs hwhyouapt rdThoes. matrai s SpkesrinAOPg part
of the sntials wel. Part of the Spring Core, we also find resource management,
10
CHAPTER 1
Spring in the real world
internationalizton (i18n), type conversion, and SpEL. We’l encounter aspect of
thesfaturesinexamplesthroughouthebo k.
1.2.2
Using Spring Data Access feature to implement the app’s persistence
Fomor apst licatontocrials’,persit oahf de tha ey proWoces. rkinwig th
datbse is a fundamental subject, and in Spring, it’s the Data Acces module that
you’l use to take care of dat peristnce in many case. The Spring Data Acces
includesusing JDBC,integraingwithobject-rlainmaping (ORM)frameworkslie
Hibernate (don’t wory if you don’t ye know what n ORM frma ework is or haven’t
heard about Hibernate; we’l discu thes apects lar in the bo k), and managin
transctions. In chapters 12 through 14, we’l cover evrything ned to get you
staredwithSpringDataAcces.
1.2.3
The Spring MVC capabilities for developing web apps
The most common ap licatons devloped with Spring are web ap s, and within the
Springecosytm,you’lfindalrgestof oslthatenablesoy utowritewebap lications and web servic n difernt fashions. You can use the Spring MVC to devlop
ap s using a stndar servlt fahion, whhic is common in a vst number of ap licationstoday.Inchapter7,we’lgointomoredtailonusingtheSpringMVC.
1.2.4
The Spring testing feature
TheSpringtesingmoduleofrsualrgestof olsthatwe’lusetowriteuntina d
integraion tes. Ther have ben many pages writen about the tesing topic, but
we’l discu evrything that isential o get youstared with Spring tesingin chapter15.I’l asoref tos mevalublersourcesyounedtoreadtoge althedetails
of this topic. My rule of thumb is tha you’re not a mature devloper if you don’t
understandtesing,sothistopicsoneyoushouldcarebout.
1.2.5
Projects from the Spring ecosystem
The Spring ecosytm is o much more than just he capbiltes discued earli n
this ection. It includes a big coleti n of other fameworks that integra wel and
formularge nHeivers. were hpave roSplikejcts rnDag Spta, rinSecug prity, ng
Cloud, Spring Batch, Spring Boot, andso n. When you devlopan ap , youcanuse
moorethf pes rotjecs ghFer.oxampyloe, ucanbuildanp usinoalgSpf ring
BooSpt, rinSecug anrity, dSprinDag Inta. hne fwxt chapweters, wo’l orknsmaler
projethcs maat uke os varif ups rojects hf Spe rinecgosytmWh. enpsayI roject,
I ref to a part of the Spring ecosytm that is indepndently devloped. Each of
thes projects has epart em tha works on extnding its capblites. Also, ceah
project is epartly describd and has it own refnce on the Spring ofical webhspt/rins: g.io/projects
site:
Out of this vast univers creatd by Spring, we’l also ref to Spring Data and
SpringBoot.Thesprojectsaoftenencounterdinap s,oit’smportantogeto
knowthemfromthe begin ing.
.
The Spring ecosystem
EXTENDING THE PERSISTENCE CAPABILITIES WITH SPRING DATA
The Spring Data project implements a part of the Spring ecosytm tha enables you
to easily con ect o datbse and use the persitnce layr with a minimum number
oflinesofc dewriten.TheprojectfsobothSQLandNoSQLtechnol giesna d
creatshigh-levayr,whichsimplifesthewayouworkwithdatpersitnce.
WehSpave rinDag Acta whces, ichmoas duoleSpf rinCog anre, dwe
asol heav an indepndent project in the Spring ecosytm named Spring
Data. Spring Data Acces ontains fundamental dat ces implementaions
likethetransactionmechanismandJDBCto ls.SpringDataenhna cesa
todatbnse dobafers dosetrf whls, ichmadkes vlopmenmot re
acesiblndenablesyourap toc n ectodiferntkindsofdatsources.
We’ldiscuthisubjectinchapter14.
NOTE
SPRING BOOT
Spring Boot is a project part of the Sprni g ecosytm that introduces the concept of
“convention over configutraon.” The main idea of this concept is hat instead of settinug pthal coe nfiguratonofrsamewoyrk uSprself, inBog otyfers uda efult
configurtaonthyoatucnstomnas ediz Th. resuingthl,yois uaerl,write
les code becaus you fol w known convenoti ns and oy ur ap difers om others in
fewsmor waalinSoys.teawrdof thincoal eg fiuratonechfarspdevyit’s ,
more ficnt o star with a default configuraton and only change what’s difernt
fromtheconvention.We’ldiscumoreaboutSpringBootsaringnchapter7.
The Spring ecosytm is vast and contains many projects. Some of them you
encountermoreoftnthanothers,andsomeyoumaynotuseatlifyou’rebuildng
an ap licaton without a particul ned. In this bo k, we ref only to the projects
tha re sntial for you to get sared: Spring Core, Spring Data, nd Spring Boot.
YoucanfindafulistofprojectshatrepartoftheSpringecosytmontheofical
hspt/rins: g.io/projects/
Sprni gwebsite:
.
Alt ernatives for using Spring
We can’t really discuss alternatives to Spring because someone could misunderstand them as alternatives to the entire ecosystem. But for many of the individual
components and projects that create the Spring ecosystem, you can find other
options like other open source or commercial frameworks or libraries.
For example, let’s take the Spring IoC container. Years ago, the Java EE specification
was a solution very much appreciated by the developers. With a slightly different philosophy, Java EE (which in 2017 was open sourced and remade in Jakarta EE,
https://jakarta.ee/ ) offered specifications like Context and Dependency Injection
(CDI) or Enterprise Java Beans (EJB). You could use CDI or EJB to manage a context
of object instances and implement aspects (named “ interceptors” in the EE terminology). Also, throughout history, Google Guice (https://github.com/ google/ guice) was
an appreciated framework for the management of object instances in a container.
11
12
CHAPTER 1
Spring in the real world
(continued)
For some of the projects taken individually, you could find one or more alternatives.
For example, you could choose to use Apache Shiro (https://shiro.apache.org/ )
instead of Spring Security. Or you could decide to implement your web app using the
Play framework (https://www.playframework.com/ ) instead of Spring MVC and Springrelated technologies.
A more recent project that looks promising is Red Hat Quarkus. Quarkus is designed
for cloud native implementations and becomes more and more mature with rapid
steps. I wouldn’t be surprised to see it as one of the lead projects in developing enterprise apps in the Java ecosystem in the future (https://quarkus.io/ ).
My advice for you is to always take into consideration your alternatives. In software
development, you need to be open-minded and never trust one solution as being “ the
one.” You’ll always find scenarios in which a specific technology works better than
another.
1.3
Spring in real-world scenarios
Now that you have n overiw of Spring, you’re aware of when and why ou should
use a framework. In this section, I’l give you some ap licaton scenarios in whcih
usingtheSpringframeworkmightbeanelxcntfi.Too ften,I’vesndevlopers
onlyreftobackend ap licatonsforusingafrmeworklieSpring.I’vensena
trend of resticng, evn more, the scnario to backend web ap licatons. While t’s
truehatinplentyofcaseweseSpringusedinthisway,it’smportantoremember
tha the framework isn’t limited to this ensc ario. I’ve sen teams sucef ly using
Sprni g in difernt kinds of ap licatons, uch as the devlopment of an automation
tesingap orevninstandalonedsktopscenarios.
I’l further describ to you some common real-world scenarios in which I’ve sn
Spring usedsucef ly. Thes ar not he onlyposible scnarios, andSpringmight
not work al the time in thes case. Remember what we discued in section 1.2: a
framework is not always go d choice. But hes ar common case in which genralySpringisao dfit:
1
2
3
4
1.3.1
Thedvlopmentofabckendap
Thedvlopmentofanutomationtesingframework
Thedvlopmentofadesktopa p
Thedvlopmentofamobileap
Using Spring in the development of a backend app
Abackendap licatonisthepartof asytemthatexcutsonthesrvideandhas
the responsiblty of managin dat and sernvi g client ap cliatons’ request. The
user acs functionaitles by using the clint ap s directly. Further, the clint ap s
make request to the backend ap to work with the user’ dat. The backend ap
Spring in real-world scenarios
13
might use dtabse to s re dat or c mmunicate with other backend ap s in diferentfashions.
You can imagine, in a real-world scenario, tha the ap would be the backend
ap licaton managing the transactions in your bank acounts. Users may aces their
acounts and manage them via web ap licaton (onli e banking) or a mobile ap .
Both emobileap ans dthewebap srepntclientsforhbe ackndpa iclaton.
To manage user’ tansactions, the backend ap licaton neds to communicate with
other backend solutions, and part of the dat i manages neds to be persitd in a
datbse.Infigure1.5,youcanvisuzaelthearchitecurofsuchasytem.
Other backend solutions
make direct requests to
your backend app.
The users interact with the
client apps to manage their data.
Your backend app directly
communicates with other
backend solutions.
The client app make requests
to your backend app to resolve
users’ requests.
Your backend app uses a
message broker and adds
messages in a queue or topic.
Figure 1.5 A backend app interacts in several ways wit h other apps and uses dat abases to manage data.
Usually, a backend app is complex and may require the use of various technologies. Frameworks simplify t he
implement at ion by providing t ools you can use t o implement t he backend solut ion fast er.
Donwo’t yoifrudonu’t nderstandthal de otailsfgudI1.5re on’t
expct you to know what mesage broke is and not evn how to establih
the dat exchange among the components. What I want you to se is tha
such a sytem can become complex in the real world and then understna d
that projects from the Spring ecosytm were built o help you elimintae his
complexityasmuchaspoisble.
NOTE
Spring ofers an exclnt set of to ls for implementing backend ap licatons. It
makes your life asr with the difernt functionalites you generaly implement in a
backendsolution,fromintegraionwithother ap stopersitnceinvariousdatbse
technol gies. It’s no wonder devlopers often use Spring for such ap licatons. The
14
CHAPTER 1
Spring in the real world
framewobrk asicoly fer uevrythinyog unedinsuchimplementaionas danis
exclnt fi or any kind of architecuralstye.Figure 1.6 indicates he posiblte of
usingSpringforabckendap .
Use Spring Security to implement
the authentication and authorization
configurations.
Use the Spring IoCcontainer to
manage object instances easier
and glue in other functionalities
Spring provides.
Use Spring MVCor Spring WebFlux
to implement the REST endpoints
called by the client apps or other
backend solutions.
Use Spring Boot to ease the
complexity of your configurations
and write less code to implement
the app.
Use Spring Data to connect to
the SQL and NoSQL databases
your backend app uses to persist
the data.
Use Spring Integration or
Spring for Apache Kafka to
more easily send messages
to your JMS or Kafka topics.
Figure 1.6 The possibilit ies of using Spring in a backend applicat ion are endless, from exposing
functionalit ies that other applications can call t o managing t he dat abase access, and from securing
the applicat ion to managing integrat ion though third-part y message brokers.
1.3.2
Using Spring in a automation test app
Nowadywes, oftenuase tomationtesinfog enr d-toendtesinog sytfemwes implement. Automation tesing refs to implementing software that devlopment teams
usetomakesuranap laitconbehavesxpectd.Adevlopmenteamcanschedule the automation tesing implementaion to frequently es the ap and notify he
devlopers if something is wrong. Having such functionality vegis devlopers confidence becaus they know they’l be notifed if they break anything in the existng
capbiltesofheap whiledvopingnewfeaturs.
Whiwile thsmaslytemysoucandothestingmanualyit,’swagyos di etao
automatehetsca.Formorecomplexsytms,manualytesingaltheflowsin’t
evn an option. Because the flows are o numerous, it’d require a masive number of
hoursandto muchenrgytoc veritomplety.
Spring in real-world scenarios
tI urns out hat he most eficnt solution is to have separt em implement
anp tha sthersponsibltyofvaidtngalthefol wsofthetsdyem.While
devlopers ad new functionalites o the sytm, this teng ap is alo enhanced to
cowhver nat’s ewan, dtheamus tioe valdthe varythinstgwol dasrk ei .
The devlopers vntualy use an integraion to l and schedule the ap to run regularytogefdbackso nasposiblefortheirchanges(fiur1.7)
The team continuously adds new tests to
cover all the flows developed in the system.
Usually, the app is stored in a repository of
a version management system like Git.
GIT
A continuous integration tool like
Jenkins regularly runs all the tests.
TEST 1 passed
TEST 2 passed
TEST 3 failed
Jenkins
If a test is failing,
Jenkins notifies the team.
Figure 1.7 The team deploys t he test ing app in a t est environment . A cont inuous integrat ion tool
like Jenkins executes the app regularly and sends feedback t o t he t eam. This way, the t eam is
always aware of t he syst em’s st atus, and they know if t hey break somet hing during development .
Suchanap licatonmightbecomeascompxleas backendap .Inordetovalidte
thfloe wths, ape nedtos c mmunicawite th coe mpone ots hf sytemandevn
con ect to datbse. Sometimes the ap mocks extrnal depndencies to simutlea
difernt excution scenarios. For writng the tes scenarios, devlopers use frameworks lie Slnium, Cucumber, Gauge, and others. But, ogether with thes frameworks,theap couldstibenefitnsevrawal ysfromSpring’sto s.lForexample,the
ap couldmanthage obinject santocesmathke codmoe mare intai abule sinthg e
Spring IoC container. It could use Spring Data o connect o the datbse wher it
neds to validte he dat. I could send measge to que sor t pics of a broke sytem to simulate specif snarios or simply use Spring to cal some REST endpoints
(figuR1.8)re ememboit’ser,hfkay lois toks advncedme; ani wig bl careifd
asyouprogesthrought ebo k).
15
16
CHAPTER 1
Spring in the real world
The testing app may use
Spring MVCto simulate
calls from other systems.
The testing app may use
Spring Data to connect to
the SQL and NoSQL database
your backend app uses to
persist the data.
The testing app may use
Spring Integration to send
messages to queues or topics.
Figure 1.8 A test ing app might need to connect to dat abases or communicat e wit h ot her
syst ems or the test ed syst em. The developers can use component s of t he Spring ecosyst em
to simplify t he implement at ions of these functionalit ies.
1.3.3
Using Spring for the development of a desktop app
Today, esktopa plicatonsarenothatfrequentlydevoped,aswebormobileap s
havetkntherol finteracingwiththeusr.Howevr,ther’stilamalnumber
of desktop ap licatons, and components of the Spring ecosytm could be a go d
choicenthedvelopment oftheirfatures.Adesktopap couldsucef lyusethe
SprinIog Ccontainoer managthe objinect sa Thces. wais thy, ape im’s plementationcleais nr dimpromaitsve intainabAdityl. ditonthaly, pe couldpotentialy
uSpse rintog’s lsimplemendt ifernatufores,xamptolec mmunwiicate tha
backend or other compone ts (caling web servic or using other techniques for
remotecals) rimplementachingsolution.
1.3.4
Using Spring in mobile apps
With its Spring for Android project (
Sprincog mmunityresohelpthedvlopmentofmobailep licatonEvs. enthough
youl’proba lyrencounterhistuaon,it’sworthmentioni gthatyoucanuse
Sprintog’s ldevlopAndroidap Ths. Spis rnpg ropject rovidRESaes Tcienl fot r
Androidandauthenticaonsup ortf acesingsecurdAPI.s
hspt/rins: g.io/projects/pring-android
), the
When not to use frameworks
1.4
When not to use frameworks
In this section, we discu why you should sometimes avoid uins g frameworks. It’s
esntial you know when to use a framework and when to avoid using them. Sometimes, using a to l tha’s to much for the job might consume more nergy and also
obtain a worse ult. Imagine using a chainasw to cut bread. While you could try o
and evn achiev a fni al result, it’d be more difcult and enrgy-consuming than
using a reula knife (and you may end up with nothing but breadcumbs instead of
sliced bread). We’l dcisu a few scenarios in which usni g a frmework isn’t a gret
idea, nd then I’l te you a story about a tem I was part of that filed in the implementaionofanap becausofusingafrmework.
Iturnsoutha,likevrythingelsinsoftwaredvlopment,youshouldn’tap ly
framewoinrk cYaosel. ufin’l dsituaonis whichframewonisrk ogat dfit—
omar ybfarme ewoagrisk odfit,bunt otheSprinfgramework.Inwhichofthefollowingscenarioshouldyouconsidernotusingafrmework?
1
2
3
4
You ned to implement a particul functionality with a fo tprint as smal as
posible.Byfo tprint,Imeanthestoragmemory cupiedbytheap ’sfile.
Specif security requirements force you to implement only custom code in
yourap withoutmakinguseofanyopensourcefamework.
You’d have to make so many customizatons over the framework tha you’d
writemorecodethanifyou’dsimplynotusedital.
You alredy have functional p , and by changing it o use a frmework you
don’tgai anybenefit.
Let’sdicusthespointsi moredtail.
1.4.1
You need to have a small footprint
Forpointone,Irftosiuatonsinwhichyounedtomakeyourap licatonsmal.
Intoday’stems,wefindmoreandmorecasinwhichthesrvicadelivrdin
containYoers. uhlikey’v ardboucot ntainsuer, chDoas Kucker, bernoets,rher
termsrelatdothisubject(ifnot,agin,that’soky).
Containers thenir toasey pbic eyondthscoe pe othf bis o sok, f nr owthe
only thni g I ned you to know is that when you use uch a deployment sfahion, you
wanyot uapr licatontobsmae pasl osbi Ale. containblkesroinx whichyour
ap licaton lives. One cruial prni cple regading ap deployment in containers is
tha coe ntai sher ouldbeasiy posabthle: cany bde stroyedandrecat s
fast posible. The siz of the pa (fo tprint) maters a lot her. You can saev conds from the ap intialzon by making it smaler. That doesn’t mean you won’t
useframeworksf altheap sdepol yedincontaine.rs
But for some ap s, which are us aly also quite smal, it makes more sense to
imptrhoinve r italzona dmathfoke ir tprinsmt rathle r and indgepndencies to difernt frameworks. Such a cse i a kind of ap licaton caled serv-l
functio. Thes serv-l functions are tiny ap licatons deployed in containers.
17
18
CHAPTER 1
Spring in the real world
Becauysoe udonh’t aveo muchaetsohwae thy e’rdployedtloi, litkshe y
excutwithoutaserv(hencetheirname).Thesap snedtobesmal,ndthat’s
why,forthispecifasop s,you’lwantoav ida dingafrmeworkasmuchas
posibleBe. cauose itfz,’al posibthle yaot uwon’t edframewoarnk yway.
1.4.2
Security needs dictate custom code
I said in point wo tha in specif stuaions, ap s could not use frameworks becaus
of security requirements. This scenario us aly hap ens with ap s in the field of
defnse or governmental organizatons. Agnai , it dones ’t mean al the ap s used in
governmental organizatons are prohibted from using frameworks, but for some,
resticonapre s liedYo.umawoy ndwher Wey. ansyl,opensouframce ewoliker
Spring is used. If someone finds a specif vulnerabilty, wil become known, and a
hacker ould use this knowledg to exploit . Sometimes, takholders of such ap s
wantomasuke thr ce anoces f meonhe acking tohsytermi cloasitezr
asposible.Thiscouldleadtoevnrebuildngafunctionalitynsteadofusingitfrom
athird-partysource.
NOTE
Wait! Earlie I sad that i’s more scure to use an open source fame-
work becaus if a vulnerabilty exs, omeone wil ikey discover it. Wel, if
youinvest noughtimeandmoney, ouproba ly cnachiev thisyourselfa
wel. In genral, it’s cheapr to use a frmework, of course. And if you don’t
want to be extra cautious, it makes more sense to use a framework. But in
some projects, the stakeholders realy want to make sure no information
becomespublic.
1.4.3
Abundant existing customizations make a framework impractical
Another case (point thre) in which you might want to avoid using a framework is
whenyou’dhave tocustomizetscompone tso muchthatyouendupwritng more
code than if t hadn’t ben used. As I specifd in section 1., a frmework provides
you parts hat you asemble with your busines code to obtain an ap . Thes compone pts, rovide bthy frame ewodrk, onpfit’ erancly, dyounedtocustomthize m
indiferntways.It’perfctlynormalto customizetheframework’sc mponentsand
the style in which they asemble than if you’d devloped the functionality from
scrath. If you find yourself in such a situaon, you have proba ly chosen the wrong
framework(seachforaltenatives)ory ushouldn’tusefarmeworkatl.
1.4.4
You won’t benefit from switching to a framework
Inpoinfot umeIr, ntionedthpat otenmitial scotake uldbtryienog uframse ework
to replac something that lredy exist and is working in an ap . Sometimes we are
tempted to replac an existng architecur with something new. A new framework
ap eanrs, dpits’ opuanlr, devryonue soit, whshy ouldnwe’t chanoge uapr as
wetol uthse frami ewoYrk? ucanb, uyot unedtoaentiveanly zwhe yoat uwant
toachbievchy angi sogmethinthg woa nIrks. ommylikecas, stofry msection
What will you learn in this book
coitu1., ldbhe lpfutochl anyogeuapr andmaorelynitspkafmec ewoAsrk.
lonthascg i anbgerinaegs defit, oA! reasoncouldbthe yoa uwant tomathke
ap moremaintainable,morepformant,ormorescure.Butifhischangedoesn’t
bring you a benfit,and somtiemes it might evn bring incertiude, then, in the nd,
youmighdt iscoyver uinvestdhtime nae dmonfoeywoar resuLelt. met yotel u
astoryf mmyownexprince.
An avoidable mistake
Using frameworks isn’t always the best choice, and I had to learn that the hard way.
Years earlier, we were working on the backend of a web application. Times influence
many things, including software architectures. The app was using JDBC to directly
connect to an Oracle database. The code was quite ugly. Everywhere the app needed
to execute a query on the database it opened a statement and then sent a query that
was sometimes written on multiple rows. You might be young enough not to have
encountered JDBC direct usage in apps, but trust me, it’s a long and ugly code.
At that time, some frameworks using another methodology to work with the database
were becoming more and more popular. I remember when I first encountered Hibernate.
This is an ORM framework, which allows you to treat the tables and their relationships
in a database as objects and relationships among objects. When used correctly, it
enables you to write less code and more intuitive functionality. When misused, it may
slow down your app, make the code less intuitive, and even introduce bugs.
The application we were developing needed a change. We knew we could improve
that ugly JDBC code. In my mind, we could at least minimize the number of lines. This
change would have brought great benefits to maintainability. Together with other
developers, we suggested using a tool provided by Spring called JdbcTemplate
(you’ll learn this tool in chapter 12). But others strongly pushed the decision to use
Hibernate. It was quite popular, so why not to use it? (Actually it still is one of the
most popular frameworks of its kind, and you’ll learn about integrating it with Spring
in chapter 13.) I could see changing that code to a completely new methodology
would be a challenge. Moreover, I could see no benefits. The change also implied a
greater risk of introducing bugs.
Fortunately, the change started with a proof of concept. After a couple of months, lots
of effort, and stress, the team decided to quit.
After analyzing our options, we finished the implementation using JdbcTemplate. We
managed to write cleaner code by eliminating a large number of lines of code, and
we didn’t need to introduce any new framework for this change.
1.5
What will you learn in this book
Sinyoce uopendthbis o Iasuk, myoe up’re oba soly ftwdare vlopiner thJave
ecosytm who found out it’s usef l to learn Spring. The purpose of this bo k is to
te ac h yo u th e fo un d a tion s o f S p rin g , a s u m i n g yo u k n o w n o th in g a t l a b o u t fra m e works and, of course, about Spring. When I say Spring, I ref to the Spring ecosytem,notjushecorpatofheframework.
19
20
CHAPTER 1
Whenyoufinshthebo k,youwil havelrnedhowtodothefol wing:
UsetheSpringcontex andimplementaspectaroundobjectsmanagedbythe
framework.
Implement he mechanism of a Spring ap to con ect o a datbse and work
withtheprsitd at.
Establish dat exchange betwen ap s using REST APIs implemented with
Spring.
Buildbiacsp sthatuseheconve tion-overc nfiguraot nap roach.
Usebstpraciesnthestna dar clsdeignofaSpringap licaton.
ProperlytsourSpingimplementaions.
Summary
An ap licaton framework is a et of c mmon software funocti nalites hat provides a foundational struc re for devloping an ap licaton. A framework acts
astheskltaup ort buildanap licaton.
Aframeworkhelpsyoubuildanap moreficntlybprovidngfunctionality
tha you asemble to your implementaion instead of devloping it yourself.
Using a frmework save you time and helps ensure ther a fwer chances of
implementi gbugyfeat rs.
Usinwia g dknely ownframewSpolike rnogpenda osc lrgemta munity,
whichmamoitkes thlikeyroathwiers imfacesl ilar problemYos.uthenhave
anexclntop ortunityolearnabouthowothersolvdsomethingims ilarto
anisuyone dato whres, ichwispyoluarethime inofediv uresachl .
When implementi g an ap lictaon, alwyas think of al posiblte, including
notusingafrmework.fIyoudeci touse oneormorefameworks,taeinto
consideraton al their altnatives. You should think about he purpose of the
framework, who els i using it (how big the community s), and for how long
it’sbenonthemarket(maturiy).
Springisnotjust afrmework.Weoftenref toSprni gas“Springframework”
to indicate the core functionalites, but Spring ofers an entire ecosytm
formedomaf npy rojeucts dinap latioc ndevlopmenEat. chprojdecist icated to a specif domain, and when implementing an ap , you might use
more of thes projects o implement he functionality ou desir. The projects
oftheSpringecosytmwe’luseinthisbo karesfol ws:
– Spring Core, which builds the foundation of Spring and provides featurs
likethecontex,aspctandbasicdtes.
– Spring Data, which provides a high-lev, comfortable-ouse set of to ls to
implementheprsitncelayrof urap s.Youlfin’ dhoweasyitouse
SpringDataoworkwithbothSQLandNoSQLdatbse.
– SprinBog owht, ichpas rojecthf Spe rinecog sytmthat elpyos uap aly
“convention-overc nfiguraton”ap roach.
Spring in the real world
Summary
Quite often, learni g materials (like bo ks, artclies, or video tuorials) ofer
examples with Spring only for backend ap licatons. While it’s true that it’s
widesprda to use Spring with backend ap s, you can use Spring with other
kindos apf awes elv,ni desktopa plicatonas dautomationtesinagp s.
21
TheSpringcotx:
Defingbeas
This chapter covers
Understanding the need for Spring context
Adding new object instances to the Spring context
Inthischapter,youstarleni ghowtoworkwithacruialSprngframeworkelmenth: coe n(alsotex knownthas pe licatonconitex Spa rinapg Im). agine
the contex as place in the memory of your ap in which we ad al the object
instances that we want he framework to manage. By default, Spring doesnt’ know
any of the objects you define in your ap licaton. To enable Spring to se your
objects, you ned to ad them to the contex. Later in this bo k we discu using
diferntcapbiltesprovide bySpringinpa s.You’learnthatpluginginsuch
featurs is done through the contex by ad ing object instances and establihing
relationhs ipams onthg emSp. rinug thse instanices thcoe ntoexc n yoect ur
ap tovari ufs nctionaliteps rovidYeo.s u’learnthebasicofthemostimportantfeaurs(.g,tansctions,teing,etc.)hroughouthebo k.
22
Creating a Maven project
Learni whg Spat rincog nteaixs dhowwoit thriks fetpinlear intog use
Spring, becaus without knowing how to manage the Spring contex, almost nothing
els you’l earn to do with it wil be posible. The contex is a complex mechanism
that enables Spring to control instances you define. This way, it alows you to use the
capbiltesheframework fes.
Westarinthischapterbylani ghowtoad objectinstancestoheSpringcontex. In chapter 3, you’l eran how to fre to the instances you ad ed and establih
relatoi nhs ipsamongthem.
We’lnamethesobjectinstances“bans.”Ofcourse,fothesyntaxesyounedto
learnwe’lwritecodesnpi ets,andyoucanfindalthesnpi etsintheprojectsprovide with the bo k (you can download the projects from the “Bo k resources” tion of the live bo k). I’l enhance the code examples with visual and detail
explantionsoftheap roaches.
Because I want to make your introduction to Spring progesiv and take evrythinstepg bsteypin, thcis aptewer focuos nthsyne taxyoes unedtoknowfowor rking with the Spring contex. You’l find out later tha not al the objects of an ap
ned to be managed by Spring, so you dont’ ned to da al the object instances of
yourap toheSpringcontex.Forthemoment,Iinviteoy utof cusonlearni gthe
ap roachesforad inga instanceforSpingtomangea.
2.1
Creating a Maven project
In this ecton, we’l discu creating a Maven project. Maven is not a subject directly
relatd to Spring, but it’s a to l you use to easily manage an ap ’s build proces
regadlsofthferameworky u se.YounedtoknowMavenprojectbasiof low
the coding example.s Maven is also one of the most used buildng to ls for Spring
projectsinreal-worldscenarios(withGradle,anotherbuildto l,takingsecondplace,
buwet wond’t iscunt hbis o Bek). cauMase vensu’ chwea l-knownto yl, umay
alredy know how to creat project and ad depndencies to it using its configuration.Inthiscae,oy ucanskipthisectonandgodirectlyos n2.
Abuildto sil ftwweare utose buildap mos Yeoasirly. uconfigubareuildto l
to do the task tha are part of buildng the ap instead of manualy doing them.
Somexamplesoftakhatreofnprtaofbuildngtheap aresfol ws:
Downloadingthedpendenciesned byourap
Run ingtes
Validatngthahesyntaxfol wsrulethatyoudenfi
Checkingforsecuityv lnerabilts
Compilngtheap
Packgintheap ina excutablerchive
Sothaouerxampcalesnilmay nadge pendencies,wenedtoubsea uildto fol r
theprojectwes devlop.Thisectonteachesonwhly yatounedtoknowfodr evloping the xamples in this bo k; we’l go step by step through the proces of creating a
23
24
CHAPTER 2
The Spring context: Defining beans
Mavenproject,andI’lteachyouthesntialsregdingitsruct re.Ifyou’dliketo
learn more details bout using Maven, I recommend Introducig Maven: A Build Tol
forToday’sJvDeveloprsbyBalajiVaransi(APres,2019).
Let’s ar hevrybegin ing.First,awithdevlopinganyotherap ,youned
ani tegrad evlopment vironmen(IDt E)An. py rofesi nIDal Enowadoys fer
sup ort for Maven projects, o you can cho se any ou’d like: InteliJ IDEA, Eclipse,
SpringSTS,Netbeans, dso n.Forthisbo uk,I senteliJIDEA,whichst eIDEI
use most often. Don’t wory—the struc re of the Maven project is the same rgadlesofwhichIDEyoucho se.
Lestb’ar ceiynag ewprojeYct. unacret wprojinect I tferlioJ mF>lei
New>Project.This wilgetyoutoawindowliketheoneinfigure2.1
Here you see the JDK you’re using.
In this book, we’ll use Java 11, but
you can use any version above Java 11
to compile and run the projects.
To create a Maven project,
you select Maven from the
left panel.
Figure 2.1 Creat ing a new Maven project. Aft er going t o File > New > Project, you get to t his window,
where you need t o select t he t ype of t he project from the left panel. In our case, we choose Maven. In
the upper part of t he window, you select t he JDK you wish t o use t o compile and run t he project.
Once you’ve selctd the type of your project, in the next window (figure 2.) you
ned to give t a name. In ad iton to he project name and cho sing the locati n in
whichtos reit,foaMavenprojecty ucanlsopecifythefol wing:
AgroupID,whichweusetogr upmultiperladprojects
AnartifcID,whichist enameofthecurntap licaton
Aversion,whichisanidentiferohecurntimplementaionstae
Creating a Maven project
Optionally, you provide a group ID,
an artifact ID, and a version. If you
don’t configure these attributes,
your IDE will use default values.
You need to give a name to your
project and store it somewhere
in your computer.
Figure 2.2 Before you finish creat ing your project , you need to give it a name and specify where
you want your IDE to store t he project . Opt ionally, you can give your project a group ID, an artifact
ID, and a version. You then press the Finish but ton in the lower right corner t o complete creating
the project .
In a real-world ap , thes thre atributes ar esntial details, and it’s mportant o
providthe mBu. int oucarseb, uwese onwoly ork ntheortxicalmpleyos, ucan
omithemandleavyourIDEtofilnsomedfaultv esforthescharcteis.
Once you’ve creatd the project, you’l find its struc re lo ks like the one presented in figure 2.3 Again, the Maven por ject suct re does not depnd on the IDE
you cho se for devloping your projects. When you lo k first at your project, you
observtwomainthings:
The “src”folder (also known astheos urce folder),wheryou’l putevryhing
thabelongstoheap .
The pom.xml file, wher you write the configuratons of your Maven project,
likead ingnewdepndencies.
Mavenorganizesthe“src”folderintohefol wingfolders:
The “main” folder, wher you store the ap licaton’s ource ode. This folder
containstheJavcodeandtheconfiguroat nsepartlyintowodiferntsubfo lde rsn a m ed “ja v ” n d “re so u rce s.”
The “ts” folder, wher you store the unit es’ ource ode (we discu more
about nitesandhowtodefinetheminchapter15).
25
26
CHAPTER 2
The Spring context: Defining beans
All your source
code goes into
this folder.
The Java source code for your
app goes into this folder.
The source code
for your app goes
into this folder.
Other resources like properties
files or configuration files go
into this folder.
The source code
for the unit tests
goes into this folder.
You change the pom.xml file
to manage the Maven project
configuration.
Figure 2.3 How a Maven project is organized. Inside the src folder, we add everyt hing that belongs to
the app: t he application’s source code goes int o t he main folder, and t he source code for t he unit t est s
goes into t he test folder. In t he pom.xml file we writ e configurat ions for t he Maven project (in our
examples we’ll primarily use it t o define the dependencies).
Figure 2.4 shows you how to ad new source code to the “main/jav” folder of the
Mavenproject.Newclaseoftheap gointohisfolder.
Inside the “ java” folder you create your usual
Java packages and classes. Here, I’ve created
a package named “ main” and a new Main class
inside it.
Figure 2.4 Inside the “ java” folder, you creat e t he usual Java packages and classes of your
applicat ion. These are the classes that define t he whole logic of your app and make use of t he
dependencies you provide.
Creating a Maven project
Intheprojectswe creat in this bo k,weuesplenty of extrnaldepndencis:lbraies or frameworks we use to implement the functionality of the examples. To ad
thes depndencies to your Maven projects, we ned to change the conte of the
pom.xmfile.Inthefol winlgsting,youfindthedfaultconte ofthepom.xmfile
immediatelyfrcngtheMavenproject.
Listing 2.1
The default cont ent of the pom.xml file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>sq-ch2-ex1</artifactId>
<version>1.0-SNAPSHOT</version>
</project>
Withpis om.xmthfile, prodject osnu’tanse xry dal epndenyoIf uc. loink
theproject’sxnaldepndenciesfolder,youshouldonlysetheJDK(figure2.5)
Initially, inside the External Libraries
section of your project, you only have
the JDK. Once you add more dependencies
to your project, other files will appear
here, represented as external dependencies.
Figure 2.5 Wit h a default pom.xml file, your project only uses t he JDK as an external dependency.
One of the reasons you change the pom.xml file (and t he one we’ll use in this book) is to add new
dependencies your app needs.
27
28
CHAPTER 2
The Spring context: Defining beans
The fol wing listng shows you how to ad extrnal depndencies to your project.
You write al the depndencies betwen the
Each depndency is repsnted by a
wher you write the depndency’s atribute:s the depndency’s group ID, artifc
name, na d version. Maven wil search for the depndency b the values you provide
for thes thre atributes and wil download the depndencies from a reposit ry. I
won’t go into detail on how to configure a custom reposit ry. You just ned to be
awarethatMavenwildownloadthedpendencies(u alyjrfies)bydefaultroma
reposit ry named the Maven central. You can find the downloade jar files in your
project’s extrnaldepndenciesfolder,aspntedinfgui re2.6
Listing 2.2
<dependencies> </dependencies> tags.
<dependency> </dependency> group of tgas
Adding a new dependency in t he pom.xml file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>sq_ch2_ex1</artifactId>
<version>1.0-SNAPSHOT</version>
You need to write the dependencies for the
project between the < dependencies> and
< /dependecies> tags.
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
</dependencies>
</project>
Onceyou’vead edthedepndencyinthepom.xmlfie,aspresntedintheprevious
listng, the IDE downloads them, and you’l now find thes depndencies in the
“ExternalLibraies”folder(figue2.6)
Now we can move to the next section, wher we discu the basic of the Spring
contex. You’l creat Maven projects, and you’l learn to use a Spring depndency
n am e d
spring-context ,tomanagetheSpringcontex.
A dependency is represented
by a group of < dependency>
< /dependency> tags.
Adding new beans to the Spring context
29
Adding the Spring context dependency
adds multiple files as external dependencies.
Figure 2.6 When you add a new dependency t o t he pom.xml file, Maven downloads t he jar files represent ing
that dependency. You find t hese jar files in t he Ext ernal Libraries folder of t he project.
2.2
Adding new beans to the Spring context
Inthsiecton,you’learnhowtoad newobjectinstanc(esi.,bans)toheSpring
conYotex. ufinl’ douthyoat uhmuave ltipwae toysad beanis thSpe rincog ntex
such that Spring can manage them and plug featurs it provides into your ap .
Depending on the action, you’l cho se a specif way to ad the bean; we’l discu
whentoselc neoanr otheYor. ucand beanis thecontexinthefol wingways
(whic we’ldescriblatnthischapter):
Usingthe
Usingsteroypean otai ns
Progammaticaly
Let’s fir ceat project with a refnce to no framework—not evn Spring. We’l
then ad the depndencies ned to use the Spring contex and creat it (figure
2.7) This example wil serv a prequiste o ad ing beans to the Spring contex
examplesthatwer’egoingtoworok ni sections2.1through2.3
We creat Maevn project and define a sc.l Because it’ fun y to imagine, I’l
consideraclsnamed
the parot (lisng2.3) Remember,inthis chapter, weonlyfocusonad ing beansto
the Spring contex, so it’s okay to use any object hat helps you betr member the
@Bean an otai n
Parrot withonlya
String atributerpesntingthenameof
30
CHAPTER 2
The Spring context: Defining beans
What you want to achieve
We’ll start by independently creating an object
of the type Parrot and the Spring context.
Spring context
Figure 2.7
The Spring context is initially empty.
Later, we move the Parrot instance into
the context to let Spring know the instance
and be able to manage it for us.
To st art, we creat e an object inst ance and t he empt y Spring cont ext.
syntaxes. You find the code for this emxa ple in the project “sq-ch2-ex1” (you can
download the projects from the “Resources” tion of the liv bo k). For your project,youcanusethesamenameorcho setheoneyou pref.
Listing 2.3
The Parrot class
public class Parrot {
private String name;
// Omitted getters and setters
}
Youcannowdefineaclsontain gthemainmethodandcreatninstanceofthe
clas
Parrot ,asprentedinthefol winglistng.Ius alynamethiscla
Listing 2.4
Creat ing an inst ance of t he Parrot class
public class Main {
public static void main(String[] args) {
Parrot p = new Parrot();
}
}
no’sItwmi adnthoed pe noBepdutrnwee.cja sier’ uManis g nev ,
adlI’ thde pne densic ht epomm.x ps,alefi nr edt inthfoe l wni stlg .
Listing 2.5
Adding t he dependency for Spring cont ext
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
Main .
Adding new beans to the Spring context
31
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>sq-ch2-ex1</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
</dependencies>
</project>
A crital thing to observ is tha Spring is designed to be modular. By modular, I
mean that you don’t ned to ad the whole Spring to your ap when you use omething out of the Spring ecosytm. You just ned to ad those parts hat you use. For
this reason, in listng 2.5, you se that I’ve only ad ed the
dency, which instruc Maven to pul the ned depndencies for us to use the
Springcontex.Throughouthebo k,we’lad variousdepndenciesto urpojects
acordingtowhatweimplement,butwe’lawaysonlyad whatwened.
spring-context depn-
Youmighwot ndher owknI ewwhhic MavendepndenshIcy oulda d.
The truh is that I’ve used them so many times I know them by heart. Howevr, you don’t ned to memorize them. Whenver you work with a new
Springproject,y ucansearchforthedpendenciesyounedtoad directly
in the Spring refnce (
curent/ps ring-frameworke-fnce/ore.html
denciesarptofhe
NOTE
hdtp/ocs.: ring.io/spring-framework/docs/
). Generaly, Spring depnorg.springframework groupID.
With the depndency ad ed to our project, we can creat n instance of the Spring
contex. In the nextlisng, youcanse how I’ve changedthe main method to crea
theSpringcontexinstance.
Listing 2.6
Creat ing t he inst ance of t he Spring cont ext
public class Main {
public static void main(String[] args) {
var context =
new AnnotationConfigApplicationContext();
Parrot p = new Parrot();
}
}
Creates an instance of
the Spring context
32
CHAPTER 2
NOTE We use the
Spring contex instance. Spring ofers multipe implementaions. Because in
most case you’l use the
implementaionthuat sehmoust edtodapy’s roachan: otai ns)we, ’l
focusonthisoneinthisbo k.Also,I nlyteouwhatyounedtoknowfor
the curent discuon. If you’re just geting stared with Spring, my recommendation is to avoid geting into details with contex implementaions and
thes clase’ inheritance chains. Chansce are that if you do you’l get lost
withunimportantdeails insteadof cusingonthesntial things.
The Spring context: Defining beans
AnnotationConfigApplicationContext clasto crea the
AnnotationConfigApplicationContext clas (the
As presnted in figure 2.8, you creatd an instance of
tex depndencies to your project, and creatd an instance of the Spring contex.
Yourobjectivsoad the
Parrot , ad ed the Spring conParrot objectohecontex,whichst enxtsep.
What you did
What you want to achieve
You created a parrot instance,
but it’s not in the Spring context.
Spring context
Adding the parrot instance in
the Spring context will allow
Spring to “ see” the instance.
Spring context
You defined the Spring context,
but it’s now empty.
Figure 2.8 You creat ed t he Spring cont ext inst ance and a Parrot inst ance. Now, you want
to add t he Parrot inst ance inside t he Spring cont ext t o make Spring aware of t his inst ance.
We just finshed creating the prequiste (skelton) project, which we’l use in the
next scions to understand how to ad beansto he Springcontex. Insection 2.1,
we continue larni g how to ad the instance to the Spring contex using the
an otai n. Further, in sections 2. and 2.3, you’l also learn the alternatives of
ad inthg ine stanuce sinterog ypane otai nas d oinptgroammaAfticaly. ter
discungalthreap roachewes, ’lcompathre m,andyoul’earnthbe stcirumstancesforusingeach.
@Bean
Adding new beans to the Spring context
2.2.1
33
Using the @Bean annotation to add beans into the Spring context
Inthisecton,we’ldiscuad inganobjectinstancetoheSpringcontexusingthe
@Bean an otai n. This makes it posible for you to ad the instances of the clase
defined in your project (lik
yourself but you use in your ap . I beliv this ap roach is the asit o understand
whenstari oguRet. membther atsoeny ulearn toad beantohsSpe rincogntex is hat Spring can manage only the objesct hat re part of it. Frs, I’l give you a
straightforward example of how to ad a bean to the Spnri g contex using the
an otai nTh. shenI’l owyouhowatdo multipbeanothsmf e doerifntype.
The stp you ned to f low to ad a ben to he Spring contex using the
an otai naresfol ws(figure2.9):
1
2
3
Parrot in our case), wel as cle you di n’t crea
@Bean
@Bean
Defincoae nfiguratonclas( notaedwith
which,aswe’ldisculater,weusetoc nfigurethecontexofSpring.
Add a method to the configuraton clas tha retuns the object instance you
wantoad tohcoe natex dan othae methodwith e
MaSpkerniuthcogsenfiguratodnceflsi Asedinstp1.yoweulearnt,’
useconfiguratonclasetowritedfrentconfiguratonsfortheframework.
@Configurationfo) yr upr oject,
@Beanan otai n.
Lefolt’s wthseanpdthplyeminthpnroe jctam“sToqed-c2thx.” kealp
stepwediscuepartd,Irecommendyoucreatnewprojectsf rahexample.
NOTE
Remember, you can find the bo k’s projects in the “Resources” sec-
tionofthelivbo k.
Step 1
@Configuration
public class ProjectConfig {
Step 2
@Bean
Parrot parrot() {
var p = new Parrot();
p.setName("Koko");
return p;
}
}
Spring context
Step 3
var context = new AnnotationConfigApplicationContext(ProjectConfig.class);
Figure 2.9 St eps for adding the bean t o the cont ext using t he @Bean annot ation. By
adding the inst ance to t he Spring context , you make t he framework aware of the object,
enabling it to manage t he instance.
34
CHAPTER 2
NOTE
The Spring context: Defining beans
AconfiguratospincleSas nri apg lictaonthsweat use
toinstruSpc rintodg spactioefnFos.examr pwele, canSptel rintoce-g
ate beans or to enable crtain functionalites. You wil earn difernt hings
youcandefineinconfiguratonclsaethroughoutherstofhebo k.
STEP 1: DEFINING A CONFIGURATION CLASS IN YOUR PROJECT
The first ep is to creat configuraton clas in the project. A Spring configuraton
clasiharcteizdbythefact hatisn otaedwiththe
tion. We use the configuraton clase to defin various Spring-relatd configuratons
for the project.Throughouthe bo k,you’l earndifernt hings youcanconfigure
using the configuraton clase. For the moment we focus only on ad ing new
instancestoheSpringcontex.Thenextlisngshowsyouhowtodefinetheconfigurationclas.Inamedthisconfiguratonclas
Listing 2.7
@Configuration an ota-
ProjectConfig .
Defining a configurat ion class for the project
@Configuration
public class ProjectConfig {
}
NOTE
We use the @Configuration annotation to define
this class as a Spring configuration class.
I separt he clas into difernt packges to make the code asir
to understand. For example, I creat the configuraton clase in a packge
n am e d
config , and the
clase into packges is a go d practie; I recommend you fol w it in your
real-worldimplementaionsawel.
Main clas in a packge named
main . Organiz g the
STEP 2: CREATE A METHOD THAT RETURNS THE BEAN, AND ANNOTATE THE METHOD WITH @BEAN
Onoethf e inyogs ucandowithcoa nfiguratonadiscl beantoshSpe rincog ntex. To do this, we ned to define a method tha retuns the object instance we wish
toad tohcoe ntexandan otaehmeat thodwith e
Sprni g know that i neds to cal this method when it nitalzes contex and ad s
threunedvalutoehcoe nThtex. ne listx hg owths ce antogeshcoe nfigurationclastoimplementhecurntsep.
NOTE
@Bean an otai nwh, cihelts
For the projects in this bo k, I use Jav 1: the lates long-term sup-
portedvsoJia nMo. anre dmopre oadectsj ptinhg versionGe. neraly,theonlyspecifatureI sinthecodesnip etshatdoesn’tworkwith
an earli version of Jav is the
ther to make the code shorte and easir to read, but if you’d like to use an
earli vson of Jav (sy 8, for example), you can replac
inferdtype.Thisway,ou’lmaketheprojectsworkwithJav8swel.
Listing 2.8
var resvd type name. I use
var with the
Defining t he @Bean met hod
@Configuration
public class ProjectConfig {
@Bean
var her and
By adding the @Bean annotation, we instruct Spring
to call this method when at context initialization and
add the returned value to the context.
Adding new beans to the Spring context
35
Parrot parrot() {
Set a name for the parrot we’ll
var p = new Parrot();
use later when we test the app.
p.setName("Koko");
return p;
Spring adds to its context the Parrot
}
instance returned by the method.
}
Observ tha the name I used for the method doesn’t contain a verb. You proba ly
learnedthJabtv eps ractiopuvetrbins methodnambes cauthse methods
generaly presnt acions. But for methods we use to ad beans in the Spring contex, we don’t fol w this conve tion. Such methods repsnt the object instances
they rtun and tha wil now be part of the Spring contex. The method’s name also
becomestheban’sname(asinlistng2.8,theban’snameisnow“parot”).Byconvention,youcanusenouns,andmostofentheyhavethesamenameastheclas.
STEP 3: M AKE SPRING INITIALIZE ITS CONTEXT USING THE NEWLY CREATED CONFIGURATION CLASS
We’ve implementd a configuraton clas in which we tel Spring the object instance
tha neds to become a bean. Now we ned to make sure Spring use this configuration clas when intliazng its contex. The next lisng shows you how to change the
instantiaon of theSpring contex in themain clas touse theconfiguraton clas we
implementdinthefirstwostep.
Listing 2.9
Init ializing t he Spring cont ext based on t he defined configurat ion class
public class Main {
public static void main(String[] args) {
var context =
new AnnotationConfigApplicationContext(
ProjectConfig.class);
}
When creating the Spring context
instance, send the configuration class as
a parameter to instruct Spring to use it.
}
To verify the
instanceandprintisnameintheconsole,aprsentedinthefol winglsting.
Parrot instance is nde part of the contex now, you can ref to the
Listing 2.10
Referring t o t he Parrot inst ance from t he cont ext
public class Main {
public static void main(String[] args) {
var context =
new AnnotationConfigApplicationContext(
ProjectConfig.class);
Parrot p = context.getBean(Parrot.class);
System.out.println(p.getName());
}
}
Gets a reference of a bean of type
Parrot from the Spring context
36
CHAPTER 2
Now you’l se the name you gave to the parot you ad ed in the contex in the console,inmycase
The Spring context: Defining beans
Koko .
In real-world scenarios, we use unit and integraion tes to validte
tha our implementaions work as desir . The projects in this bo k implement unit tes to validte the discued behavior. Because this a “geting
stared”bo k,youmightnotyebawareofunites.Toavoidcreatngconfusion and alow you to focus on the discued subject, we won’t discu unit
tes until chapter 15. Howevr, if you alredy know how to write unit tes
and reading them helps you betr understand the subject, you can find al
theunitesmplementedinthetsfolderofachof urMavenprojects.If
you don’t yet know how unit est work, I recommend focusing only on the
discuedsubject.
NOTE
Asintheprviousexample,youcanad anykindof bjectoheSpringcontex(figure2.10)Let’salod a
String andan
Adding more beans of
different types into the
Spring context
Integer andsethati’sworking.
Spring context
Hello
Figure 2.10 You can add any
object t o the Spring context to
make Spring aware of it.
10
Thne listxnhg owyos uhowchI angedthcoe nfiguratontcolas d ba enof
type
String andabenoftype
Listing 2.11
Integer .
Adding t wo more beans t o t he cont ext
@Configuration
public class ProjectConfig {
@Bean
Parrot parrot() {
var p = new Parrot();
p.setName("Koko");
return p;
}
Adds the string “ Hello”
to the Spring context
@Bean
String hello() {
return "Hello";
}
Adding new beans to the Spring context
@Bean
Integer ten() {
return 10;
}
37
Adds the integer 10
to the Spring context
}
Remember the Spring contex’s purpose: we ad the instances we
expct Spring neds to manage. (This way, we plug in functionalites ofred
by the framework.) In a real-world ap , we won’t ad evry object to the
Spring contex. Staring with chapter 4, when our examples wil become
closer to code in a production-ready ap , we’l aols focus more on which
objects Spring neds to manage. For the moment, focus on the ap roaches
youcanusetoad beanstoheSpringcontex.
NOTE
Youcan owreftohetswonewbeanis thsaemewawey di with pe arotTh. e
nexlistnhg owyos uhowtochangthe mainmethodtoprinthenwbeanvlus’ e.
Listing 2.12
Print ing t he t wo new beans in t he console
public class Main {
public static void main(String[] args) {
var context = new AnnotationConfigApplicationContext(
ProjectConfig.class);
Parrot p = context.getBean(Parrot.class);
System.out.println(p.getName());
String s = context.getBean(String.class);
System.out.println(s);
Integer n = context.getBean(Integer.class);
System.out.println(n);
}
}
Run ing the ap now, the values of the thre banswil be printed in the console, a
sh o w n i th e n e xtc o de sn ip e t.
Koko
Hello
10
Thus far we ad ed one or more beans of dferint types to the Spring contex. But
couldwead morethanoneobjectofhesametyp(figure2.1)?Ifys,howcanwe
indiv ualyref tohes objects?Let’screa newproject,“sq-h2ex3,”todemonhstrae owyoucand multipbe anosthf same type othSpe rincog natex dhow
youcanreftohemafterward.
You don’t need to do any explicit
casting. Spring looks for a bean
of the type you requested in its
context. If such a bean doesn’t exist,
Spring will throw an exception.
38
CHAPTER 2
Adding more beans of
the same type into the
Spring context
The Spring context: Defining beans
Each instance has an
unique name (identifier).
You use the identifier later
to refer to the instance.
Spring context
parrot1
parrot2
parrot3
Figure 2.11 You can add more beans of the same t ype to t he Spring cont ext by using
multiple met hods annot ated with @Bean . Each instance will have a unique identifier. To refer
to t hem aft erward, you’ll need to use t he beans’ ident ifiers.
NOTE Don’t confuse the name of the bean with the name of the parot. In
ouexarmpthle, beans’ am(oes idr enitfers) hSpe rincog naretx
rot1 , parrot2 , na d
them).ThenamesIgav to heparots e
name is just an atribute of the
toSpring.
parparrot3 (like the name of the
You can declar s many instances of the same type as you wish by simply declaring
more methods an otaed with the
howI’ve declar thre bans oftpy e
examplewiththeproject“sq-h2-ex3.”
Listing 2.13
@Bean methods defin g
Koko , Miki ,and
Riki .Theparot
Parrot object, and it doesn’t mean anything
@Bean an otai n. The fol wing listng shows you
Parrot in the configuraton clas. You findthis
Adding multiple beans of t he same t ype t o t he Spring cont ext
@Configuration
public class ProjectConfig {
@Bean
Parrot parrot1() {
var p = new Parrot();
p.setName("Koko");
return p;
}
@Bean
Parrot parrot2() {
var p = new Parrot();
p.setName("Miki");
return p;
}
@Bean
Parrot parrot3() {
var p = new Parrot();
Adding new beans to the Spring context
39
p.setName("Riki");
return p;
}
}
Of course, you can’t ge the beans from the contex anymore by only specifyng the
type. If you do, you’l get an excption becaus Spring can ot gues which instance
you’ve declar you ref to. Look at the fol wing listng. Run ing such a code
throwans excptioni whichSprinytoelsg uthyoa unedtobpe rwhcis, ichts e
instanceyouwantouse.
Listing 2.14
Referring t o a Parrot inst ance by t ype
public class Main {
public static void main(String[] args) {
var context = new
AnnotationConfigApplicationContext(ProjectConfig.class);
Parrot p = context.getBean(Parrot.class);
System.out.println(p.getName());
}
You’ll get an exception on this line
because Spring cannot guess which
of the three Parrot instances you
refer to.
}
When run ing your ap licaton, you’l get an excption similar to he one presnted
bythenxtcodesnip et.
Exception in thread "main"
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No
qualifying bean of type 'main.Parrot' available: expected single matching
bean but found 3:
parrot1,parrot2,parrot3
Names of the Parrot
at …
beans in the context
Tosothlve amis bigutpy roblemyo, unedtopref tcoisly noe thf ine stancebs y
using the bean’s name. By default, Spring use the names of the methods an otaed
with
@Bean as the ban’s names themselv. Remember that’s why we don’t name the
@Bean methodsusingverbs.In ourcase,thebanshavethenames
parrot3 (remembther, methodrepsnthbe anYo). ucanfi dthnes ames
and
in the previous code snip et in the mesage of the excption. Did you spot them?
Let’s change the main method to ref to one of thes beans explicty by using its
name.ObservhowIrefdtohe
Listing 2.15
parrot1 , parrot2 ,
parrot2 beaninthefol winglistng.
Referring t o a bean by it s ident ifier
public class Main {
public static void main(String[] args) {
var context = new
40
CHAPTER 2
The Spring context: Defining beans
AnnotationConfigApplicationContext(ProjectConfig.class);
Parrot p = context.getBean("parrot2", Parrot.class);
System.out.println(p.getName());
}
First parameter is the
name of the instance
to which we refer
}
Run ing the ap now, you’l no longer get an excption. Instead, you’l se in the
co n so let h en a m e of th e s c o n d p ar ot,
Ifyou’dlitkeogvanothner ametoheban,youcanuesitheroneofthename
or the value atributes of the
changethenameofthebanin
Miki .
@Bean an otai n. Any of the fol wing syntaxes wil
"miki" :
@Bean(name = " miki " )
@Bean(value = " miki " )
@Bean( " miki " )
In the next code snip et, you can observ the change as it ap ears in code, and if
you’dliketorunthisexample,youfinditntheprojectnamed“sq-ch2-ex4”:
@Bean(name = "miki")
Parrot parrot2() {
var p = new Parrot();
p.setName("Miki");
return p;
}
Sets the name of the bean
Sets the name of the parrot
Defining a bean as primary
Earlier in this section we discussed that you could have multiple beans of the same
kind in the Spring context, but you need to refer to them using their names. There’s
another option when referring to beans in the context when you have more of the
same type.
When you have multiple beans of the same kind in the Spring context you can make
one of them primary. You mark the bean you want to be primary using the @Primary
annotation. A primary bean is the one Spring will choose if it has multiple options and
you don’t specify a name; the primary bean is simply Spring’s default choice. The next
code snippet shows you what the @Bean method annotated as primary looks like:
@Bean
@Primary
Parrot parrot2() {
var p = new Parrot();
p.setName("Miki");
return p;
}
Adding new beans to the Spring context
41
If you refer to a Parrot without specifying the name, Spring will now select Miki by
default. Of course, you can only define one bean of a type as primary. You find this
example implemented in the project “ sq-ch2-ex5.”
2.2.2
Using stereotype annotations to add beans to the Spring context
In this ecton, you’l earn a difernt ap roach for ad ing beans to the Spring contex (later in this chapter, we also compare the ap roaches and discu when to
cho se one or another). Remember, ad ing beans to the Spring contex is ential
becaus it’ how you make Sprni g aware of the object instances of your pa licaton,
which ned to be managed by the framework. Spring ofers you more ways to ad
beantosci nItex. difernsct arioys, ufin’l dusinog noethf apes roachise
more comfortable than another. For example, with steroype an otai ns, you’l
observyouwritelscodetoinstrucSpringtoad abentoisc ntex.
Later you’l learn tha Spnri g ofers multipe steroype an otai ns. But in this
section, I want you to focus on how to use a steroype an otai n in general. We’l
takehemostbaicofthes,
Withserotypean otai ns,youad thean otai nabotehv clafsorwhichyou
ned to have an instance in the Spring contex. When doing so, we say that you’ve
marked the clas a compone t. When the ap creats he Spnri g contex, Spring
creatsninstanceoftheclasyoumarkedas componentanda dsthatinstanceto
its contex. We’l stil have a configuraton clas when we use this ap roach to tel
Sprinwhg etor l ofk thr claesn otaedwithserotypane otai nMos. reov,
you can use both the ap roaches (using
we’lworkonthestypsofc mplexamplesinlaterchapters).
Thestpwenedtof lowintheprocesaf lows(figure2.1):
1
2
Let’s ake our example with the
the Spring contex by an otaing the
tions,ay
Using the
toad ani stancetois ntex(inourcase
Usni g
onwhertofindtheclasyoumarked.
@Component ,anduesitodemonstraeourexamples.
@Bean and steroype an otai ns togeher;
@Component an otai n, mark the clas for which you want Spring
Parrot ).
@ComponentScan an otai novetrhconfiguratonclas
, instrucSpring
Parrot clas. We can ad an instance of the clas in
Parrot clas with one of the stroype an ota-
@Component .
42
CHAPTER 2
The Spring context: Defining beans
STEP 1
@Component
public class Parrot {
// Omitted code
}
Tells Spring to add
an instance of this
class in its context
Tells Spring where to look
for classes annotated with
stereotype annotations
Spring context
STEP 2
@Configuration
@ComponentScan(basePackages = " main" )
public class ProjectConfig {
}
Figure 2.12 When using stereot ype annotat ions, consider t wo st eps. First , use t he st ereot ype
annotat ion ( @Component ) t o annotat e t he class for which you want Spring t o add a bean t o its
context . Second, use t he @ComponentScan annot at ion to t ell Spring where to look for classes
annotat ed wit h st ereot ype annot at ions.
Thne listx hg owyos uhowtouthse
Youcanfi dthisexampleintheproject“sq-h2-ex6.”
@Componentan otai nfothr e
Listing 2.16
Using a st ereot ype annot at ion for t he Parrot class
@Component
public class Parrot {
By using the @Component annotation
over the class, we instruct Spring to
create an instance of this class and add
it to its context.
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
But wait! This code won’t work just ye. By default, Spring doesn’t search for clase
an owitaed stheroanypeS thcorianswewo-,dlevjutofgsnads, ’t
btypoeanf
withsteroypean otai ns,weusethe
ratoi Alnclas. sowi, th e
thWeclase. enumthera pwhackges weer definedthwiclase thserotype
an otai nThs. nlitshexgowyohus owthuose
theconfiguratonclasoftheproject.Inmycase,thenamoe fthepackgis“main.”
ParrotancolsenToSpafrhitoednx.la sg
@ComponentScan an otai novertheconfigu@ComponentScanan otai nweSp, tel rinwhg tol erf k
@ComponentScanan otai nover
Parrotclas.
Adding new beans to the Spring context
Listing 2.17
43
Using t he @ComponentScan annot at ion t o t ell Spring where t o look
@Configuration
@ComponentScan(basePackages = "main")
public class ProjectConfig {
Using the basePackages attribute of the
annotation, we tell Spring where to look
for classes annotated with stereotype
annotations.
}
NowyoutoldSpringthefol wing:
1
2
Whichlasetod aninstancetois ntex(
Whertofindthecsla(using
Parrot )
@ComponentScan )
We don’t ned methods anymore to define the beans. And it now
lo ks lie this ap roach is betr becaus you achiev the same thing by writing les code. But wait until the end of this chapter. You’l learn tha both
ap roachesaruef l,depndingonthescnario.
NOTE
You can conti ue writng the main method as presnted in the fol wing listng to
provethatSpringcreatsnda dsthebanintscontex.
Listing 2.18
Defining t he main met hod t o t est t he Spring configurat ion
Prints the default String representation of
the instance taken from the Spring context
public class Main {
public static void main(String[] args) {
var context = new
AnnotationConfigApplicationContext(ProjectConfig.class);
Parrot p = context.getBean(Parrot.class);
System.out.println(p);
System.out.println(p.getName());
Prints null because we did
not assign any name to the
parrot instance added by
Spring in its context
}
}
Run ingthaisp licatonyo, u’ol bservSpingad eda
becaus the first value printed is the default
Howevr,thescondvalueprintedis
parot. Spring just crea he insta ce ofthe clas, but i’s l our duty if we want o
changethisnstanceinanywafyteraward(likeasgni gitanme).
Now tha we’ve coverd the two most frequently encounterd ways ou ad beans
toheSpringcontex,l’smakeashortc mparisonofthem(table2.1)
What youo’l bthiserv nat rel-worldscenarioys u’l steroypnae otai ns
asmuchasposible( causethsiap roachimpielswritnglescode),andyou’lonly
use the
@Bean when you can’t ad the ban otherwise (.g, you creat he ban for a
clas that is part of a libray so you can ot modify that clas to da the steroype
an ota i n).
Parrot instancetois ntex
String repsntaion of this instance.
null becauswedi notasignanynametohis
44
CHAPTER 2
The Spring context: Defining beans
Table 2.1 Advant ages and disadvantages: A comparison of t he t wo ways of adding beans t o t he Spring
context , which t ells you when you would use eit her of them
Using t he @Bean annot ation
Using stereotype annot ations
1 You have full control over the instance creation you
1 You only have control over the instance
add to the Spring context. It is your responsibility to
create and configure the instance in the body of the
method annotated with @Bean. Spring only takes
that instance and adds it to the context as-is.
2 You can use this method to add more instances of
the same type to the Spring context. Remember, in
section 2.1.1 we added three Parrot instances
into the Spring context.
3 You can use the @Bean annotation to add to the
Spring context any object instance. The class that
defines the instance doesn’t need to be defined in
your app. Remember, earlier we added a String
and an Integer to the Spring context.
4 You need to write a separate method for each bean
you create, which adds boilerplate code to your app.
For this reason, we prefer using @Bean as a second
option to stereotype annotations in our projects.
after the framework creates it.
2 This way, you can only add one instance of
the class to the context.
3 You can use stereotype annotations only to
create beans of the classes your application owns. For example, you couldn’t add a
bean of type String or Integer like we
did in section 2.1.1 with the @Bean annotation because you don’t own these classes
to change them by adding a stereotype
annotation.
4 Using stereotype annotations to add beans
to the Spring context doesn’t add boilerplate code to your app. You’ll prefer this
approach in general for the classes that
belong to your app.
Using @PostConstruct t o manage t he inst ance aft er it s creat ion
As we’ve discussed in this section, using stereotype annotations you instruct Spring
to create a bean and add it to its context. But, unlike using the @Bean annotation,
you don’t have full control over the instance creation. Using @Bean, we were able to
define a name for each of the Parrot instances we added to the Spring context, but
using @Component, we didn’t get a chance to do something after Spring called the
constructor of the Parrot class. What if we want to execute some instructions right
after Spring creates the bean? We can use the @PostConstruct annotation.
Spring borrows the @PostConstruct annotation from Java EE. We can also use this
annotation with Spring beans to specify a set of instructions Spring executes after
the bean creation. You just need to define a method in the component class and
annotate that method with @PostConstruct, which instructs Spring to call that
method after the constructor finishes its execution.
Let’s add to pom.xml the Maven dependency needed to use the @PostConstruct
annotation:
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
You don’t need to add this dependency if you use a Java version smaller than Java
11. Before Java 11, the Java EE dependencies were part of the JDK. With Java 11,
the JDK was cleaned of the APIs not related to SE, including the Java EE dependencies.
Adding new beans to the Spring context
If you wish to use functionalities that were part of the removed APIs (like @PostConstruct), you now need to explicitly add the dependency in your app.
Now you can define a method in the Parrot class, as presented in the next code
snippet:
@Component
public class Parrot {
private String name;
@PostConstruct
public void init() {
this.name = "Kiki";
}
// Omitted code
}
You find this example in the project “ sq-ch2-ex7.” If you now print the name of the
parrot in the console, you’ll observe the app prints the value Kiki in the console.
Very similarly, but less encountered in real-world apps, you can use an annotation
named @PreDestroy. With this annotation, you define a method that Spring calls immediately before closing and clearing the context. The @PreDestroy annotation is also
described in JSR-250 and borrowed by Spring. But generally I recommend developers
avoid using it and find a different approach to executing something before Spring clears
the context, mainly because you can expect Spring to fail to clear the context. Say
you defined something sensitive (like closing a database connection) in the @PreDestroy method; if Spring doesn’t call the method, you may get into big problems.
2.2.3
Programmatically adding beans to the Spring context
In this section, we discu ad ing beans progammaticaly to the Spring contex.
We’ve had the option of progammaticaly ad ing beans to the Spring contex with
Spring 5, which ofers gat flexibty becaus it enables you to ad new instances in
the contex directly by caling a method of the contex instance. You’d use this
ap roach when you want o implement a custom way of ad ing beans to the contex
a nd th e
@Bean or the stroype an otai ns are not enough for your neds. Say ou
nedtoregispcfibeansintheSprincgontexdpendingonspecifonfigurations of your ap licaton. With the
menmot ost hf scenariobs, uyot ucand’t os methinthlkeg codpe rsntedinthe
n ex tsn ip et:
if (condition) {
registerBean(b1);
} else {
registerBean(b2);
}
@Bean and steroype an otai ns, you can imple-
If the condition is true, add a
specific bean to the Spring context.
Otherwise, add another
bean to the Spring context.
45
46
CHAPTER 2
The Spring context: Defining beans
Tokepusingourpaotsexmple,thescnariosafol ws:Theap readsacoletion of parots. Some of them are gn; others a orange. You want he ap to ad
toheSpringcontexonlytheparotshatregn(figure2.13)
From a collection of parrots,
you want to add only those
that are green to the Spring
context.
Spring context
for (Parrot p : parrots) {
if (parrot.isGreen()) {
context.registerBean(...);
}
}
Using the registerBean() method
you can write custom logic to
add the desired instances to the
Spring context.
Figure 2.13
Using the registerBean() met hod to add specific object instances to t he Spring context
Let’s e how this method works. To ad a bean to the Spring contex using a programmaticap roach,you justnedtocalhe
cationContext instance. The
th e n e xt co de sn ip et:
registerBean() methodofthe
registerBean() has four parmetrs, as presnted in
Appli-
<T> void registerBean(
String beanName,
Class<T> beanClass,
Supplier<T> supplier,
BeanDefinitionCustomizer... customizers);
1
2
3
Usethefirstparmetr
beanName to defin anamefortheban you ad in the
Sprincog nytoeIxf. udon’t edtonagive mtoe hbe anyoua’dre inyog, u
canuse
null asvluewhenyoucalthemethod.
Thescondparmetrisheclasthatdefinesthebanyouad tohecontex.
Say ou want o ad an instance of the clas
Parrot ; the value you give to this
parmetris
Parrot.class.
The third parmetr is an instance of
Supplier . The implementaion of this
Supplier neds to retun the value of the instance you ad to the contex.
Remember,
Supplier is a functional interfac you find in the
.function packge. The purpose of a sup lier implementaion is to retun a
valueyoudefinewithoutakingparmetrs.
java.util
Adding new beans to the Spring context
4
The fourth and last parmetr is a vrgs of
thdisoenu’t nfadmthoilar,ky;’se
interfacyouimplementoc nfigurediferntcharcteisofheban;e.g,
makinpt grimary.
entirely,o ucangivetmorevalusoftype
47
BeanDefinitionCustomizer. (If
BeanDefinitionCustomizerjuanist
)Beindg efintypvargsoed,ucanomthi ps armetr
BeanDefinitionCustomizer .
In the project “sq-ch2ex8,” you find an example of using the
method. You observ that his project’s onfiguraton clas i empty, and the
clasweusefor urbeandefintonexampleisjutaplinoldJavobject(POJO);we
unse oan otai nwithIin. thne coxt dsne ip eyot, ufindthcoe nfiguratonascl
Idefineditforhisexample:
registerBean()
Parrot
@Configuration
public class ProjectConfig {
}
Id efin e dth e clas
Parrot thaweusetocraheban:
public class Parrot {
private String name;
// Omitted getters and setters
}
In the main method of the project, I’v used the
instanoypcef
main method. Figure 2.14 focuse on the syntax for caling the
method.
Listing 2.19
registerBean() method to ad an
ParrottohSpe rincognThtex. ne listx pg resnths coedthf e
registerBean()
Using t he registerBean() met hod t o add a bean t o t he Spring cont ext
public class Main {
public static void main(String[] args) {
var context =
new AnnotationConfigApplicationContext(
ProjectConfig.class);
Parrot x = new Parrot();
x.setName("Kiki");
We create the instance we want
to add to the Spring context.
Supplier<Parrot> parrotSupplier = () -> x;
context.registerBean("parrot1",
Parrot.class, parrotSupplier);
We call the registerBean() method to add
the instance to the Spring context.
Parrot p = context.getBean(Parrot.class);
System.out.println(p.getName());
}
}
We define a Supplier to
return this instance.
To verify the bean is now in the
context, we refer to the parrot bean
and print its name in the console.
48
CHAPTER 2
The Spring context: Defining beans
The type of the bean
context.registerBean("parrot1", Parrot.class, parrotSupplier);
The ApplicationContext instance
representing the Spring context
The name we give to the
bean that we add to
the Spring context
The Supplier returning the
object instance that we add
to the Spring context
Figure 2.14 Calling the registerBean() method t o add a bean t o t he Spring
context programmat ically
Use one or more bean configurato instances as the last parmetrs to set difernt
charcteis ofthebansyouad .For example,youcanmakethebanprimaryb
changing the
marybeandefinestheinstanceSpringselctbydefaultifyouhavemultipebansof
thesametypinthecontex:
registerBean() method cal, s hown in the next code snip et. A pri-
context.registerBean("parrot1",
Parrot.class,
parrotSupplier,
bc -> bc.setPrimary(true));
You’ve just made a first bg step into he Spring wodrl . Learni g how to ad beans to
the Spring contex might not sem like much, but i’s more important han it lo ks.
With this kl, you can now proced to freing to the beans in the Spring contex,
whichwediscunchapter3.
NOTE
Inthisbo k,weuseonlymodernconfiguratonap roaches.Howevr,
I find it esntial for you also to be aware of how the devlopers configured
thframe ewoinrk thedarly os Spf rinAtg. thiamwee, weure sinXML
g to
writehecos nfiguratons.Inap endixB,ashoertxampisle rovide togive
youfelainog nhowyouwoulduXML
se toad ba entohSpe rincog ntex.
Summary
Thefirsthinyog unedtolearni Sprinsgad ingobjecitnstanc(ews hichwe
cal beans) to the Spring contex. You can imagine the Spring contex as a
bucketinwhichyouad theinstancesyouexpctSpringtobea ltomanage.
Springcanseonlytheinstancesyouad toisc ntex.
Summary
Youcand beanstoheSpringcontexinthreways:uingthe
tion,usingsteroypean otai ns,and oingitprogammaticaly.
– Using the
@Bean an otai n to ad instances to the Spring contex nables
youtoad anykindof bjectinstanceas benandevnmultipeinstances
of the same kind to the Spring conext. From this point of view, this
ap roachismoreflxibthanusingsteroypean otai ns.Stil,requires
you to write more code bcaue s you ned to write a separt method in the
configuratonclasforehindepndentinstancead edtohecontex.
– Using steroype an otai ns, you can creat beans for only the ap licaton
clase with a specif an otai n (e.g,
ap roach requires writng les code, which makes your configuraton more
comfortable to read. You’l pref this ap roach over the
forclasethatyoudefineandcan notae.
– Using the
registerBean() method enba les you to implement custom logic
for ad ing beans to the Spring contex. Remember, you can ues this
ap roachonlywithSpring5andlater.
49
@Bean an ota-
@Component ). This configuraton
@Bean an otai n
TheSpringcotx:
Wiringbeas
This chapter covers
Establishing relationships among beans
Using dependency injection
Accessing the beans from the Spring context
through dependency injection
Inchapwe2,ter discuedthSpe rincog nthex: pinlace thape me’s mowhry er
wead thoe binjct sa weces wanSpt rintogmanBeage. cauSpse rinug thse IoC
principle,aswe discuedin chapter 1,wened to el Springwhichobjects of ur
ap nit edtos controSpl. nri g edcos ntrol sver moe thf oe bjoects f uapr to
augment hem with the capblites provides. In chapter 2, you learned multipe
ways to ad object instances to the Spring contex. You also learned that we ad
thesintsances(bans)intoheSpringcontexomakeSpringawareofthem.
In this chapter, we discu how to aces the beans, which we’ve ad ed to the
Spring contex. In chapter 2, we used the
instance directly o aces the beans. But ni ap s, we ned to ref om one bean
toanotherinstraightforwardfshion—bytelinSgpringtoprovidearfntceo
getBean() method of the contex
50
Implementing relationships among beans defined in the configuration file
an instance from its contex wher we ned it. This way, we establih relationships
amongthebans(onebanwilhave rfncetoanothertodelgatcs whenit
neds).Asyouproba lyredknow,ofteni anyobject-orintedprogamminglanguae,nobjenct edtos delgastpcifre onsiblteo therswhenimplementing their behavior, so you ned to know how to esbta lih such relationships among
objectswhenyou seSpringasfrmeworksawel.
Youlearn’ youhmoave ware yos ucanthes obyojects uad edtohSpe rni g
contex, andwe’l studyeachwithexamples, viuals, nd,ofc user,codesnip ets.At
the nd of this chapter, you’l have the need skil to use the Spring contex and
configure bena s na d relationships among them. This kl is the foundation of using
Springyo; uwonfi’t danSyprinapg inwhichyouwouldna’pt thly aep roachwees
discu in thischpa ter.Forthis reoa n,evrythinginthis bo k (and evrythingyou’l
learn from any other bo k, article or video tuorials) e on properly understandingtheap roacheswediscunchapters2hrough5.
In chapter 2, you learned to use the
contex. In section 3.1, we star by implementi g a relationship betwen two beans
youd’l efine thcoe nfiguratonbclas uy sinthg e
twowaysoucanestablihtherlationshipsamongbeans:
51
@Bean an otai n to ad beans in the Spring
@Beanan otai nHe. were discu
Link the beans by directly caling the methods that creat them (whic we’l
calwirng).
EnableSpringtoprovideusavl eusingamethodparmetr(whichwe’lca
auto-wirng).
Then, in section 3.2, we discu a third ap roach, which is a technique sup orted by
the IoC principle: depncy injecto (DI). We’l discu how to use DI in Spring,
a p lyin g th e
beans (which is also an example of auto-wirng). You’l use both thes ap roaches
togeherinreal-worldprojects.
@Autowired an otai n to implement the relationship betwen two
You might hink that he xamples in chapters 2 and 3 are not close
enough to the production code. In the nd, real p s don’t manage parots
andpersonBus! waIt ntosamr o thwily th moe straightforwardexmples and make sure you focus on thes ntial syntaxe,s which oy u’l use in
virtuSpeayl rinapg Th. wais maIy, suke yor upropuerly nderstandhow
thediscuedap roachesworkandfocuos nlyonthem.Staring chapter4,
ourclasdeignwilbecomeclosrt whatyou’lfindni real-worldprojects.
NOTE
3.1
Implementing relationships among beans defined
in the configuration file
In this section, you wil learn to implement the relationship betwen two beans
defined in the configurtaon clas an otaing methods with the
You’l often encounter his ap roach for establihing the rlationships among beans
usinthg Spe rincog nfiguratonI. chapwe2,ter discuedthwea uthse
taionto ad beansto heSpringcontex inthecasinwhichwecan otchangethe
@Bean an otai n.
@Bean an o-
52
CHAPTER 3
The Spring context: Wiring beans
clasforwhichwewantoad theban,forexample,iftheclasipartoftheJDKor
another depndency. And to etsablih relationships among thes beans, you ned to
learn the ap roaches we discu in this section. We’l dsciu how thes ap roaches
work, I’l give you the step you ned to implement he relationships among beans,
andthenwe’lap lythestpwithsmalcodeprojects.
weSay htwave oinstanices thSpe rincog npatex:ront dpa ersonWe. creat’l
and ad thes instances to the contex. We want o make the person own the parot.
Inotherword,swenedtolinkthetwoinsta ces.Thistraghtforwradexmplehelps
uds icuths we oap roachfoes linr k thg be anis thSpe rincog nwitex thouadt ing un ecsary complexity and enables you to focus on the Spring configuratons
o n ly.
So, for each of the two ap roaches (wirng and auto-wirng), we have two step
(figure3.1):
1
2
Addthpe rsona dparobt eantos hSpe rincog nyo(teasx uelarnedinchpa te r2 ).
Establishareltionshipbetwentheprsona dtheparot.
STEP 1:
In the Spring context
you add a parrot and
a person as beans.
Spring context
STEP 2:
You make the person
own the parrot.
Spring context
Figure 3.1 Having t wo beans in the Spring context , we want to establish a relat ionship bet ween
them. We do t his so that one object can then delegat e t o the ot her in the implement at ion of their
responsibilities. You can do t his using a wiring approach, which implies direct ly calling t he met hods
that declare the beans to est ablish t he link between them, or through aut o-wiring. You use t he
framework’s dependency inject ion capabilit ies.
Fgiure3.2psentshe“has-A”relationshipbetwentheprsonandtheparot bject
in a more technical way than figure 3.1
Beforde ivnig toeiherothf ape roachlest,’wiar th efixarstmpole thf is
chapter (“sq-ch3-ex1”) to remember how to ad the beans into the Spring contex
using methods an otaed with
tion 2.1 (step 1). We’l ad a parot ni sta ce and a person instance. Once we have
@Bean intheconfiguratonclas,wediscuedinsec-
Implementing relationships among beans defined in the configuration file
53
A person has a parrot.
Person
- name
- parrot
thpis roejctadwey, chantoige sabliht relationshipbetwenthwe oinstances
(step 2). In section 3.1, we implement wiring, and in section 3.12, we implement
auto-wirng for
wead thedpendencyforSpingcontexasyoufinditnhenextcodesnip et:
Figure 3.2 Implementing the
relat ionship between t he beans. This
is a simplified diagram representing
t he “ has-A” relat ionship between t he
Person and t he Parrot object s.
We’ll implement this relat ionship
t hrough wiring and aut o-wiring.
Parrot
- name
@Bean an otaed methods. In the pom.xml fie of the Maven project,
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
We then define a cls to describ the
Inthenextcodesnip et,youfindthedfintonofthe
Parrot object and one to describ the
Person .
Parrot clas:
public class Parrot {
private String name;
// Omitted getters and setters
@Override
public String toString() {
return "Parrot : " + name;
}
}
Inthenextcodesnip et,youfindthedfintonofthe
public class Person {
private String name;
private Parrot parrot;
// Omitted getters and setters
}
Person clas:
54
CHAPTER 3
The Spring context: Wiring beans
The fol wing stling shows you how to define the two beans using the
tioni theconfiguratonacls.
Listing 3.1
@Bean an ota-
Defining t he Person and t he Parrot beans
@Configuration
public class ProjectConfig {
@Bean
public Parrot parrot() {
Parrot p = new Parrot();
p.setName("Koko");
return p;
}
@Bean
public Person person() {
Person p = new Person();
p.setName("Ella");
return p;
}
}
You can now write a
thetwoinstancesarn’tyelinkedto nea other.
Main clas, presnted in the fol wing listng, and check tha
Listing 3.2
The definit ion of t he Main class
Creates an instance of the Spring context
based on the configuration class
public class Main {
public static void main(String[] args) {
var context = new AnnotationConfigApplicationContext
(ProjectConfig.class);
Person person =
context.getBean(Person.class);
Gets a reference to the Person
bean from the Spring context
Parrot parrot =
context.getBean(Parrot.class);
Gets a reference to the Parrot
bean from the Spring context
System.out.println(
"Person's name: " + person.getName());
Prints the person’s name to prove that
the Person bean is in the context
System.out.println(
"Parrot's name: " + parrot.getName());
Prints the parrot’s name to prove that
the Parrot bean is in the context
System.out.println(
"Person's parrot: " + person.getParrot());
}}
Prints the person’s parrot
to prove that there’s not yet
a relationship between the
instances
Implementing relationships among beans defined in the configuration file
Whenrun inthg apis yo, ucase’lnsole utpusimt toilarhoe npe rsntedinthe
n ex tc o de sn ip et:
The Person bean is in the Spring context.
Person's name: Ella
Parrot's name: Koko
Person's parrot: null
55
The Parrot bean is in
the Spring context.
The relationship between the person
and the parrot isn’t established.
The most important thing to observ her is that the person’s parot (third output
line) is
null . Both the person and the parot instances ar in the contex, howevr.
Thisoutputis
null ,whichmeansther’s notye arlionshipbetwentheinstances
(figure3.)
Spring context
The person doesn’t yet
own the parrot.
The two beans are in the context,
but no link has been established
between them.
Figure 3.3 We added the
t wo beans in t he cont ext t o
configure the relat ionship
bet ween t hem furt her.
3.1.1
Wiring the beans using a direct method call between the @Bean methods
Inthis ecton,weestablihthertiola nshipbetwenthetwo instances of
Parrot . The first way (wirng) to achiev this to cal one method from another in
the configuraton clas. You’l find this often used becaus it’s a straightforward
ap roach.Inthenextlisng,youfindthesmlachangeIhadtomakeinmyconfiguration clas to establih a link betwen the person and the parot (se figure 3.4) To
kepalthestp separt ndhelpyoueasirunderstandthe code,Ihave lsoeparatedhischangeinasecondproject:“sq-h3-ex2.”
Listing 3.3
Making a link bet ween the beans wit h a direct met hod call
@Configuration
public class ProjectConfig {
@Bean
public Parrot parrot() {
Parrot p = new Parrot();
p.setName("Koko");
return p;
}
@Bean
public Person person() {
Person p = new Person();
Person and
56
CHAPTER 3
The Spring context: Wiring beans
p.setName("Ella");
p.setParrot(parrot());
return p;
}
Setting the reference of the parrot
bean to the person’s parrot attribute
}
Run ing the same ap , you’l observ the output changed in the consoel. Now you
find(se nextsnip et) hathescondlineshowsthatElla(thepersonintheSpring
contex)ownsKoko(thepaor tintheSpringcontex):
Person's name: Ella
Person's parrot: Parrot : Koko
@Configuration
public class ProjectConfig {
@Bean
public Parrot parrot() {
Parrot p = new Parrot();
p.setName("Koko");
return p;
}
We now observe the relationship between the
person and the parrot has been established.
We define the relationship between
the person bean and the parrot bean
by directly calling the method that
returns the bean we want to set.
Spring context
@Bean
public Person person() {
Person p = new Person();
p.setName("Ella");
p.setParrot(parrot());
return p;
}
}
The result is the has-A relationship
between the two beans. The person
has-A (owns) the parrot.
Figure 3.4 We establish t he relationship bet ween t he beans using direct wiring. This
approach implies calling t he met hod t hat returns t he bean you want t o set direct ly. You need
to call this method from the one t hat defines t he bean for which you set t he dependency.
WhentachIver apis roachinkIclas, owsomhe tav qe uestiond: oesnth’ is
meanthwea crtwea oinstanoces f
and ad s into its contex and another one when the
parrot() method? No, we actuly have only one parot instance in
direct al o the
thisap licatonoveral.
It might lo k strange at first, but Spring is smart enough to understand that by caling the
parrot() method, you want o ref to the parot bean in its contex. When
weusethe
@Bean an otai ntodefinebansinto heSpringcontex,Springcontrols
how the methods rae caled and can ap ly logic above the method cal (you’l leran
more about how Spring intercps methods in chapter 6). For the moment, remember that when the
person() method cals the
logic, as describd next.
Parrot(figu3.5)—
re onie stanSpce rincetasg
person() method makes the
parrot() method, Spring wil ap ly
Implementing relationships among beans defined in the configuration file
1. Spring calls the parrot()
method to create the parrot
bean and add it to the context.
57
@Configuration
public class ProjectConfig {
@Bean
public Parrot parrot() {
Parrot p = new Parrot();
p.setName("Koko");
return p;
}
Spring
@Bean
public Person person() {
Person p = new Person();
p.setName("Ella");
p.setParrot(parrot() );
return p;
3. Does this mean a second
}
2. Spring calls the person()
method to create the person
bean and add it to the context.
parrot instance is created
here when Spring creates
the person bean?
}
Figure 3.5 Spring creat es a parrot instance when it calls the first @Bean annot at ed met hod
parrot() . Then, Spring creat es a person inst ance when it calls t he second @Bean annot at ed
met hod person() . The second met hod, person() , direct ly calls t he first met hod, parrot() .
Does t his mean t wo instances of type parrot are created?
If the parot bean alredy exist n the contex, hen instead of caling the
methodSp, rinwig dl irectakhy ne stanfroce micots nthIfex. parobt eandoes
not ye xist n the contex, Spring cals the
(figure3.6)
parrot()
parrot() method and retuns the bean
3A. Return directly the parrot bean from
the Spring context without delegating
the call anymore to the parrot() method.
YES
1. Call the parrot() @Bean method
from the person() @Bean method.
Figure 3.6 When two met hods annot ated
with @Bean call each ot her, Spring knows
you want t o creat e a link between t he beans.
If t he bean already exist s in t he context (3A),
Spring ret urns t he exist ing bean wit hout
forwarding the call t o t he @Bean met hod. If
t he bean doesn’t exist (3B), Spring creat es
t he bean and returns it s reference.
2. Does a Parrot bean already
exist in the Spring context?
NO
3B. Call the parrot() method, add the
value it returns to the Spring context,
and return the value to the actual call
made from the person() method.
58
CHAPTER 3
The Spring context: Wiring beans
It’s aculy quite sya otes his behavior. Justad a no-args construcort he
rot clas nd print a mesage into he console from it. How many times wil the message be printed in the console? If the behavior is coret, you’l se the mesage only
once. Let’s do this expriment. In the next code snip et, I’ve changed the
clastod ano-argsc nstrucor:
Par-
Parrot
public class Parrot {
private String name;
public Parrot() {
System.out.println("Parrot created");
}
// Omitted getters and setters
@Override
public String toString() {
return "Parrot : " + name;
}
}
Rerunthape Th. oe utpucht angedn(s coext dsne ip aent), dnowth“Pe aroce-t
ated” mesage p reas wel. You’l observ it ap ears only once, which proves tha
Springmanagesthebancreationa dcalsthe
parrot() methodonoly nce:
Parrot created
Person's name: Ella
Person's parrot: Parrot : Koko
3.1.2
Wiring the beans using the @Bean annotated method’s parameters
In this section, I’l show you an alternative ap roach to directly lcaing the
method. Instead of directly ang the method tha defines the ban we wish to ref
towe, ad pa rmtoer hmee thodothf coe rspondintypg oe f banject, dwerely
onSpringtoprovideusavluethrough thaprmetr(figue3.7)Thisap roachis
a bit more flxibe than the one we discued in section 3.1 With this ap roach, it
doesnma’t theifr beanwewantoref todis efnedwithmea thodan otaedwith
@Bean or using a steroype an otai n like
myexprince,howevr,Ihaveobservdit’snotnecasrilythisflexbtyhatmakes
devlopers use this ap roach; it’s mostly he tsa of each devloper that detrmines
which ap roach they use when working with beans. I wouldn’t say one is betr han
the other, but you’l encounter both ap roaches in real-world scenarios, you ned
tounderstandandbea ltousethem.
Todemonthapsrei roachwhpweaurme s inetrcalsodhfge
method directly, we’l take the code we devloped in the project “sq-ch3-ex2” and
chantoesbi lhg t linebktwenthwe oinstani cetshoenspI’thlexar.
newexampleinaprojectnamed“sq-ch3-ex.”
@Bean
@Component (discued in chapter 2). In
@Bean
Implementing relationships among beans defined in the configuration file
@Configuration
public class ProjectConfig {
59
We instruct Spring to provide a bean
from its context by defining a parameter
for the method.
@Bean
public Parrot parrot() {
Parrot p = new Parrot();
p.setName("Koko");
return p;
}
Spring context
@Bean
public Person person(Parrot parrot) {
Person p = new Person();
p.setName("Ella");
p.setParrot(parrot);
return p;
}
}
We set the value of the person’s
attribute with the reference
Spring provided.
The result is the has-A relationship
between the two beans. The person
has-A (owns) the parrot.
Figure 3.7 By defining a paramet er to t he met hod, we instruct Spring t o provide us a bean of t he t ype
of that paramet er from it s cont ext . We can t hen use t he provided bean ( parrot ) when creating the
second one ( person ). This way we est ablish the has-A relat ionship bet ween t he t wo beans.
Inthne listx yog, ufindthde fintionothf coe nfiguratonTaclas. oakethe
person() method.Itnowrecivsaprmetrofype
of tha parmetr to the retuned person’s atribute. When caling the method,
Spring knows it has to find a parot bean in its contex and inject its value into the
parmetrofhe
Listing 3.4
Parrot ,andIsetherfnce
person() method.
Inject ing bean dependencies by using paramet ers of t he met hods
@Configuration
public class ProjectConfig {
@Bean
public Parrot parrot() {
Parrot p = new Parrot();
p.setName("Koko");
return p;
}
@Bean
public Person person(Parrot parrot) {
Person p = new Person();
p.setName("Ella");
p.setParrot(parrot);
return p;
}
}
Spring injects the parrot
bean into this parameter.
60
CHAPTER 3
The Spring context: Wiring beans
In the previous parg h, I used the word n“i ject.” I rf her to what we wil from
nowoncaldepndencyinjection(DI).Assint amesugt,DIisatechniqueinvolinthg frame ewosetinrk valugine topsa fieldc opr amInetr. ouSpcase,r ing
setaprticulav eintoheparmetrofhe
resolv a depndency of this method. DI is an ap licaton of the IoC princple, and
IoC implies that he framework controls the ap licaton at excution. I repat figure
3.8wh, ichyoualsowinchapt(e1frigu.4),herasfhefor udr iscuon
onIoC.
person() methodwhencailngitna d
Without IoC
The application executes
and controls (uses) the
dependencies it needs.
Dependency
Dependency
Dependency
Controls
Application
The application executes
being controlled by the
framework (dependency).
With IoC
Application
Controls
Framework (dependency)
Figure 3.8 An applicat ion t hat ’s not using the IoC principle controls t he execut ion and makes use
of various dependencies. An applicat ion using t he IoC principle allows a dependency to cont rol it s
execution. The DI is such an example of cont rol. The framework (a dependency) set s a value int o a
field of an object of the app.
You’l often use DI (and not only in Spring) becaus it’s a very comfortable way to
manage object instances that are creatd and help us minimize the code we write
when devlopingourap s.
Whenrun ingtheap ,theoutputinyourconsolewilbesimilartohenextcode
snip et.Youobservthatheparot
Parrot created
Person's name: Ella
Person's parrot: Parrot : Koko
Koko isnde linkedtoheprson
Ella :
Using the @Autowired annotation to inject beans
3.2
61
Using the @Autowired annotation to inject beans
In this section, we discu another ap roach used to creat a link betwen beans in
the Spring contex. You’l often encounter his technique, which refs to an an otatio n na m ed
bean(whenthisclanotparofdepndency).Usingthe
wemarkanobjectp’s ropertywherwewantSprintog injvecalut fromthcoe ntex,
and we mark this ntention directly n the clas tha defines the object hat neds the
depndency. This ap roach makes it easir to se the relationship betwen the two
objects han the atlrnaetivs we discuedin section 3.1 As you’l se,ther a thre
wayswecanuseth
@Autowired, when you can change the clas for which you defin the
@Autowired an otai n,
@Autowired an otai n:
Injecting the value in the fild of the clas, which you us aly find in examples
andpro fsoc ncept
Injecting the value through the construcor parmetrs of the clsa ap rocah
thayou’l semostofeni real-worldscenarios
Injecting the value through the setr, which you’l raely use in productionreadycode
Let’sdicusthesinmoredtailndwriteanexampleforach.
3.2.1
Using @Autowired to inject the values through the class fields
In this ecton, we star by discung the simplest of the thre posiblte for using
@Autowiredwh, ichalsothoe nde vlopoers ftnuinse xampules: inthg ane otationotvehr fild(guAs3.9r)e youle’arnev, thif aps roachstevriyg tforward, it has its sins, which is why we avoid using it when writng production code.
Howevr, you’l se it ofen used in examples, pro fs o c ncept, and in writng tes,
aswe’ldiscunchapter15,soy unedtoknowhowtousethisap roach.
Letd’s evlopa ro(ject“sq-h3-ex4i”n) whichwean otahe
Person clas with the
thefromcoits ntLeex. tswi’ar th cldeas fin og utwr o bjects:
Parrot .Youfindthedfintionofthe
parrot feildofthe
@Autowired an otai n to tel Spring we want o inject a vlue
@Component
public class Parrot {
private String name = "Koko";
// Omitted getters and setters
@Override
public String toString() {
return "Parrot : " + name;
}
}
Personna d
Parrot clasinthenxtcodesnip et:
62
CHAPTER 3
The Spring context: Wiring beans
The stereotype annotation @Component
instructs Spring to create and add a bean
to the context of the type of this class: Person.
@Component
public class Person {
private String name = "Ella";
@Autowired
private Parrot parrot;
Spring context
// ...
}
We instruct Spring to provide a bean
from its context and set it directly as
the value of the field, annotated with
@Autowired. This way we establish
a relationship between the two beans.
Figure 3.9 Using t he @Autowired annotat ion over the field, we instruct Spring t o provide a
value for that field from it s cont ext. Spring creat es t he t wo beans, person and parrot , and
inject s t he parrot object t o the field of t he bean of type Person .
We use the stroype an otai n
(section 2.) We use the steroype an otai n as an alternative to creating the
bean using the configuraton clas. When an otaing a cls with
knowsithastocreni stanceofthatclsnda ditosc ntex.Thenxtcode
snip etshowsthedfintonofthe
@Component her, which you learned in chapter 2
@Component , Spring
Person clas:
@Component
public class Person {
private String name = "Ella";
@Autowired
private Parrot parrot;
Annotating the field with @Autowired, we
instruct Spring to inject an appropriate
value from its context.
// Omitted getters and setters
}
NOTE
I’ve used steroype an otai ns to ad the beans in the Spring con-
tex for this example. I could have defined the beans using
often, in real-world scenarios, you’l encounter
with steroype an otai ns, olet’s focusontheap roachthat’s most usef l
fory u.
Tocontinuoe uerxampwele, defincaoe nfigutraonclasI’. mthe configuraton
clas
ProjectConfig . Over this clas, I’l use the
Spring wher to find the clase Iv’e an otaed with
@Bean , but most
@Autowired used togehr
@ComponentScan an otai n to tel
@Component , as you learned in
Using the @Autowired annotation to inject beans
chapter 2 (section 2.) The next code snip et shows the defintion of the configurationclas:
@Configuration
@ComponentScan(basePackages = "beans")
public class ProjectConfig {
}
I’l then use the main clas, the same way I’ve used in the previous examples of this
chapter,oprovethaSpringnjectdheparotbean’srefnceortly:
public class Main {
public static void main(String[] args) {
var context = new AnnotationConfigApplicationContext
(ProjectConfig.class);
Person p = context.getBean(Person.class);
System.out.println("Person's name: " + p.getName());
System.out.println("Person's parrot: " + p.getParrot());
}
}
This wil print in the ap ’s console something smi ilar to the output perns ted next.
The second line of the output proves that the parot (in my case, named Koko)
belongstoheprsonbean(namedElla):
Person's name: Ella
Person's parrot: Parrot : Koko
Why is this ap roach not desir in production code? It’s not otaly wrong to use it,
but oy u want o make sure you make your ap maintainable and tesabl in productioncode.Byinjectingthevaludirectlynthefild:
you don’t have the option to make the fild final (se next code snip et), and
thisway,makesurno necanchangeitsvalufterintialzon:
@Component
public class Person {
private String name = "Ella";
@Autowired
private final Parrot parrot;
}
it’smoredifcultomanagethevalueyourselfatintialzon.
This doesn’t compile. You cannot define
a final field without an initial value.
63
64
CHAPTER 3
The Spring context: Wiring beans
As you’l earn in chapter 15, you sometimes ned to creat instances of the objects
andeasilymanagetheunites’dpendencies.
3.2.2
Using @Autowired to inject the values through the constructor
The second option you have for injecting values into the object’s atributes when
Spring creats a bean is using the clas’ construcor defin g the insta ce (figure
Th3.10) apis roach this oe nue sdmoost feni productioncodane dthoe nrec-I
ommendenIt. abyoles utodefinthe fildnas el, suring o ncae hanthge ir
value after Spring intialzes them. The posiblty to set he values when caling the
construcoalsrhelpyosuwhenwritnspg uecif nwhtesi yoer udonwa’t ntorely
onSpringmakingthefildnjectionfory u(butmoreonthisubjectlar).
The stereotype annotation @Component
instructs Spring to create and add a bean
to the context of the type of this class: Person.
@Component
public class Person {
private String name = "Ella";
private final Parrot parrot;
Spring context
@Autowired
public Person(Parrot parrot) {
this.parrot = parrot;
}
// ...
}
When Spring creates the bean of
type Person, it calls the constructor
annotated with @Autowired. Spring
provides a bean of type Parrot from
its context as value of the parameter.
Figure 3.10 When you define a parameter of t he const ruct or, Spring provides a bean from it s
context as a value to t hat paramet er when calling t he const ructor.
We can quickly change the project’s implementaoi n from section 3.21 to use construcorinjectioninsteadofieldnjection.Youonlynedtochangethe
pas rentedinthfoe l winlstg Yo. unedto efincoaenstrucofrthanclse d
an otae i with
nedtomakeanychangestoy urconfiguratonclas.
Listing 3.5
Person clas,
@Autowired . Now we can also make the
Inject ing t he values t hrough const ruct or
@Component
public class Person {
private String name = "Ella";
parrot field final. You don’t
Using the @Autowired annotation to inject beans
private final Parrot parrot;
@Autowired
public Person(Parrot parrot) {
this.parrot = parrot;
}
We can now make the field final to ensure its
value cannot be changed after initialization.
We use the @Autowired annotation
over the constructor.
// Omitted getters and setters
}
To kep al the stp and changes, I’v parted this example in the project “sq-h3ex5.” You can alredy star he ap and observ tha it display the same rsult as in
thexampinle scton3As.21 youcanise thne coxt dsne ip the, personowns
theparot,s Springestablihedthelinkbetwenthetwoinstancesortly:
Person's name: Ella
Person's parrot: Parrot : Koko
NOTE
Staring with Sprni g version 4.3, when you only have one construcor
intheclas,youcanomitwritngthe
3.2.3
@Autowired an otai n.
Using dependency injection through the setter
You won’t ofen find devlopers ap lying the ap roach of using the str fo depndeni cy jetionTh. apis roachmoas dreisa vnthages ndvanmoit’s age: chre allengi gtoread,it oesn’talowyoutomake thefildnal,ndit oesn’thelpyouin
making the tesing easir. Even so, I wanted to mention this posiblty. You might
encounter i at some point, and I don’t want you to wonder about is extnce then.
Evenit’sf ost methinrecoIg mmendhI, seavnthuis edincoa upole f ldap s.
In the project “sq-ch3-ex6,” you’l find an example of using the setr injection.
You’l fni d tha I only ned to chna ge the
nextcodesnip et,Iusdthe
Person clas to implement this. In the
@Autowired an otai nonthestr:
@Component
public class Person {
private String name = "Ella";
private Parrot parrot;
// Omitted getters and setters
@Autowired
public void setParrot(Parrot parrot) {
this.parrot = parrot;
}
}
When run ing the ap , oy u’l get he same output as the previously discued examplesofthisecton.
65
66
3.3
CHAPTER 3
The Spring context: Wiring beans
Dealing with circular dependencies
It’s comfortable to let Spring build and set he depndencies to the objects of your
ap licaton.LetingSpringdothisjobfory usaevyoufromwritngabunchoflines
of code and makes the ap easir to read and understand. But Spring can also get
confused in some cas. A scenario ften encounterd in practie s gnerating a circulardepndencybmistake.
A cirula depndency (figure 3.1) is a tuaion in which, to creat bean (let’s
nametiBeanA),Springnedstoinjectanotherbanthadoesn’texisy(BeanB).
ButBeanBalsorequestadepndencytoBeanA.So,t creaBeanB,Springneds
first o have Bean A. Spring is now in a dea lock. It can ot crea Bean A becaus it
nedsBeanB,anditcan otcreaBeanBbecausitnedsBeanA.
2. To call the Parrot class
constructor, Spring needs a
bean of type Person.
1. Spring needs to create
a bean of type Parrot.
3. Spring tries to
create the bean
of type Person.
@Component
public class Parrot {
@Component
public class Person {
private final Person person;
private final Parrot parrot;
@Autowired
public Parrot(Person person) {
this.person = person;
}
@Autowired
public Person(Parrot parrot) {
this.parrot = parrot;
}
}
}
4. To create a bean of type
Person, Spring needs a
bean of type Parrot.
Spring is now in a deadlock!
Figure 3.11 A circular dependency. Spring needs t o create a bean of t ype Parrot . But because
Parrot has as a dependency a Person , Spring needs first to creat e a Person . However, t o create a
Person , Spring already needs to have built a Parrot . Spring is now in a deadlock. It cannot creat e
a Parrot because it needs a Person , and it cannot create a Person because it needs a Parrot .
A cirula depndency is eay to avoid. You just ned to make sure you don’t define
obwhjects ocreatis ndepndosnthoethHaer. vindgepndenfrociesmonoebt jc
anboadthisInlekgyouca.r,fherdwtoy riute code.
dI onth’ inIk knowanSpy rindg evlopwher odi noleast ’ ciruaet l
depndency in an ap . You ned to be aware of this scenario so thta when you
encounteri,youknowitscauendyou’lsoveitfa.
Dealing with circular dependencies
67
nI theproject“sq-h3-ex7,”you’lfindanexampleofciruladepndency.Aspresentedinthne coxt dsne ip maIets, dthe Parobt eni’s tantiaondepndenot n
the
Person beanandvice-rsa.
The
Person clas:
@Component
public class Person {
private final Parrot parrot;
@Autowired
public Person(Parrot parrot) {
this.parrot = parrot;
}
To create the Person instance,
Spring needs to have a Parrot bean.
// Omitted code
}
The
Parrot clas:
public class Parrot {
private String name = "Koko";
private final Person person;
@Autowired
public Parrot(Person person) {
this.person = person;
}
To create the Parrot instance, Spring
needs to have a Person bean.
// Omitted code
}
Run ingtheap withsuchaconfiguratonwileadtoanexcptionliketheonepresentedinthenextsnip et:
Caused by:
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error
creating bean with name 'parrot': Requested bean is currently in creation:
Is there an unresolvable circular reference?
at
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.before
SingletonCreation(DefaultSingletonBeanRegistry.java:347)
With this excption, Spring tries o tel you the problem it encounterd. The xcption mesage is quite clear: Spring deals with a cirula depndency and the clase
thcausedthsiue atonWh. enyeovr ufindsuchan excptionyo, unedtog the
clasepcifedbythexcptionandeliminateheciruladepndency.
68
3.4
CHAPTER 3
The Spring context: Wiring beans
Choosing from multiple beans in the Spring context
In this ecton, we discu the scenario in whcih Spring neds to inject a vlue into a
parmetr or clas fied but has multipe beans of the same type to cho se from. Say
yo u h av e th re
valuoe typf e
thesametypwouldtheframeworkcho setoinjectinsuchacsenario?
Dependingonyourimpelmentaoi n,youhavethefol wingscae:
1
2
Parrot beans in the Spnri g contex. You confgiure Spring to inject a
Parrot intopa rmetr.HowwiSlprinbg ehave?Whichotfhbe anos f
Thide notifer hpe armematr tches namoe f noe thf be anfros mthe
contex (whic , remember, is the same as the name of the method an otaed
with
@Bean tha retuns it value). In this cae, Spring wil cho se the ban for
whicht enameisthesameastheparmetr.
Theidntiferotheparmetrdoesn’tmatchanyofthebannamesfromthe
contex.Thenyouhavethefol wingoptions:
a Youmarkedoneofthebansaprimary(swediscuedinchapter2,using
the
@Primary an otai n). In this case, Spring wil selct he primary bean
for injection.
b You can explicty selct a specif bean using the
whichwedsciunthischpa ter.
c If none of the beans i primary nd you don’t use
fail withanexcption, complain gtha the contexcontainsmore bansof
thesametypandSpringdoesn’tknowwhichonetocho se.
Let’s ry further in the project “sq-ch3-ex8,” a scenario ni which we haev more than
one instance of a type in the Spring contex. The next lins g shows you a configuratio n c las th at d e fine s tw o
parmetrs.
Listing 3.6
@Qualifier an otai n,
@Qualifier , the ap wil
Parrot insta ces and use injection through the method
Using paramet er inject ion for more t han one bean
@Configuration
public class ProjectConfig {
@Bean
public Parrot parrot1() {
Parrot p = new Parrot();
p.setName("Koko");
return p;
}
@Bean
public Parrot parrot2() {
Parrot p = new Parrot();
p.setName("Miki");
return p;
}
@Bean
public Person person(Parrot parrot2) {
The name of the parameter
matches the name of the bean
representing parrot Miki.
Choosing from multiple beans in the Spring context
69
Person p = new Person();
p.setName("Ella");
p.setParrot(parrot2);
return p;
}
}
Run inthg ape with cois nfiguratonyo,u’dobcaservnsoleutpusimt toilarhe
next code snip et. Observ tha Spring linked the
Miki becausthebanrepsnti gthisparothasthename
person bean to the parot named
parrot2 (figure3.12):
Parrot created
Person's name: Ella
Person's parrot: Parrot : Miki
@Configuration
public class ProjectConfig {
@Bean
public Parrot parrot1() {
Parrot p = new Parrot();
p.setName("Koko");
return p;
}
In the context, we define two beans
of type Parrot. These two beans will
take the name of the methods creating
them: parrot1 and parrot2. We also
define one bean of type Person.
Spring context
parrot1
@Bean
public Parrot parrot2() {
Parrot p = new Parrot();
p.setName("Miki");
return p;
}
@Bean
public Person person(Parrot parrot2) {
Person p = new Person();
p.setName("Ella");
p.setParrot(parrot2);
return p;
}
}
parrot2
Spring will provide the value of the
bean whose name is the same as the
name of the parameter we defined.
Figure 3.12 One way t o instruct Spring t o provide you a specific inst ance from its cont ext , when
the cont ext cont ains more than one inst ance of the same t ype, is to rely on t he name of this
inst ance. Just name t he paramet er t he same as t he instance you’d like Spring t o provide you.
Inreal-worldscenariopI, tref avoidrelynog nthne amoethf pe armwhetr, ich
couldbrefactosiy dandchangedbmiy bstakeny othder vlopToer. mofel re
comfortba le, I us aly cho se a more visble ap roach to exprs my intention to
inject a specif bean: using the
found evlopersaguingforandaginstuingthe
@Qualifier an otai n. Again, in my exprince, I
@Qualifier an otai n.Ifelits
70
CHAPTER 3
The Spring context: Wiring beans
betr o use in this cae becaus it cleray defines your intention. Other devlopers
belivda ingthisan otai ncreatsun ed (boilerpat)code.
The fol wing ilstng provides na example using the
Observthatinsteadofhavingaspecifdntiferoheparmetr,Inowspecifythe
beanIwantoinjectusingthevalutributeofhe
Listing 3.7
@Qualifier an otai n.
@Qualifier an otai n.
Using t he @Qualifier annot at ion
@Configuration
public class ProjectConfig {
@Bean
public Parrot parrot1() {
Parrot p = new Parrot();
p.setName("Koko");
return p;
}
@Bean
public Parrot parrot2() {
Parrot p = new Parrot();
p.setName("Miki");
return p;
}
@Bean
public Person person(
@Qualifier("parrot2") Parrot parrot) {
Using the @Qualifier annotation,
you clearly mark your intention
to inject a specific bean from the
context.
Person p = new Person();
p.setName("Ella");
p.setParrot(parrot);
return p;
}
}
Rerun ingtheap licaton,theap printshesamersultintoheconsole:
Parrot created
Person's name: Ella
Person's parrot: Parrot : Miki
A similar stuaion can also hap en when using the
you this case, I creatd another project, “sq-ch3-ex9.” In this project, we define two
beans of type
Parrot (using the
steroypean otai ns).I’lconfigureSpintgoinjoect neofthewo
thebanoftype
Person .
Aspresntedinthenextcode snpi et,Idi n’tad the
Parrot clas becaus I intend to define the two beans of type
the
@Bean an otai nintheconfiguratonclas:
@Autowired an otai n. To show
@Bean an otai n) and an insta ce of
Person (using
parrot beanis
@Component an otai nto
Parrot uisng the
Choosing from multiple beans in the Spring context
71
public class Parrot {
private String name;
// Omitted getters, setters, and toString()
}
We define a bean of pty e
Observ the identifer I gave to the parmetr of the construcor in the next code
snip et. The rason I gave the identifer “parot2” is this the name I’l aso configurefothebani thecontexIwantSpringtoinjectinothaprmetr:
Person using the
@Component steroype an otai n.
@Component
public class Person {
private String name = "Ella";
private final Parrot parrot;
public Person(Parrot parrot2) {
this.parrot = parrot2;
}
// Omitted getters and setters
}
I define two beans of type
claDos. nfo’t werge hstil oaved
clase n otaedwithsteroypean otai ns. In ourcase,wean otaedclas
with the
theconfiguratonclas.
Parrot using the
@Bean an otai n in the configuraton
@ComponentScantoSpel rinwhg toer findthe
Person
@Component steroype an otai n. The next lisng shows the defintion of
Listing 3.8
Defining t he beans of t ype Parrot in t he configurat ion class
@Configuration
@ComponentScan(basePackages = "beans")
public class ProjectConfig {
@Bean
public Parrot parrot1() {
Parrot p = new Parrot();
p.setName("Koko");
return p;
}
@Bean
public Parrot parrot2() {
Parrot p = new Parrot();
p.setName("Miki");
return p;
}
}
With the current setup, the bean named
parrot2 is the one that Spring injects into
the Person bean.
72
CHAPTER 3
The Spring context: Wiring beans
What hap ens if you run a main method as the one presnted in the next code snippOuet? pr esonownwhs ichparoBet? cauthse namoethf coe nstrucopr’s ametr
matchesoneoftheban’snamesintheSpringcontex(
bean(figure3.1),sothenameoftheproa theap printsintheconsolei
parrot2 ),Springinjectshat
Miki :
public class Main {
public static void main(String[] args) {
var context = new
AnnotationConfigApplicationContext(ProjectConfig.class);
Person p = context.getBean(Person.class);
System.out.println("Person's name: " + p.getName());
System.out.println("Person's parrot: " + p.getParrot());
}
}
Run ingthisap ,theconsolehowsthefol wingoutput:
Person's name: Ella
Person's parrot: Parrot : Miki
When Spring creates the bean of
type Person, it also needs to provide
a value for the constructor’s parameter.
If multiple beans of the same type are
available, Spring will choose the bean
with the same name as the parameter.
@Component
public class Person {
private String name = "Ella";
private final Parrot parrot;
public Person(Parrot parrot2) {
this.parrot = parrot2;
}
Spring context
// ...
parrot1
}
parrot2
Figure 3.13 When t he Spring context cont ains multiple beans of t he same type, Spring will
select the bean whose name mat ches the name of t he paramet er.
As we discued for the
relying on the name of the varible. Instead, I pref using the
tiontoexpmyrs intentioniIcleary: jt psa becif anfromthcoe nThtex. wais y,
we minimize the chance that someone would refacto the name of the varible and
thus afect how the ap works. Look at he change I made to the
@Bean an otaed method parmetr, I recommend aginst
@Qualifier an ota-
Person clas in the
Summary
nextcodesnip et.Usingthe
want Spring to inject from the contex, and I don’t rely on the identifer of the construcor’spametr(shechangeintheprojectnamed“sq-ch3-ex10”):
73
@Qualifier an otai n,IspecifythenameofthebanI
@Component
public class Person {
private String name = "Ella";
private final Parrot parrot;
public Person(@Qualifier("parrot2") Parrot parrot) {
this.parrot = parrot;
}
// Omitted getters and setters
}
The behavior of the ap doesn’t change, and the output remains the same. This
ap roachmakesyourcodelsubjectomistake.
Summary
The Spring contex is a place in the ap ’s memory that he framework use to
kep the objects i manages. You ned to ad any object hat neds to be augmentedotheSpringcontexwithafeturheframework fes.
Whenimplementinag p yo, unedtofr monoe btjcanothTher. is
way, an object can delgat actions to other objects when excuting their
responsibTolte. implementhbis ehavioyr, unedtosba lihreatonships
amongthebansintheSpringcontex.
You can establih a relationship betwen two beans using one of thre
ap roaches:
– Directly fering to the
@Bean an otaed method that cres one of them
from the method tha crets he other. Spring knows you ref to he ban
inthcoe nteaxn, dthif be anlreadxiyst, oesnca’thl semmee thod
agin to creat another instance. Instead, it retuns the refnce to the
existngbeani thecontex.
– Defin g a parmetr to the method an otaed with
observ the
@Bean method has a parmetr, it searches a bean of that
parmetr’s type in its contex and provides that bean as a value to the
pa r m e t r .
– Usingthe
@Autowired an otai ni threways:
Annotae he fild in the clas wher you wanto instruc Sprni g to inject
the bean from the contex. You’l find this ap roach often used in examplesandpro fsoc ncept.
@Bean . When Spring
74
CHAPTER 3
The Spring context: Wiring beans
Annotae the construcor you’d like Spring to cal to creat the bean.
Spring wil inject other beans from the contex in the construcor’s
parmetrs.You’lfni dthisap roachthemostuedinreal-worldcode.
Annotae he str of the atribute wher you’d like Spring to inject he
bean from the contex. You won’t find this ap roach often used in
production-readycode.
Whenyover ualowSprintogprovidalue orfnthce roughantribute
othf oclmeaser thodocr nstrucopr amweetr, Spsay rinug DIse techa, niques p ortedbytheIoCprincple.
The creation of two beans tha depnd on one another genrates a cirula
depndency. Spring can ot creat he beans with a cirula depndency, and
thexcutionfailswithanexcption.Whenconfigurngyourbeans,makesur
youavoidcruladepndencies.
When Spring has more than one bean of the same type ni its contex, i can’t
deci which of those beans ned to be injectd. You can tel Spring which is
theinstanceitnedstoinjectby
– usingthe
@Primary an otai n,whichmarksoneofthebansa thedefault
fordepndencyinjection,or
– naming the beans and injecting them by name uins g the
a n o ta i n .
@Qualifier
TheSpringcotx:
Usingabstrco
This chapter covers
Using interfaces to define contracts
Using abstractions for beans in the Spring
context
Using dependency injection with abstractions
In this chapter, we discu using abstrcion with Spring beans. This topci s enbtial ecuins real-worldprowejects, oftenuabse trciontosdecoupimle plementaions. As you’l earn in this chapter,we ensure our ap licaton is comfortable o
maintai andtesbydecouplingimplementaions.
We’l star with a refsher on how to use interfacs o define contracs in section 4.1 To ap roach this ubject, we begin by discung objects’ rponsiblte
andfindouthowtheyfitnastndar clasdeignofanap .We’luseourcoding
skil toimplementa smalscenario n whichwe don’t uesSpring, but wefocus on
implementing a requirement and using abstrcions to decouple the ap ’s depndentobjects.
75
76
CHAPTER 4
The Spring context: Using abstractions
We then discu Spnri g’s behavior when using DI with abstrcions in section 4.2
We’l star fom the implementaion we worked on in section 4.1 and ad Spring to
the ap s’ depndencies. We then use the Spring contex o implement depndency
injection. With this example, we get closer to what you expct o find in productionready implementaions: objects with typical responsiblte for real-world scenarios
andabstrcionuesdwithDIandtheSpringcontex.
4.1
Using interfaces to define contracts
Inthisecton,wediscu usinginterfacsodefinecontracs.InJav,theinterfacis
anbstracu yreou setodeclarspif onsiblty.Anobjectimplementing the interfac has to defni this responsiblty. More objects implementi g the
same interfac can define the responsiblty declar by tha interfac in difernt
ways. We can say tha the interfac specif the “what neds to hap en,” while vry
objectimplementingtheinterfacspifesthe“howitshouldhap en.”
WhenwaI kidasmy, da megve anodl ra iocI uld isaembanle dpwilay th(I
was quite nthusiatc bout disaembling things). Looking at i, I realizd I ned
something to unscrew the bolts of the cas. After hinking a while, I deci d I could
use a knfie or this job, so I asked my ftaher for a knife. He asked me, “Whta do you
nedaknifeor?”IsaidIned ito penthecas.“Oh!”hesaid.“Youbetrusea
screwdrive; her it s!” At that ime, I alerned that i’s always marte o ask for what
you ned instead of or a solution when you have no idea what you’re doing. Interfacesrthewayobjectsakforwhatheyned.
4.1.1
Using interfaces for decoupling implementations
This ecton discue what contracs e and how you can define them ni a Jv ap
using terfacs.I’lwithananlogy,andthenI’ul seomevisuatloexplainthe
concepant dwhenusinugseftWerac .l th’l enco tinuwie threquirements
of a problem in section 4.12 and solve this cenario without a frmework in section
F4.13urthiner, sctonwe4.2, ad Sprintog urecipan, dyoulearn’ howdepndencyinjectioni Springworkswhenusingcontracsodecouplefunctionalites.
An analogy: Sup ose you use a ride-shrina g ap becaus you ned to get somewher. When you orde a trip, you us aly don’t care how the car lo ks or who the
drive s. You just ned to ge somewher. nI my case, I don’t care whether a c or a
spacehipcomtoespmeick upreachIif t de stinationi tmThe. ride -sharinpg
is an interfac. The customer doesn’t request a cr or a drive, but a trip. Any drive
withacrwhocanoferthesrvicananswerthecustomer’squest.Thecustomer
andthde ariv ecoupledthrought ape (interfahc); ue stomder oesnk’t ow
who the drive is nor which car wil pick them up befor a car responds to their
request, and the drive doesn’t ned to know who they do the srvic for. Using this
analogy, ucande ucetherol finterfacsinrelationshipwithobjectsinJav.
An implementaion example: Say you implement an object tha neds to print
packge’s details to be delivr for a ship ing ap . The printed details must be
Using interfaces to define contracts
77
The SorterByAddress object
implements the sorting responsibility.
To sort the details before printing, the
DeliveryDetailsPrinter needs to sort
the details by their delivery addresses.
DeliveryDetailsPrinter
SorterByAddress
Uses
printDetails()
sortDetails()
The DeliveryDetailsPrinter delegates the
sorting responsibility to another object.
Figure 4.1 The DeliveryDetailsPrinter object delegat es the responsibilit y of sorting t he
delivery det ails by the delivery addresses t o anot her object named SorterByAddress .
sortedbytheirdstnationda res.Theobjectdalingwithprintngthedtailsneds
to delgat to some other object the responsiblty of sorting the packges by their
delivrya dres(figure4.1)
Asshowni fgur4et.1h, e
responsibltyohe
difcultes later if we ned to change this functionality. Let’s imagine you ned to
chanthpgerintedanorlis,dthenwthbosenyrdi ne r’samYoue. ’d
nedtoreplacthe
responsiblty, uot u’dalsonedto chanthge
usethesortingresponsiblty(fgure4.2)
DeliveryDetailsPrinter directly gaehs ornti g
SorterByAddress object.Ifwekepthiscladegn,wemayface
SorterByAddress objectwithanotheroneimplementingthenew
DeliveryDetailsPrinterobthjec at
public class DeliveryDetailsPrinter {
private SorterByAddress sorter;
public DeliveryDetailsPrinter(SorterByAddress sorter) {
this.sorter = sorter;
}
If you must change the
sorting responsibility,
these are places you
need to change the code.
public void printDetails() {
sorter.sortDetails();
// printing the delivery details
}
}
Figure 4.2 Because the t wo object s are st rongly coupled, if you want t o change t he sorting
responsibility, you also need t o change t he object using this responsibilit y. A bett er design would allow
you to change the sort ing responsibilit y without changing the object t hat uses the responsibilit y.
78
CHAPTER 4
The Spring context: Using abstractions
Howcanweimprothve dis egnWh? enchanginag obrespjct’ onisbwelty, wanto
avoidthne dtochanoge thoer bujects inthg ce angedrsponsiblThty. dis egn’s
problem ocurs becaus the
DeliveryDetailsPrinter object specif both what it
neds and how it neds. As discued earli, an object only neds to specify what i
neds and stay complety unaware of how the what is mplemented. We do this, of
course, by using interfacs. In figure 4.3, I introduced an interfac named
Sorter to
decouple the two objects. Instead of declaring a
SorterByAddress , the
DeliveryDetailsPrinter object only specifs it neds a
Sorter . You can now have as many
DeliveryDetailsPrinter An. y
obyojasect u’dtolike s lve thwhe reatquestdbthy e
obimject plementi hg e
Sorterincatherfsiydepndenothcyf e
DeliveryDetailsPrinter objectanytime.Figure4.3isavulrepsntaionofthedpenDeliveryDetailsPrinter objectandthe
SorterByAddress object
d en c y b et w e n the
afterwedecoupledthemusingani terfac.
The DeliveryDetailsPrinter object specifies
only what it needs to implement its responsibility.
Instead of depending on an implementation,
the DeliveryDetailsPrinter object now depends
on an interface.
DeliveryDetailsPrinter
Uses
The Sorter interface defines what
the DeliveryDetailsPrinter object needs.
Sorter
<<interface>>
printDetails()
sortDetails()
SorterByAddress
sortDetails()
SorterByName
sortDetails()
You now can have more objects implementing the same
interface. This allows you to change the implementation
(the how) without affecting the object that consumes the
implementation (DeliveryDetailsPrinter).
Figure 4.3 Using an interface t o decouple t he responsibilit ies. Inst ead of depending directly on an
implement at ion, t he DeliveryDetailsPrinter object depends on an interface (a contract).
DeliveryDetailsPrinter can use any object implement ing t his interface inst ead of being st uck
to a specific implementat ion.
Using interfaces to define contracts
Inthenextcodesnip et,youfindthe
79
Sorter interfacdinton:
public interface Sorter {
void sortDetails();
}
Look at figure 4. and compare it with figure 4.2 Because the
Printer object depnds on the interfac instead of the implementaion directly, ou
don’t edtochangeitfurherifyouchangethewaythedlivry etailsrod.
DeliveryDetails-
public class DeliveryDetailsPrinter {
private Sorter sorter;
public DeliveryDetailsPrinter(Sorter sorter) {
this.sorter = sorter;
}
Now you can use any implementation
of the Sorter interface and no longer
need to change the object that uses
the responsibility.
public void printDetails() {
sorter.sortDetails();
// printing the delivery details
}
}
Figure 4.4 The DeliveryDetailsPrinter object depends on the Sorter interface. You can
change t he implement at ion of t he Sorter int erface and avoid making more changes t o the object
using this responsibilit y ( DeliveryDetailsPrinter ).
With this theortical introduction, you are now aware of why we use interfacs to
decouple the objects hat depnd on each other in the clas design. Next, we implement a requirement for a scenario. We’l implement this requirement using plain
Jav, without any framework, and we’l focus on objects’ responsiblte and using
interfacs o decouple them. At the nd of this ecton, we’l have project defin g
someobjectshatcolbortae implementausec.
Insection4.2,we’lchangetheprojectanda dSpringtoi managetheobjects
as wel as the relationships among them with depndency injection. By taking this
step-bystepa proachyo, umo’l eaosrily bstherv c anges de toad Sprintog
anp ,aswelasthebnefitshatwouldcomewiththischange.
4.1.2
The requirement of the scenario
Thus far, we’ve used simple xamples and we’ve chosen simple objects (lik
Even if they aren’t close to what a production-ready ap licaton use, they help you
focusonthesyntaxesyounedtolearn.Nowit’ms eyoutakespforwardnduse
whatyou’velarnedintheprviouschapterswithanexamplecosrt whathap ens
intheralworld.
Say ou are implementing an ap a tem use to manage their task. One of the
ap ’sfeatursialowingtheusertoleavcommentsforthetask.Whenauserpublishe a comment, i s tored somewher (.g, in a datbse), and the ap sends an
emailtospecifad resconfiguredintheap .
Parrot ).
80
CHAPTER 4
The Spring context: Using abstractions
We ned to design the objects and find the right responsiblte and abstrcions
forimplementingthisfeatur.
4.1.3
Implementing the requirement without using a framework
Inthisecton,wefocusonimplementing therquirementdescribdinsection4.1
You wil do this by using what you’ve larned about interfacs hus far. Fist, we ned
toidentifyheobjects(rponsiblte)oimplement.
In standar real-world ap licatons, we us aly ref to the objects implementing
use case as servic, and that’s whta we’l do her. We’l ned a servic that implementshe“publishcomment”useca.Let’snamethisobject
CommentService .Iprefer to give the srvic lae name that ends with “vseicr” o that heir ole in the
projectsandsout.Formoredtailsongo dnamingpracties,Iommendchapter
2 from Clean Code: A Handbok of Agile Software Craftsmanship by Robert C. Martin
(Pearson,208).
When analyzing the requirement agin, we observ that the use case consit of
twoacti nsto: rinthg coe mmenat dsendinthg coe mmenbt may Asil. thqarey uite
diferntfromonea other,weconsiderthesactionstobetwodiferntresponsiblties,andthuswenedtoimplementwodiferntobjects.
Whenwehave nobjectworkingdirectylwithadtabse,wegenraylnamesuch
an object reposity. Sometimes you also find such objects refd to sa dat aces
objects (DAO). Let’s name the object hat implements he storing comment responsibilty
CommentRepository .
Finaly, in a real-world ap , when implementing objects whose responsiblty is
to establih communicaton with something outside the ap , we name thes objects
proxies, so let’s name the object whose responsiblty is sending the email
CommentNotificationProxyshF4.5oiguwrethlaionse hamip onthrespgonsiblte.
But wait! Didn’t we say we shouldn’t use direct coupling betwen implementationWes? nedtomakseurwedecoupltehime plementaionbs uy singi terfacIsn.
the end, the
CommentRepository might now ues a datbes to store the comments.
Buint hfue t mare, ybthe nis edtos bche angedtousoe moe thecr nol ogy anr
extrnsearlvicWe. canthsy ame foe thr e
CommentNotificationProxyobjectNo. w
itsendtshne otifca nbemy aibl, umat ybine fua t versionthcoe mment otifcation edtos benthroughsomoe thcer an eWel. certainwayl ntomasuke wer
decouple the
CommentService from the implementaions of its depndencies o tha
whenwenedtochangethedpendencies,wedon’tnedtochangetheobjectusni g
themaswel.
Figush4.6re owhs owtodecoupthle dcasi egnbuy sinabg strcionIs. teadof
designng
CommentRepository and
CommentNotificationProxy as clase, we design
themasinterfacshatwecanimplementodefinethefunctionality.
Using interfaces to define contracts
81
The CommentRepository object stores the
comment in the database. The CommentService
object uses this responsibility to implement
the “ publish comment” use case.
The CommentService object
implements the “ publish comment”
use case.
CommentService
Uses
CommentRepository
publishComment()
storeComment()
Uses
The CommentNotificationProxy object
sends the comment to a specific email
address. The CommentService object
uses this responsibility to implement
the “ publish comment” use case.
CommentNotificationProxy
sendComment()
Figure 4.5 The CommentService object implement s t he “ publish comment ” use case. To do t his,
it needs t o delegat e to t he responsibilit ies implement ed by t he CommentRepository and t he
CommentNotificationProxy objects.
CommentRepository
<<interface>>
storeComment()
Uses
Implements
CommentService
DBCommentRepository
storeComment()
publishComment()
Uses
CommentNotificationProxy
<<interface>>
sendComment()
Implements
Instead of using the implementations directly,
the CommentService object uses abstractions
to decouple from these.
EmailCommentNotificationProxy
sendComment()
Figure 4.6 The CommentService object depends on the abstractions provided by
CommentRepository and CommentNotificationProxy int erfaces. The classes
DBCommentRepository and EmailCommentNotificationProxy furt her implement
these int erfaces. This design decouples t he implementat ion of t he “ publish comment” use case
from it s dependencies and makes t he applicat ion easier to change for fut ure development s.
82
CHAPTER 4
The Spring context: Using abstractions
Now that we have clear picture of what we want o implement, le’s tar coding it.
Fothr moe menwet, pcraet lni Maevnprowiject, thouadt inag extryndal epndencies to he pom.xml fie. I’ name this project “sq-h4-ex1,” and I’l organize t as
presntedinfgusep4.7,r atinhg de ifrnespt onsibnlte hoeir wnpackges.
To make the structure of the project
easy to understand, we organize the
project by distributing the responsibilities
in separate packages.
Figure 4.7 The project st ruct ure. We declare a separat e package for each responsibilit y to make t he
st ruct ure of t he project easy to read and underst and.
OnethingIdi n’tmentionearli(toal wyoutof cusonthemainresponsiblte
othf e ap this) weat also’ htoaverpesnthcoe mmensot mehowWe. junst edto
write a smal POJO clas for defin g the comment. We star he implementaion of
the use case with writng this POJO clas. The responsiblty of this type of object is
simply to model the dat the ap use, and we cal it model. I’l consider a comment
thahstwoatributes:axndanuthor.Let’screapkg
d efin e ac l s
Comment .Thefol winglistngpresntshedfintionofthiscla.
NOTE
model ni whichwe
APOJOisa simpleobjectwithoutdepndencies,onlydescribdbyits
atributes and methods. In our case, the
describngthedtailsofc mmentbyiswoatributes:a horandtex.
Listing 4.1
Comment clas defines a POJO
Defining t he comment
public class Comment {
private String author;
Using interfaces to define contracts
83
private String text;
// Omitted getters and setters
}
Wecan owdefinthe rsponsibolterpf osit anry dproInxy. thne listx yog, u
can se the defintion of the
this interfac declars the
CommentService object neds to implement he use ca. We store this nterfac and
theclasimplementingitnthe
Listing 4.2
CommentRepository interfac. The contrac defind by
storeComment(Comment comment) method, which the
repositories packgeoftheproject.
Defining t he CommentRepository int erface
public interface CommentRepository {
void storeComment(Comment comment);
}
Theinterfaconlygivesthewhathe
the use ca: store a comment. When you define an object hat implements his contrac,inedsto veridthe
howIn. thne ltisx gyo, ufindthde fintonothf e
donk’t owhyet owtoc n todeca bsoae,weo’l nwrly intexa hcoe nsotle
simulate his acton. Later, saing with chapter 12, you’l aso learn how to con ect
yourap licatontoadtbase.
Listing 4.3
CommentService objectnedsforimplementing
storeComment(Comment comment) methodtodefinethe
DBCommentRepository clasWe.
Implement ing t he CommentRepository int erface
public class DBCommentRepository implements CommentRepository {
@Override
public void storeComment(Comment comment) {
System.out.println("Storing comment: " + comment.getText());
}
}
Similary, we define an interfac for the second responsiblty the
onbjectds:
menting it n the
interfac.
Listing 4.4
CommentService
CommentNotificationProxyWe. defnitha isterfcmdhlas e pleproxies packge of the project. The fol wing listng presnts his
Define a CommentNotificationProxy interface
public interface CommentNotificationProxy {
void sendComment(Comment comment);
}
84
CHAPTER 4
The Spring context: Using abstractions
In the next lisng, you find the implementaion for this nterfac, which we’l use in
ourdemonstraion.
Listing 4.5
Implement ation of t he CommentNotificationProxy int erface
public class EmailCommentNotificationProxy
implements CommentNotificationProxy {
@Override
public void sendComment(Comment comment) {
System.out.println("Sending notification for comment: "
+ comment.getText());
}
}
We can now implement he object islf with the two depndencies of the
Serviceob(tjehc
pweservicakg,wrthie
Listing 4.6
CommentRepository andthe
CommentServicepasrencl tedinhfole winlst g .
CommentCommentNotificationProxy In). the
Implement ing t he CommentService object
public class CommentService {
We define the two dependencies
as attributes of the class.
private final CommentRepository commentRepository;
private final CommentNotificationProxy commentNotificationProxy;
public CommentService(
CommentRepository commentRepository,
CommentNotificationProxy commentNotificationProxy) {
this.commentRepository = commentRepository;
this.commentNotificationProxy = commentNotificationProxy;
}
public void publishComment(Comment comment) {
commentRepository.storeComment(comment);
commentNotificationProxy.sendComment(comment);
}
}
Let’s now write a
design.
We implement the use case that
delegates the “ store comment” and
“ send notification” responsibilities
to the dependencies.
Main clas, presnted in the next lisng, and tes he whole cas
Listing 4.7
Calling t he use case in t he Main class
public class Main {
public static void main(String[] args) {
var commentRepository =
new DBCommentRepository();
var commentNotificationProxy =
new EmailCommentNotificationProxy();
We provide the
dependencies
when the object is
built through the
parameters of the
constructor.
Creates the instance for
the dependencies
Using dependency injection with abstractions
85
Creates the instance of the service
var commentService =
class and providing the dependencies
new CommentService(
commentRepository, commentNotificationProxy);
var comment = new Comment();
comment.setAuthor("Laurentiu");
comment.setText("Demo comment");
Creates an instance of comment to send as a
parameter to the publish comment use case
commentService.publishComment(comment);
Calls the publish comment use case
}
}
When run ni g this ap licaton, you’l observ the two lines in the console printed by
the
CommentRepository and the
snip etprsntshioutput:
CommentNotificationProxy objects. The next code
Storing comment: Demo comment
Sending notification for comment: Demo comment
4.2
Using dependency injection with abstractions
In this ecton, we ap ly the Spring framework over the clas design we implemented
in section 4.1 Using this example, we can discu how Spring manages depndency
ni jection when using abstrcions. This ubject is ential becaus in most projects,
you’l mi plement depndencies betwen objects using abstrcions. In chapter 3, we
discued epndencyinjection,andweused concretlas odeclarthevaribls
wherwewantedSpringtosehevalusofbeansfromitscontex.Butasyou’learn
inthischapter,S ingalsounderstandsabtrcions.
We’lstarbyad ingtheSpringdepndencyto urpoject,andthenwe’ldeci
whichoftheobjectsofhisap licatonnedtobemanagedbySpring.You’learnto
deci whichobjectsyounedtomakeSpringawareof.
We’l then adpt he project we implemented in section 4.1 to use Spring and its
depndenicy jetioncapbWeiltes. fo’l cuos ndiscunvariog usit aonths can
ap earwhenusingdepndencyinjectionwithabstrcions.Atthendofthesction,
wed’l iscumoore nthserotypane otai nYos. ufin’l dout
onlysteropean otai nyoucanuseandwhenyoushoulduseotheran otai ns.
4.2.1
Deciding which objects should be part of the Spring context
When we discued Spring in chapters 2 and 3, we focused on syntax, nd we di n’t
have usecatomiros methingyoucanfindinarel-worldscenario.This alo
whywedi n’tdiscuwhetheyrounedtoad anobjectoheSpringcontex.Based
on our discuon, you might hink you ned to ad al the ap objects in the Spring
contex,buthisnothecas.
Remember, you learned that he main reason to ad an object o the Spring contex is to alow Spring to control it and further augment it with functionalites the
@Componentnis othe
86
CHAPTER 4
The Spring context: Using abstractions
frameworkpoidv es.Sothedcisonshouldbeasyndbasedonthequestion,“Does
thisobjectnedtobemanagedbytheframework?”
nIt’s odt ifcutol answther qis uestionfor uscenr aioths, oe nSply rinfegatur
we use is the DI. In our case, we ned to ad the object to the Spring contex if it
either has a depndency we ned to inject from the contex or if t’s a depndency
itself.Lookingatourimplementaion,you’lobservthatheonlyobjecthatdoesn’t
hdave pendenacy dasloinodat epndenitslfcy
ourclasdeignaresfol ws:
CommentTh. oe thoer binjcts
CommentService —Has two depndencies, the
CommentNotificationProxy
DBCommentRepository —Implements he
depndencyofthe
CommentService
EmailCommentNotificationProxy —Implements the
Proxy interfacndisa epndency ofthe
But why not ad the
Comment instances a wel? I’m often asked this question when I
teach Spring course. Adding objects to the Spring contex without neding the
framewotrkmanthage mad us n ecosary mptolexiy uapr ma, kinthg ape
both more chalenging to maintain and sle perfomant. When you ad an object o
thSpe rincog nteyxo, ualowthframe ewotrk manwiiatge thsomspe cfiunctionality he framework proivdes. If you ad the object o be managed by Spring without
getinag by enfroti mthframe ewoyrk, uj ost ver-ngi eryouimr plementaion.
In chapter 2, we discued that using steroype an otai ns (
most comfortable way to ad beans to the Spring contex when the clas beol ng to
yourpoject,andyoucanchangethem.We’lusethisap roach eraswel.
Observ tha the two interfacs in figure 4.8 remain white (we don’t mark them
with
@Component ). I often se tudents confused about wher they should use the streotype an otai ns when they also use interfacs in their mplementaions. We use
steroype an otai ns for the clase that Spring neds to creat instances and ad
thes instances to iscontex. I doesn’t make sne to ad steroype an otai ns on
interfacs or abstrc clase becaus thes cna ot be instantiaed. Syntcaily, you
candothis,butisnotusef l.
Let’s change the codeandad the
fol wni glsting,youfindthec angeforthe
Listing 4.8
CommentRepository and the
CommentRepository interfac nd is a
CommentNotificationCommentService
@Component ) is the
@Component an otai nto hes cla. In the
DBCommentRepository clas.
Adding @Component t o t he DBCommentRepository class
@Component
public class DBCommentRepository implements CommentRepository {
@Override
public void storeComment(Comment comment) {
System.out.println("Storing comment: " + comment.getText());
}
}
Marking
the class with
@Component
instructs Spring
to instantiate the
class and add an
instance as a bean
in its context.
Using dependency injection with abstractions
87
Interfaces are abstract.
We never use stereotype
annotations on interfaces.
CommentRepository
<<interface>>
storeComment()
Uses
Implements
CommentService
DBCommentRepository
publishComment()
storeComment()
Uses
CommentNotificationProxy
<<interface>>
sendComment()
Implements
EmailCommentNotificationProxy
sendComment()
We use stereotype annotations
for these classes.
Figure 4.8 The classes we’ll mark wit h the @Component st ereot ype annot at ion are shaded gray. When the
context is loaded, Spring creat es instances of these classes and adds them t o its context .
Inthlis yoextfung, thdc eanthforges
EmailCommentNotificationProxyclas.
Listing 4.9
Adding @Component t o t he EmailCommentNotificationProxy class
@Component
public class EmailCommentNotificationProxy
implements CommentNotificationProxy {
@Override
public void sendComment(Comment comment) {
System.out.println(
"Sending notification for comment: " +
88
CHAPTER 4
The Spring context: Using abstractions
comment.getText());
}
}
In the next lisng, we change the
@Component . The
compone ts hrough the interfacs
Proxy .Springsetheatributesardefinedwithinterfacypesandismartenough
tosearchinitscontexforbeanscreatdwithclasethaimplementhesinterfacs.
As we discued in chapter 2, becaus we have only one construcor ni the clas, the
@Autowired an otai nisoptional.
Listing 4.10
CommentService clas wel by an otaing it with
CommentService clas declars the depndencies to the other two
CommentRepository and
CommentNotification-
Making t he CommentService class a component
@Component
public class CommentService {
Spring creates a bean of this class and adds it to its context.
private final CommentRepository commentRepository;
private final CommentNotificationProxy commentNotificationProxy;
We would have to use @Autowired if the class had more than one constructor.
public CommentService(
CommentRepository commentRepository,
CommentNotificationProxy commentNotificationProxy) {
this.commentRepository = commentRepository;
this.commentNotificationProxy = commentNotificationProxy;
}
public void publishComment(Comment comment) {
commentRepository.storeComment(comment);
commentNotificationProxy.sendComment(comment);
}
Spring uses
this constructor
to create the
bean and injects
references from
its context in the
parameters when
creating the
instance.
}
WeonlynedtoelSpringwhertofindtheclas n otaedwithsteroypean otaions and tes the ap . The next listng presnts the project’s configuraton clas
wher we use the
an otaedwith
Listing 4.11
@ComponentScan an otai n to tel Spring wher to find the clas
@Component .Wediscued
@ComponentScan inchapter2.
Using @ComponentScan in t he configurat ion class
The @Configuration annotation
marks the configuration class.
We use the @ComponentScan annotation to tell Spring in which
packages to search for the classes annotated with stereotype annotations. Observe that the model package is not specified because it
doesn’t contain classes annotated with stereotype annotations.
@Configuration
@ComponentScan(
basePackages = {"proxies", "services", "repositories"}
)
public class ProjectConfiguration {
}
Using dependency injection with abstractions
NOTE
In th is e x am p le, I us e th e
basePackages atribute of the
89
@Component-
Scanan otai nSp. rinalsothgferuodefspirctly nthgclase
(by using the
basePackageClasses atribute of the same an otai n). The
advntagoe df ein tghpe ackgtihs aytouonhly avteomentionthpe ackage name. In case it contains 20 compone t clase, you write only one line
(the name of the packge) instead of 20. The disa vntage is tha if a devloprenamthes pthackge, miy ghnt ohrealizts y toavechanthge
va lu e of th e
@ComponentScan an otai n.Mentioni gtheclasdirectly,ou
mighwrt moite bre, uwht ensomeonche angthes codthe, imy mediasetly
theyalsonedtochangethe
@ComponentScan an otai n;otherwise,theap
doesn’t compile. In a production ap licaton, you might find both approaches,and,inmyexprince,oneisnotberhantheother.
Tootesur npacetl’s,wmainmethodpas,rentedinthfoe l winlstg .
Weps’l inthSpe rincog ngtraebx, hbe anotypf e
the
publishComment(Comment comment) method.
Listing 4.12
CommentServiceouoanti,f dcal
The Main class
public class Main {
public static void main(String[] args) {
var context =
new AnnotationConfigApplicationContext(
ProjectConfiguration.class);
var comment = new Comment();
comment.setAuthor("Laurentiu");
comment.setText("Demo comment");
var commentService = context.getBean(CommentService.class);
commentService.publishComment(comment);
}
}
Run ing the ap licaton, you’l observ the output presnted in the fol wing code
snip et, which demonstrae hat he two depndencies were acsed and coretly
caledbythe
CommentService object:
Storing comment: Demo comment
Sending notification for comment: Demo comment
It’s a mal exmple, and it might not l ok lie Spring improves a lot he xperince,
but lo k agin. By using the DI featur, we don’t crea he instance of the
Service object and its depndencies ourselv, and we don’t ned to explicty make
the rlationship betwen them. In a rel-world scenario, wher you have more than
threclas,tingSpringmanagetheobjectsand epndenciesamongthemrealy
makes a difernce. It eliminates code that can be implied (whic devlopers also
Comment-
90
CHAPTER 4
The Spring context: Using abstractions
name boilerpat code), which alows you to focus on what the ap licaton does. And
remember that d ing thes instances to the contex nables Spring to control and
augmenthemwithfeaturshatwe’ldiscunthenextchapters.
Different ways of using dependency injection wit h abst ract ion
In chapter 3, you’ve learned multiple ways you can use auto-wiring. We discussed the
@Autowired annotation, through which you can make field, constructor, or setter
injection. We also discussed using auto-wiring within the configuration class using
the parameters of the methods annotated with @Bean (which Spring uses to create
beans in the context).
Of course, in the current section, I started with the most used approach in real-world
examples, constructor injection. But I consider it essential for you to be aware of
different approaches that you might encounter as well. In this sidebar, I’d like to
highlight that DI with abstractions (as you saw in this section) works the same with
all the DI fashions you learned in chapter 3. To prove this, let’s try to change project
“ sq-ch4-ex2” and make it first use field dependency injection with @Autowired. We
can then change the project again and test how DI with abstraction works if we use
@Bean methods in the configuration class.
To keep all the steps we work on, I’ll create a new project named “ sq-ch4-ex3” for
the first demonstration. Fortunately, the only thing we need to change is the
CommentService class. We remove the constructor and mark the fields of the class
with the @Autowired annotation, as presented by the next code snippet:
@Component
public class CommentService {
@Autowired
private CommentRepository commentRepository;
@Autowired
private CommentNotificationProxy commentNotificationProxy;
public void publishComment(Comment comment) {
commentRepository.storeComment(comment);
commentNotificationProxy.sendComment(comment);
}
}
Fields are no longer final, and they are marked with @Autowired.
Spring uses the default constructor to create the instance of the
class and then injects the two dependencies from its context.
As you probably expect now, you can use auto-wiring through the parameters of the
@Bean annotated methods with abstractions as well. I have separated these
examples in the project “ sq-ch4-ex4.” In this project, I completely removed the
stereotype annotation (@Component) of the CommentService class and its two
dependencies.
Using dependency injection with abstractions
91
Further, I changed the configuration class to create these beans and establish the
relationships among them. The next code snippet shows the new look of the configuration class:
@Configuration
public class ProjectConfiguration {
Because we don’t use stereotype
annotations, we no longer need to use
the @ComponentScan annotation.
@Bean
public CommentRepository commentRepository() {
return new DBCommentRepository();
}
We create a bean
for each of the two
dependencies.
@Bean
public CommentNotificationProxy commentNotificationProxy() {
return new EmailCommentNotificationProxy();
}
@Bean
public CommentService commentService(
CommentRepository commentRepository,
CommentNotificationProxy commentNotificationProxy) {
return new CommentService(commentRepository,
commentNotificationProxy);
}
We use parameters of the @Bean method (which are now defined with
the interface type) to instruct Spring to provide references for beans
from its context, compatible with the type of the parameters.
}
4.2.2
Choosing what to auto-wire from multiple implementations of an abstraction
Thus far, we have focused on Spring’s behavior when using DI with abstrcions. But
weusedanexampleinwhichwemadesurtoad onlyoneinstanceforahkindof
abstrcionwerequestdforinjection.
Let’s go ne stp further and discu what hap ens if the Spring contex conitans
more instancesthat match arequestdabstrcion.This cenario cn hap enin realworld projects, and you ned to know how to handle thes case to make your ap
workasexpctd.
Sup ose we have two beans creatd with two difernt clase tha implement he
CommentNotificationProxy interfac (figure 4.9) Fortunately for us, Spring use a
mechanism for deci ng which bean to cho se that we discued in chapter 3. In
chapter 3, you learned tha if more than one bean of the same type exist in the
Spring contex, you ned to tel Spring which of thes beans to inject. You also
learnedthefol wingap roaches:
Usinthg e
thedfault
Using the
nameforDI
@Primaryan otai ntomaork noethf be anfos imr plementaionas
@Qualifier an otai n to name a bean and then ref to it by its
92
CHAPTER 4
The Spring context: Using abstractions
When CommentService requests a dependency
of the type CommentNotificationProxy, Spring
needs to decide which of the multiple existing
implementations it should choose to inject.
CommentService
CommentNotificationProxy
<<interface>>
Uses
publishComment()
sendComment()
Implements
Implements
CommentPushNotificationProxy
EmailCommentNotificationProxy
sendComment()
sendComment()
Both classes implement the same interface.
Figure 4.9 Sometimes, in real-world scenarios, we have multiple implementat ions of t he same int erface.
When using dependency injection on t he int erface, you need t o instruct Spring which is t he implement at ion
it should inject .
Now we want now to prove tha thes two ap roaches work with abstrcions a wel.
CommentPushNotificationProxy (whic implements the
Let’s ad a new clas,
CommentNotificationProxy interfac), to our ap licaton and tes the ap roaches
one by one, as shown in the fol wing listng. To kep the examples separtd, I
creatdanewprojectnamed“sq-ch4-ex5.”Istardthisexamplewiththecodeinthe
project“sq-h4-ex2.”
Listing 4.13
A new implement at ion of t he CommentNotificationProxy interface
@Component
public class CommentPushNotificationProxy
implements CommentNotificationProxy {
@Override
public void sendComment(Comment comment) {
System.out.println(
"Sending push notification for comment: "
+ comment.getText());
}
}
The class implements the
CommentNotificationProxy interface
Using dependency injection with abstractions
93
If you run this ap licaton as-i, oy u’l get an excption becaus Spring doesn’t know
whichothf we obeanis cot ntoex cho fose inr jectionhI. eaxtvrcdhmoe st
intersing part of the excption mesage in the next code snip et. The excption
cleary stae the problem Spring encounters. As you can se, it’s a
DefinitionExceptionwith mee s“eagxpctdsinmagle tchinbg ufot undTh2.” is
ishowtheframeworktelsuitnedsguidancergadingthexistngbeansithould
injectfromthecontex:
NoUniqueBean-
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'proxies.CommentNotificationProxy' available:
expected single matching bean but found 2:
commentPushNotificationProxy,emailCommentNotificationProxy
M ARKING AN IMPLEMENTATION AS DEFAULT FOR INJECTION WITH @PRIMARY
The first olution is using
@Primary . The only thing you ned to do is ad
nearthe
@Component an otai ntomarktheimplementaionprovide bythiscla
@Primary
thedfaultorimplementoai n,ashowninthefol winglistng.
Listing 4.14
Using @Primary t o mark t he implement at ion as default
@Component
@Primary
public class CommentPushNotificationProxy
implements CommentNotificationProxy {
Using @Primary, we mark this
implementation as a default
for dependency injection.
@Override
public void sendComment(Comment comment) {
System.out.println(
"Sending push notification for comment: "
+ comment.getText());
}
}
With just his mal change, your ap has more findly output, as presnted in the
nextcodesnip et.ObservthatSpringinde injectdheimplementaionprovide
bythenwlycreatdls:
Storing comment: Demo comment
Sending push notification for comment: Demo comment
Thqe uestionuI s haly t er mois men“Nis,t owwehtwave oimplementaionbs, ut
Springwilawaysinjectonlyoneofthem?Whyhavebothclaseinthiscae?”
Let’sdiscu howyoucangetintosuchasituaoninarel-worldscenario.Asyou
alredwy apre, coraesmpanlex dupse lnotydf epndenpIt’scie. osibthle a,
at some point, you use a depndency that provides an implementaion for a specif
Spring injected the new
implementation because
we marked it as primary.
94
CHAPTER 4
The Spring context: Using abstractions
You need to create a custom implementation
for the interface defined by the dependency.
But you also need to mark it as primary so
that when you use DI, Spring injects your
custom implementation and not the one
provided by the dependency.
Your app
Some dependency
@Primary
CustomImplementation
Implements
<<interface>>
Uses
Implements
Implementation
Your application has a dependency.
This dependency defines an interface
as well as an implementation for that
interface.
Figure 4.10 Sometimes you use dependencies that already provide implement ations for specific
int erfaces. When you need t o have cust om implementat ions of t hose int erfaces, you can use
@Primary t o mark your implementat ion as a default for DI. This way, Spring knows to inject t he
implement at ion you define and not t he one provided by t he dependency.
interfac(igure4.10),butheprovide impelmentaionisnotsuitablefory urap ,
and you cho se to defin your custom implementaion. Then
plestoution.
@Primary is your sim-
NAMING IMPLEMENTATION FOR DEPENDENCY INJECTION WITH @QUALIFIER
Sometimes, in production ap s, you ned to define more implementaions of the
same interfac, nd difernt objects use thes implementaions. Imagine we ned to
havetwoimplementaionsforc mmentnotifca n:byemailorbypushnotifca n
(figure 4.1) Thes ar til mplementaions of the same interfac, but hey depnd
ondiferntobjectsinheap .
Let’s change the code to tes hsi ap roach. You cna find this mpeml entaoi n in
theproject“sq-h4-ex6.”Thefol wincog desnip etshowyouhowtousethe
ifier an otai ntonamespcifmplementoai ns.
@Qual-
Using dependency injection with abstractions
95
This service needs to use the implementation
that sends the notification by email.
More objects declare the dependency on
the CommentNotificationProxy interface.
CommentService
@Qualifier(" EMAIL" )
Uses
CommentNotificationProxy
<<interface>>
Uses
AnotherService
@Qualifier(" PUSH" )
sendComment()
Implements
Implements
@Qualifier(" PUSH" )
CommentPushNotificationProxy
sendComment()
@Qualifier(" EMAIL" )
EmailCommentNotificationProxy
sendComment()
This service needs to use the implementation
that sends the notification by push notifications.
Both classes implement the same interface.
Figure 4.11 If different object s need t o use different implement at ions of the same cont ract , we can use
@Qualifier t o name t hem and tell Spring where and what it needs to inject .
The
CommentPushNotification clas:
@Component
@Qualifier("PUSH")
public class CommentPushNotificationProxy
implements CommentNotificationProxy {
// Omitted code
}
The
Using @Qualifier, we name
this implementation “ PUSH.”
EmailCommentNotificationProxy cla:s
@Component
@Qualifier("EMAIL")
public class EmailCommentNotificationProxy
implements CommentNotificationProxy {
// Omitted code
}
WhenyouwanSpt rni tog inoject noe thf es,youj nst edtospthecify mplementation’s name using the
how to inject a specif impelmentaion as a depndency of the
object.
Using @Qualifier, we name this
implementation “ EMAIL.”
@Qualifier an otai n agin. In the next lisng, you find out
CommentService
96
CHAPTER 4
Listing 4.15
The Spring context: Using abstractions
Specifying the implement at ion Spring needs t o inject wit h @Qualifier
For each parameter where we want to use a specific
implementation, we annotate the parameter with @Qualifier.
@Component
public class CommentService {
private final CommentRepository commentRepository;
private final CommentNotificationProxy commentNotificationProxy;
public CommentService(
CommentRepository commentRepository,
@Qualifier("PUSH") CommentNotificationProxy commentNotificationProxy) {
this.commentRepository = commentRepository;
this.commentNotificationProxy = commentNotificationProxy;
}
// Omitted code
}
Sprni g tjhecs depndenyoc uspecifdusing
Observtheoutputintheconsole:
@Qualifier whenyour nthape .
Observe that Spring injected
the implementation for push
notifications.
Storing comment: Demo comment
Sending push notification for comment: Demo comment
4.3
Focusing on object responsibilities with stereotype annotations
Thus far, when discung steroype an otai ns, we have only used
our examples. But with real-world implementaions, you’l find out that devlopers
sometimes ues other an otai ns for the same purpose. In this ecton, lI’ show you
howtousetwomorestoypean otai ns:
In real-world project,s i’ a common practie o define the component’s purpose
usingthe stroype an otai n explicty. Using
no detail bout he rsponsiblty of the object you’re implementing. But devlopers
genraly use objects with some known responsiblte. Two of the rsponsiblte we
discuedinsection4.1arethesrvicandtherposit ry.
The srvic a the objects with the rsponsiblty of implementi g the use ca,
whrepil othsare ibmajects naginthdpeatrsinBece. authresponsibolarte c mmoni projeancts, dthimarey portani thcdlase ignh, aving
distnawamaocivef y rkinthgemhtelpdsvoubpentr derstanhpde sign.
Spring ofers us the
responsibltyofaservicndthe
implemenrpa ots irepy onsib(fguAllt4.y12)re hl( re
and
@Repositorysteroa )ypne otai na s dinstruSpc rintaoceg da dan
instanceofthean otaedclsoit ntex.
@Component in
@Service and
@Repository .
@Component is genric and gives you
@Service an otai n to mark a component tha takes the
@Repository an otai ntomarkacomponenthat
@Component , @Service,
Focusing on object responsibilities with stereotype annotations
97
We use the @Repository annotation to
define DBCommentRepository as component
and also explicitly mark its responsibility.
We use the @Service annotation to
define CommentService as component
and also explicitly mark its responsibility.
CommentRepository
<<interface>>
storeComment()
Uses
Implements
@Service
@Repository
DBCommentRepository
CommentService
publishComment()
storeComment()
Uses
CommentNotificationProxy
<<interface>>
sendComment()
Implements
Where Spring doesn’t offer us a specific annotation
for that resposibility, we continue using @Component.
@Component
EmailCommentNotificationProxy
sendComment()
Figure 4.12 We use t he @Service and @Repository annot at ions to explicit ly mark t he responsibilities of
the component s in our class design. Where Spring doesn’t offer a specific annot at ion for t hat responsibility,
we cont inue t o use @Component .
In the examples in this chapter, you would mark the
@Serviceinsteadof
ity and make this aspect more visble for any devloper reading the clas. The next
codesnip etshowsthisclan otaedwith e
CommentService clas with
@ComponentTh. wais yo, uexpmalicty thrk oe brjspct’ onsibl-
@Service
public class CommentService {
// Omitted code
}
Similary, ou explicty mark the rposit ry clas’ reponsiblty using the
tory an otai n:
@Service steroypean otai n:
We use @Service to define this object as a
component having the responsibility of service.
@Reposi-
@Repository
public class DBCommentRepository implements CommentRepository {
// Omitted code
We use @Repository to define this object as a
}
component with the responsibility of the repository.
Youcanfindthisexample(“sq-ch4ex7”)intheprojectsprovide withthebo k.
98
CHAPTER 4
The Spring context: Using abstractions
Summary
Decoupling implementaions through abstrcions i a go d practie n implementing a clas design. Decoupling objects makes implementaions easy to
change without afecing to many parts of the ap licaton. This pa ect makes
yourap licatonmoreasilyxtnde andmaintained.
In Jav, we use interfacs to decouple implementaions. We also say that we
definecontracsbewenimplementaionsthroughinterfacs.
When uins g abstrcion with depndencyinjection, Spring knows to search for
abencreatdwithanimplementaionoftherquestdabstrcion.
You use steroype an otai ns on clase for which Spring neds to creat
instances and ad thes instances a beans to its contex. You nevr use trotypean otai nsoninterfacs.
When the Spring contex has more beans creatd with multipe implementationsofthesameabstrcion,toinstrucSpringwhichbeantoinject,youcan
– usethe
@Primary an otai ntomarkoneofthemasdefult,or
– uthse
@Qualifieran otai ntonamthe bean dtheni struSpc rintog
injecthatbenbyname.
When we have sric esponsiblty compone ts, we use the
@Component Li. kewise,whenacompone tharespostypean otai ni steadof
itory responsiblty, we use the
@Repository steroype an otai n instead of
@Component . This way, we mark the compone t’s responsiblty explicty, and
wemaketheclasdignmorecomfortableoradndunderstand.
@Service stero-
Beanscopdlify
TheSpringcotx:
This chapter covers
Using the singleton bean scope
Using eager and lazy instantiation for singleton
beans
Using the prototype bean scope
Thusfarwehavediscuedsveralntialhingsaboutobjectinstancesmanaged
by Spring (beans). We coverd the important syntaxes you ned to know to creta
beans, and we discued establihing lraetionships among beans (including the
necsity of using ba strcions). But we di n’t focus on how and when Spring createshebans.Fromthispers ctiv,we’veonlyreidontheframework’sdefault
ap roaches.
I chose not o discu this apect earli n the bo k becaus I wanted you to
focus on the syntaxes you’l ned up-front in your projects. Howevr, production
ap s’ scenarios are complex, and sometimes relying on the framework’s deufa lt
behaviorsnot enough.Forthisreaon,inthischapterwenedtog abitdepr
withourdiscuononhowSpringmanagesthebansintscontex.
99
100
CHAPTER 5
The Spring context: Bean scopes and life cycle
Spring has multpi e difernt ap roaches for ceanti g beans and managing their
ancyle,if dinthSpe rinwog rldwenamthe aps rocahInseop. thcis apweter,
discutwosc pesyou’loftenfindinSpringap nsigle:otandprotye.
NOTE
Later, in chapter 9, we discu thre more bean scopes that ap ly to
webap licatons:request,ion,a dap licaton.
Singletonthis de fauscolt poebafni Sprinag, dwhit’s weat b’ve nusinug pto
now. In section 5.1, we discu the singleton bean scope. We’l deal first with how
Spring manages ingleton beans and then discu esntial hings you ned to know
about singthesingletonscopeinreal-worldap s.
Insection5.2,wecontinue bydiscungtheprot ypebanscope.Ourfocuswil
beonhowtheprot ypescopeisdferntfromsingletonandreal-worldsituaonsi
whichyou’dnedtoap lyoneoranother.
5.1
Using the singleton bean scope
The sineglton bean scope defines Spring’s defautl ap roach for managni the beans
initscontex.Iisalohebanscopeyou’lmostencounterinproducoti nap s.
In section 5.1, we star our discuon by learni g how Spring creats nd mansinage ltonbeanwhs, ichesnfotialur nderstandinwhg yoer ushoulduthse m.
For this purpose, we’l take two examples that employ the difernt ap roaches you
canusetodefinebans(whichyoulearnedinchapter2)andanalyzeSpring’sbehavior for thes beans. We’l then discu (in section 5.12) the crital spect of using
singleton beans in real-world scenarios. We end this ecton by discung two singletonbeani stantiaonap roach(aensgr dlazny) dwhyeor ushoulduthse min
productionap s.
5.1.1
How singleton beans work
Let’s ar with Spring’s behavior for managing singleton-scoped beans. You ned to
knowwhatoexpctwhenusingthiscope,s cialybeusingletonisthedufa lt
(and the most used) bean scope in Spring. In this section, I’l describ the link
betwenthecodeyouwriteandtheSpringcontexomakeSpring’sbehavioresyto
understand.We’lthenteshebhaviorwithacoupleofxamples.
Spring creats singleton bean when it loads the contex and asigns the bean a
name(sometimesalorfedtoasbenID).Wenamethiscopesingletonbecaus
youalwthgeays mine tsanwhce enyoutorefspa bci eanBu. btcarefuYol! u
can have more instances of the same type in the Spring contex if hey have difernt
names. I highlight his apect becaus you might be aware of and have posibly used
the“singleton”designpaterninthepast.Ifyoudon’tknowtheisngletondesignpattern,youarenotsuceptibleoc nfusionandyoucanskipthefol wingpar h.
But if you know what singleton patern is, the way it works in Spring might lo k
stranogey ubecauyos uhoave noly nie stanocetypaf inthape F.oSpr inthg, e
singleton concept alows multipe instances of the same type, and singleton means
uniqueprnamebutnotuniquepra p(figure5.1)
Using the singleton bean scope
Singleton pattern
versus
With a class designed as a standard singleton,
you may have only one instance of a specific
class in the app’s memory.
App’s memory
101
Spring’s singleton scope
However, in Spring, singleton means the
same instance for a unique name. You
can have multiple instances of the same
class in Spring’s context if the instances
have different names.
Spring context
commentService1
commentService
commentService2
public class CommentService {
@Configuration
public class ProjectConfig {
public static CommentService getInstance() {
if (instanceHasNotYetBeenCreated()) {
createCommentServiceInstance();
}
@Bean
public CommentService commentService1() {
return new CommentService();
}
return commentService;
}
@Bean
public CommentService commentService2() {
return new CommentService();
}
}
}
With singleton pattern, the class manages
the instance creation and makes sure
only one instance of a type is created.
With Spring, you can define as many beans
of the same type using methods annotated
with @Bean in the configuration class.
Each of these beans is a singleton.
Figure 5.1 When one refers t o a singlet on class in an app, t hey mean a class t hat offers only one inst ance
to t he app and manages the creation of t hat inst ance. In Spring, however, singlet on doesn’t mean t he context
has only one inst ance of t hat type. It just means t hat a name is assigned t o the instance, and t he same
inst ance will always be referred t hrough that name.
DECLARING SINGLETON-SCOPED BEANS WITH @BEAN
Let’sdemonstraeingletonbean’sbehaviorwithanexampleusingthe
taion to ad an instance to the Spring contex and then simply ref to it multipe
timines maa inclaWes. dothois proweve gthe samine stanecvtirymwee ref
toheban.
@Bean an o-
102
CHAPTER 5
The Spring context: Bean scopes and life cycle
Spring context
@Configuration
public class ProjectConfig {
commentService
Adds the bean
@Bean
public CommentService commentService () {
return new CommentService();
}
}
public class Main {
Creates the context
public static void main(String[] args) {
var c = new AnnotationConfigApplicationContext(ProjectConfig.class);
Gets the
bean
Gets the
bean
var cs1 = c.getBean("commentService", CommentService.class);
var cs2 = c.getBean("commentService", CommentService.class);
boolean b1 = cs1 == cs2;
System.out.println(b1);
}
}
These two lines refer to the same bean in the context.
The two variables cs1 and cs2 contain a reference to
the same object instance. This is the reason b1 is true.
Figure 5.2 A singlet on bean. The app initializes t he cont ext when starting and adds a bean.
In t his case, we use the approach wit h t he @Bean annot ation t o declare the bean. The name
of t he met hod becomes the ident ifier of the bean. Wherever you use t hat identifier, you get a
reference t o the same inst ance.
Figure 5.2 si a vsiual repsntaion of the contex near the code tha configures it.
The cofe bean in the visual repsnts he instance that Spring ad s to its contex.
Observ that he contex contains only one instance (ofe ban) with an asocited
name. As we discued in chapter 2, when using the
ad a bean to the contex, the name of the method an otaed with
theban’sname.
In this example, I used the
@Bean an otai n ap roach to ad the bean to the
Sprni g contex. But I don’t want you to thni k a sineglton bean can onyl be creatd
using the
@Bean an otai n. The rsult would have ben the same if we used sterotypane otai n(likse
@Component to) ad thbe antohcoe nteWex. d’l emonstrae
thisfactwithhenxteample.
Also,notehatI’vexplcityusedthebannamewhengetingthebanfromthe
Spring contex in this demonstraion. You learned in chapter 2 that when you have
only one bean of a kind in the Spring contex, you no longer ned to use it name.
You can get hat bean by its pe. In this example, I used the name simply to enforce
@Bean an otai n ap roach to
@Bean becomes
Using the singleton bean scope
thwea reftohsame be anAs. wediscuedinchapcoI2,teruldhajvue rsftd
to the type, and in both case wher we get he bean from the contex we would get
th e r f n ce to h e sam e (a n d o nly )in sta n ce o f
Lewrt’s thie codane drunit toc ncludthe xamis pYole. ucanfi dthexamis ple
inthpe ronject amed“sq-chWe5-ex1.” nedto efinae mpty
aspresnted inthe next codesnip et. You then write heconfiguraton clas nd the
mainclas,prens tedinfigure5.2:
103
CommentService inthecontex.
CommentServiceclas,
public class CommentService {
}
In the next lisng, you find the configuraton clas defintion, which use a method
an otaed with
contex.
Listing 5.1
@Bean to ad an instance of type
CommentService to the Spring
Adding a bean t o t he Spring cont ext
@Configuration
public class ProjectConfig {
@Bean
public CommentService commentService() {
return new CommentService();
}
Adds the CommentService bean
to the Spring context
}
In th e n e xt lis n g , yo u fin d th e
gleton bean. We get he rfnce to the
togehesamerfnceahtime.
Main clasweusetosSpring’sbehaviorf oursinCommentService bean twice, and we expct
Listing 5.2
The Main class used t o t est Spring’s behavior for the singlet on bean
public class Main {
public static void main(String[] args) {
var c = new AnnotationConfigApplicationContext(ProjectConfig.class);
var cs1 = c.getBean("commentService", CommentService.class);
var cs2 = c.getBean("commentService", CommentService.class);
boolean b1 = cs1 == cs2;
System.out.println(b1);
}
}
Run ing the ap wil print “true” in the console becaus, being a singleton bean,
Springretunsthesamerfncevrytime.
Because the two variables hold
the same reference, the result
of this operation is true.
104
CHAPTER 5
The Spring context: Bean scopes and life cycle
DECLARING SINGLETON BEANS USING STEREOTYPE ANNOTATIONS
As mentioned earli, Spring’s behavior for singleton beans in’t any difernt when
using steroype an otai ns than when you declar them with the
tion.Butinhisecton,I’dliketonforcethistaementwithanexample.
Consideraclsdesignscenariowhertwoservic la depndonareposit ry.
Say we have both
CommentService and
n am e d
CommentRepository, asprentedinfigure5.3
In a usual class design, service
classes implement use cases.
@Bean an ota-
UserService depnding on a reposit ry
A repository class takes care of
working with the persisted data.
@Service
CommentService
Uses
@Repository
CommentRepository
@Service
Uses
UserService
In this scenario, we assume that the two
service classes depend on a repository to
implement their use cases.
Figure 5.3 A scenario class design. Two service classes depend on a reposit ory t o
implement t heir use cases. When designed as singleton beans, Spring’s context will
have one instance of each of these classes.
The rason thes cla re depndent on one another isn’t important, and our sevices won’t do anything (it’s just a scenario). We asume this cla design is part of a
more complicated ap , and we focus on the relationship betwen beans and how
Spring establihes the links in its contex. Figure 5.4 is a visual repsntaion of the
contexnearthecodethaconfigurest.
Let’s prove this behavior by creating the thre clase and comparing the refences Spring injects in the servic beans. Spring injects the same refnce in both
servic beans. In the fol wing code snip et, you find the definton of the
Repository clas(project“sq-h5-ex2”):
@Repository
public class CommentRepository {
}
Comment-
Using the singleton bean scope
105
Because of the @Repository stereotype annotation,
Spring adds a bean of type CommentRepository
to its context. By default the bean is singleton, so
Spring creates one instance and assignes a name to it.
When using stereotype annotations, the name of the
class becomes the name of the bean.
Adds the bean
@Repository
public class CommentRepository {
}
Spring context
commentRepository
Adds the bean
@Service
public class CommentService {
Gets the bean
@Autowired
private CommentRepository repo;
commentService
}
Adds the bean
userService
@Service
public class UserService {
Gets the bean
@Autowired
private CommentRepository repo;
}
Both service classes use @Autowired to
request Spring to inject a bean of type
CommentRepository. In both cases, Spring
will inject the reference to only the instance
in its context. Both services now refer to
the same instance of CommentRepository.
Figure 5.4 The beans are also singleton-scoped when using stereot ype annotat ions t o
creat e t hem. When using @Autowired t o request Spring t o inject a bean reference, t he
framework inject s t he reference t o the singleton bean in all t he request ed places.
The next code snip et presnts he defintion of the
th at I u se d
@Autowired to instruc Spring to inject an instance of type
Repository inanatributedclare intheclas.IodefinedagetrmethodthatI
intend to use latr o prove Spring ni jects he same object rfenc in both sercvi
beans:
@Service
public class CommentService {
@Autowired
private CommentRepository commentRepository;
CommentService clas. Observ
Comment-
106
CHAPTER 5
The Spring context: Bean scopes and life cycle
public CommentRepository getCommentRepository() {
return commentRepository;
}
}
Fol wingthesamelogicf r
n ex tc o de sn ip et:
CommentService ,the
UserService clasidefnedinthe
@Service
public class UserService {
@Autowired
private CommentRepository commentRepository;
public CommentRepository getCommentRepository() {
return commentRepository;
}
}
Unlike thefrist xample in this ecton,theconfiguraton clasremainsemptyin this
project. We only ned to tel Spring wher to find the clas n otaed with sterotype an otai ns. As discued in chapter 2, o tel Spring wher to find clase n otaed with steroype an otai ns we use the
definot noftheconfiguratonclasinthenxtcodesnip et:
@ComponentScan an otai n. The
@Configuration
@ComponentScan(basePackages = {"services", "repositories"})
public class ProjectConfig {
}
In the
Main clas, we get the refnces for the two servic, and we compare their
depndencies to prove tha Spring injectd the same instance in both. The fol wing
listngpresntshemainclas.
Listing 5.3
Test ing Spring’s behavior for inject ing t he singlet on bean in t he Main class
Creates the Spring context based
on the configuration class
public class Main {
public static void main(String[] args) {
var c = new AnnotationConfigApplicationContext(
ProjectConfig.class);
var s1 = c.getBean(CommentService.class);
var s2 = c.getBean(UserService.class);
Gets the references of
the two service beans in
the Spring context
Compares the references for
the repository dependency
injected by Spring
boolean b =
s1.getCommentRepository() == s2.getCommentRepository();
Using the singleton bean scope
System.out.println(b);
}
}
5.1.2
107
Because the dependency (CommentRepository)
is singleton, both services contain the same
reference, so this line always prints “ true.”
Singleton beans in real-world scenarios
Thufaswer ’vde iscuedhowSprinmag nagseingletonbeanIst.’imtoe als discu
thingsyounedtobeawareofwhen workingwithsingletonbeans.Let’sar byconsiderngsomescnarioswheryoushouldorshouldn’tuseingletonbeans.
Becaues the singleton bean scope asumes tha multipe compone ts of the ap
cansharenobjectinstance,themostimpoanrt thingtoc nsiderthathesbans
mubst ime mutableMo. ost fenra,l-worldap excutasionos nmultipehrda s
(e.g, any web ap ). In such a scenario, multipe threads share the same object
instance.Ifthes threadschangetheinstance,youencounterac-ondi senario
(figure5.)
A race conditon is a situaon that can hap en in multihread architecurs
when multipe threads try to change a shared resource. In case of a race onditon,
the devloper neds to properly snchronize the threads to avoid unexpctd excutionresultor eros.
Ifyouwantmutableins gletonbeans(whoseatributeschange),younedtomake
thbesancosncurenbyot u(mrself ainbemly ployinthg readsynchronizatonBu). t
singletonbeanrs d’t esignedtobsyne chronizedTh. coey’r mmonuly sedto efine
an ap ’s bcak one clas design and delgat rsponsiblte one to another. Technisyncal, hronizatonpis oble,nuit’sgoa tdpSynractie. hroniznthg e rad
These arrows represent the execution timelines
of two different threads named T1 and T2.
Spring context
commentRepository
T1
T2
If the two threads try to simultaneously
access and change the same instance,
they run into a race condition.
Figure 5.5 When mult iple t hreads access a singlet on bean, t hey access the same inst ance. If these
threads t ry t o change t he inst ance simultaneously, t hey run into a race condition. The race condit ion
causes unexpected results or execut ion except ions if t he bean is not designed for concurrency.
108
CHAPTER 5
The Spring context: Bean scopes and life cycle
onca curenit sance dramthafecilyp p’s erfomanIce. mocase,t
youwilfindothermeansto lvethesameproblemandavoidthreadconcurency.
Do you remember our discuon in chapter 3, wher I told you tha construcor
DIgoais dpracntie dprefdoeldfivr njectionOn? oe thf ade vntaoges cf nstrucor injection is that it alows you to make the instance immutable (define the
bean’s fields a final).In our previous example,we can enhance the
clas’ defintion by replacing the fild injection with construcor injection. A betr
designoftheclaswouldo kliethefol wingcodesnip et:
@Service
public class CommentService {
private final CommentRepository commentRepository;
CommentService
Making the field final
highlights that this field was
intended not to be changed.
public CommentService(CommentRepository commentRepository) {
this.commentRepository = commentRepository;
}
public CommentRepository getCommentRepository() {
return commentRepository;
}
}
Using beans boils down t o three points
Make an object bean in the Spring context only if you need Spring to manage it
so that the framework can augment that bean with a specific capability. If the
object doesn’t need any capability offered by the framework, you don’t need to
make it a bean.
If you need to make an object bean in the Spring context, it should be singleton
only if it’s immutable. Avoid designing mutable singleton beans.
If a bean needs to be mutable, an option could be to use the prototype scope,
which we discuss in section 5.2.
5.1.3
Using eager and lazy instantiation
Inmostcae,Springcreatslingletonbeanswhenitnitalzehs econtex—this
Spring’s default behavior. We’ve used only this default behavior, which is alo caled
eagr instao. In this section, we discu a difernt ap roach of the framework,
lazy inasto, and compare thes two ap roaches. With lazy instantiaon, Spring
doesn’t crea the singleton instances when it creas the contex. Instead, it creas
each instance the fitrs time someone refs to the bean. Let’s take an example to
observ the difernce betwen the ap roaches and then discu the advntages nd
disa vntagesofusingtheminproductionap s.
Inouinr sctienal riowe, only edba entoehs defau(ltginr) tialzon
(pro“jecstq-h5-ex3”)k.I’lpthne amingswe’bve nusing,a dI’nl amethclais
Using the singleton bean scope
109
CommentService . You make this clas a bean, either using the
@Bean an otai n
ap roachostear ypaen otai nI’adves, onie thne xcot dsne ip etBu. either
way, make sure to ad an output o the console in the clas’ construcor. This way,
wel’easyiobserviftheframeworkcalsit:
@Service
public class CommentService {
public CommentService() {
System.out.println("CommentService instance created!");
}
}
If you use a steropy e an otai n, don’t forget o ad the
tioni theconfiguratonacls.Myconfiguratonclasinthenxtcodesnip et:
@ComponentScan an ota-
@Configuration
@ComponentScan(basePackages = {"services"})
public class ProjectConfig {
}
Inthe
Main clas,weonlyinstantiaeheSpringcontex.Acritalspecto bservi
thatno neusthe
instance in the contex. We know tha Spring creats the instance becaus we’l se
the output from the
Thenxtcodesnip etprsntshe
CommentService bean.Howevr,Spingwilcreatndstorehe
CommentService bean clas’ onstrucor when run ing the ap .
Main clas:
This app creates the Spring
context, but it doesn’t use the
CommentService bean anywhere.
public class Main {
public static void main(String[] args) {
var c = new AnnotationConfigApplicationContext(ProjectConfig.class);
}
}
Eveniftheap doesn’tusethebananywher,whenrun ingtheap you’lfindthe
fol wingoutputintheconsole:
CommentService instance created!
Now change the example (project “sq-ch5-ex4”) by ad ing the
abothve (foclastr py ane otai naps roacho)abr thve
the
@Bean methodap roachYo). uo’l btsehrv oe utpunt ol napger inears thcoe nsowhle enrun inthg ape becauwes instrucedSprintogcrhea beanonwhly en
someoneusit.And,inourexample,nobodyusethe
@Service
@Lazy
public class CommentService {
@Lazy an otai n
@Beanmethod(for
CommentService bean.
The @Lazy annotation tells Spring that it
needs to create the bean only when someone
refers to the bean for the first time.
110
CHAPTER 5
The Spring context: Bean scopes and life cycle
public CommentService() {
System.out.println("CommentService instance created!");
}
}
Changethe
inthenextcodesnip et:
Main clasnda darefncetohe
public class Main {
CommentService bean,asprented
At this line, where Spring needs to provide a
reference to the CommentService bean,
Spring also creates the instance.
public static void main(String[] args) {
var c = new AnnotationConfigApplicationContext(ProjectConfig.class);
System.out.println("Before retrieving the CommentService");
var service = c.getBean(CommentService.class);
System.out.println("After retrieving the CommentService");
}
}
Rerun the ap , and youl’ find the output agin in the console. The framework ceateshebanonlyift’sued:
Before retrieving the CommentService
CommentService instance created!
After retrieving the CommentService
Whenshouldyou ineagrs tntiaona dwhenshouldyou Inlazy?se mocaes,t
it’s more comfortable to let he framework ceat l the instances at he begin ing
when the contex is instantiaed (eagr); this way, when one instance delgtas to
another,thescondbeanlaredyxistna ysituaon.
In a lzy instantiaon, the framework has to first check if the insta ce xist and
evntualy cret i f it doesn’t, so from the perfomance point of view, it’s betr o
have the instances in the contex alredy (eagr) becaus it spare some checks the
framework neds to do when one bean delgats to another. Another advntage of
eagr instantiaon is when something is wrong and the framework can ot creat a
bean; we can observ this ue when starni g the ap . With lazy instantiaon, someonewouldobservthisuoe nlwhy enthape ailsredyxcutinag drietachesthe
pointhatheban edstobecratd.
But lazy instantion is not al evi. Some time ago, I worked on a vst monolithic
ap licaton. This ap was instaled ni difernt locati ns wher it was used in vaori us
scopes by its clents. In most cae, specif lnt di n’t use a big part of the functionality, so instantiang the beans toghe r with the Spring contex un ecsarily
ocupiedalot fmemory.F rthatp ,thedvlopersdignedmostofhebansto
belaziynstantiaedsothatheap wouldcreatonlythenecsaryinstances.
Using the prototype bean scope
111
My advice s to g with the default,which is an eagrinstantiaon. Thisap rocah
generaly brings more benfits. If you find yourself in a situaon like the one I
presnted with the monolithic ap , first e if you can do something about he ap ’s
design. Often, the ned for using lazy instaniaton is a sign something might be
wronwig th ape d’s eignF.oexamr pinle, mystowoiry, uldhbave nbtheifr
ap had ben designed in a modular way or as microsevi. Such an architecur
wouldhavehelpdthedevlopersdeploy nlywhatspeciflntsned ,andthen
making the instantiaon of the beans lazy wouldn’t have ben necsary. But in the
real world, not evrything is posible due to other factors like cost or time. fI you
cannot rea the ral cuse of the problem, you can sometimes tra least ome of
thesymptoms.
5.2
Using the prototype bean scope
In this section, we discu the second bean scope Spring ofers: prot ype. In some
case, which we’l anlyze in this section, you’d go with prot ype-scoped beans
insteadosinf gletonWe. d’l scui thfraemeworbk’s ehaviofr beands eclar ps rotoypine scton5.21Yout’lhenlarnhowtochangethbeansc’optoe prot ype,
and wel’ try i with a couple of exampels. Finlay, in section 5.2, we’l discu realworldsituaonsyounedtoknowwhenusingtheprot ypescope.
5.2.1
How prototype beans work
Let’s figure out he Spring behavior for managing prot ype beans befor discung
wher you’d use them in ap s. As you’l se, the idea is straightforward. Every time
you request a refnce to a prot ype-scoped bean, Spring creats a new object
instance. For prot ype beans, Spring doesn’t crea nd manage n object instance
directly. The framework manages the object’s ype and creats new instance vry
time someone rquest a rfnce to he ban. In figure 5.6, I repsnted the ban
as cofe plant (evry ime you request a ben, you get a new instance). We stil use
the bean terminol gy, but I use the cofe plant becaus I want o help you quickly
understandandrememberSping’sbehaviorf prot ypebna s.
As you can se in fgiure 5.6, we ned to use a new an otai n named
change the bean’s scope. When you creat the bean using the
ap roach,
@Scope goes togeher with
Whendeclaringthebanwithsteroypean otai ns,you sethe
andthestroypean otai novertheclasthadeclrstheban.
With prot ype beans, we no longer have concurency problems becaus each
threadtharequesthebangetsadiferntinstance,sodefinngmutableprot ype
beansinotaproblem(figure5.7)
@Scope to
@Bean an otai n
@Bean over the method tha declars the bean.
@Scope an otai n
112
CHAPTER 5
The Spring context: Bean scopes and life cycle
Spring creates a bean and adds it to its context.
Spring uses the type of the bean to create new
instances each time they are requested.
Spring context
@Configuration
public class ProjectConfig {
Adds the bean
@Bean
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public CommentService commentService() {
return new CommentService();
}
}
public class Main {
commentService
Gets an
instance
Creates the context
public static void main(String[] args) {
var c = new AnnotationConfigApplicationContext(ProjectConfig.class);
Gets an
instance
var cs1 = c.getBean("commentService", CommentService.class);
var cs2 = c.getBean("commentService", CommentService.class);
boolean b1 = cs1 == cs2;
System.out.println(b1);
}
This line always
prints “ false.”
}
Spring creates a new instance every time the
getBean() method is called. The variables cs1
and cs2 always contain references to two
different instances.
Figure 5.6 We use the @Scope annot at ion t o change t he bean scope in protot ype. The bean is
now represent ed as a coffee plant because you get a new object inst ance each t ime you refer t o
it . For t his reason, variables cs1 and cs2 will always contain different references, so t he out put
of the code is always “ false.”
These arrows represent the execution timelines
of two different threads named T1 and T2.
Spring context
commentRepository
T1
T2
If the two threads get this
bean, each will get and work
with different object instances.
Each thread has its own instance.
Figure 5.7 When mult iple t hreads request a cert ain prot ot ype bean, each t hread gets a
different inst ance. This way, the t hreads cannot run into a race condit ion.
Using the prototype bean scope
113
DECLARING PROTOTYPE-SCOPED BEANS WITH @BEAN
To enforce our discuon, let’s write a project (“sq-ch5-ex”) and prove Spring’s
behavior for managin prot ype beans. We creat a bean named
and declar it s prot ype to prove we get a new insta ce vry time we request hat
bean.Thenxtcodesnip etprsntshe
CommentService
CommentService clas:
public class CommentService {
}
We define a bean with the
sentedinthefol winglistn.g
CommentService clas in the configuraton cals, as pre-
Listing 5.4
Declaring t he prot ot ype bean in t he configuration class
@Configuration
public class ProjectConfig {
@Bean
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public CommentService commentService() {
return new CommentService();
}
Makes this bean prototype-scoped
}
Toprovetha evrytime we request he banwegetanewinstance,wecreat
clasndrequesthebanstwicefromthecontex.Weobservthatherfnceswe
getardifent.Youfindthedfintionofthe
Listing 5.5
Main
Main clasinthefol winglistng.
Test ing Spring’s behavior for t he prot ot ype bean in t he Main class
The two variables cs1 and cs2 contain
references to different instances.
public class Main {
public static void main(String[] args) {
var c = new AnnotationConfigApplicationContext(ProjectConfig.class);
var cs1 = c.getBean("commentService", CommentService.class);
var cs2 = c.getBean("commentService", CommentService.class);
boolean b1 = cs1 == cs2;
System.out.println(b1);
This line always prints
“ false” in the console.
}
}
When you run the ap ,you’l se ti always display “fes”in the console.Thisoutput
pthwrovesainostanwhrecvids encalithge
getBean()methdoiferandt.
114
CHAPTER 5
The Spring context: Bean scopes and life cycle
DECLARING PROTOTYPE-SCOPED BEANS USING STEREOTYPE ANNOTATIONS
Let’s alo creat project (“sq-ch5-ex6”) to observ the behavior for auto-wirng protoype-scopedbeanWes. d’l efinae
the bean using
@Autowired in two other svic beans. We wil observ that ech servicebanhasrefncetoadiferntinstanceof
is milar to the xample we used in section 5.1 for singleton-scoped beans, but now
the
CommentRepository bean is prot ype. Figure 5.8 describ the relationships
betwenthebans.
CommentRepositoryprot ypbe an, dweinject
CommentRepository . Thiscenario
We declare a prototype-scoped
CommentRepository bean.
@Service
CommentService
Uses
@Repository
CommentRepository
@Service
Uses
UserService
Figure 5.8 Each service class requests
an instance of CommentRepository .
Because CommentRepository is a
prot otype bean, each service gets a
different CommentRepository
inst ance.
Each service gets a different
CommentRepository instance.
The next code snip et givs defintion of the
CommentRepository clas. Observ the
@Scope an otai nusedovertheclastohangethescopeofthebantoprot ype:
@Repository
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class CommentRepository {
}
The two servic clase request an instance of pty e
@Autowired an otai n.Thenextcodesnip etprsntshe
CommentRepository using the
CommentService clas:
@Service
public class CommentService {
@Autowired
private CommentRepository commentRepository;
public CommentRepository getCommentRepository() {
Using the prototype bean scope
115
return commentRepository;
}
}
In the previous code snip et, he
CommentRepository bean.Intheconfiguratonclas,wenedtousethe
Scan an otai n to tel Spring wher to find the clase an otaed with steroype
a n o ta i n s:
UserService clas o request an instance of the
@Component-
@Configuration
@ComponentScan(basePackages = {"services", "repositories"})
public class ProjectConfig {
}
Weadthe
bean.The
Mainot upclsa rnohjectsdowSprinthgjecs
Main clasihowni thefol winglistng.
Listing 5.6
CommentRepository
Test ing Spring’s behavior for inject ing t he prot ot ype bean in t he Main class
public class Main {
public static void main(String[] args) {
var c = new AnnotationConfigApplicationContext(ProjectConfig.class);
var s1 = c.getBean(CommentService.class);
var s2 = c.getBean(UserService.class);
Gets references from the
context for the service beans
boolean b =
s1.getCommentRepository() == s2.getCommentRepository();
System.out.println(b);
}
}
5.2.2
Compares the references for the injected
CommentRepository instances. Because
CommentRepository is a prototype bean,
the result of the comparison is always false.
Prototype beans in real-world scenarios
Sofawer d’ve iscuedhowSprinmag nageps rot ypbe anbs foy cusinog nthbe havior. In this ecton, we focus more on the use ca nd wher you should use prot type-scoped beans in production ap s. Just as we di with singleton ap s in section
5.12, we’l consider the discued charcteis and anlyze which scenarios prot typebansrego dforandwhershouldyouavoidthem(byusingsingletonbeans).
Youwon’tfindprot ypebansaoftenasoy u’lfindsingletonbeans.Butheris
a go d patern you can use to deci if a bean should be prot ype. Remember tha
singleton beans are not quite go d friends with mutaing objects. Say ou design an
object named
CommentProcessor that proces the comments and validtes hem. A
CommentProcessor object o implement a use ca. But he
servic use the
Processor objstecorhcoe mmentobpe rocesdantribute,andmeits thods
changethisatrbute(fig r5.9)
Comment-
116
CHAPTER 5
@Service
CommentService
The Spring context: Bean scopes and life cycle
Uses
CommentProcessor
The service class uses a mutable object
to implement the logic of a use case.
Thenextlisngshowstheimplementaionofthe
Listing 5.7
Figure 5.9 A service class uses a mut able
object to implement the logic of a use case.
CommentProcessor bean.
A mut able object ; a potent ial candidat e t o t he prot ot ype scope
public class CommentProcessor {
private Comment comment;
public void setComment(Comment comment) {
this.comment = comment;
}
public void getComment() {
return this.comment;
}
public void processComment() {
// changing the comment attribute
}
These two methods alter the
value of the Comment attribute.
public void validateComment() {
// validating and changing the comment attribute
}
}
The next lisng presnts his ervc tha use the
ment a use ca. The srvic method creats n instance of
theclas’onstrucorandthenusetheinstanceinthemethod’slogic.
Listing 5.8
CommentProcessor clas to impleCommentProcessor using
A service using a mut able object t o implement a use case
@Service
public class CommentService {
public void sendComment(Comment c) {
CommentProcessor p = new CommentProcessor();
p.setComment(c);
p.processComment(c);
p.validateComment(c);
Creates a CommentProcessor
instance
Uses the CommentProcessor instance
to alter the Comment instance
Using the prototype bean scope
c = p.getComment();
// do something further
}
117
Gets the modified Comment
instance and uses it further
}
The
CommentProcessor object is not evn a bean in the Spring contex. Does it ned
to be a bean? It’s crial you ask yourself this question befor deci ng to make any
object a bean. Remember that an object neds to be a bean in the contex only if
Spring nedstomanageitoaugmentheobjectwithsomecapbiltyheframework
ofers.Iweleavourscenariolkethis,the
be a nat l .
But le’s up ose further that he
CommentRepository to persit some dat, and
Springcontex(figure5.10)
@Service
CommentService
Uses
CommentProcessor objectdoesn’tnedto
CommentProcessor bean neds to use an object
CommentRepository is a bean in the
CommentProcessor
Uses
@Repository
CommentRepository
The CommentProcessor object
needs a bean from the Spring
context. The easiest way to get
an instance of CommentRepository
is to request a DI.
Figure 5.10 If t he CommentProcessor object needs t o use an inst ance of CommentRepository ,
the easiest way t o get an inst ance is t o request a DI. But t o do this, Spring needs to know about
CommentProcessor , so t he CommentProcessor object needs t o be a bean in the cont ext.
In th is ce na rio , th e
CommentProcessor beannedstobecomeabntobenefitrom
the DI capbilty Spring ofers. In genral, in any case wher we want Spring to augmentheobjectwithaspecifapbilty,nedstobea n.
Wemake
CommentProcessor abenintheSpringcontex.Butcanitbesngletonscoped? No. If we define this bean as singleton and multipe threads use it concurrently, we get into a rce onditon (as discued in section 5.12) We would not be
sure which comment provide by which thread is procesd and if the comment was
procesd coretly. In this csenario, we want each method cal to get a difernt
instanceofthe
CommentProcessor object.Wecanhangthe
tobeaprot ypeban,asprentedinthenextcodesnip et:
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class CommentProcessor {
CommentProcessor clas
118
CHAPTER 5
The Spring context: Bean scopes and life cycle
@Autowired
private CommentRepository commentRepository;
// Omitted code
}
Y o u c a n n o w g e t a n i nt s a n c e o f
CommentProcessor from the Spring contex. But be
careful! You ned this instance for evry cal of the
sendComment() method, so the
request o the bean should be insde the method itself. To achiev such a result, you
can directly inject the Spring contex (
ApplicationContext ) into the
Service bean using
@Autowired . In the
sendComment() method, you retiv the
CommentProcessor instance using
getBean() from the ap licaton contex, as presentedinthenextlisng.
Listing 5.9
Comment-
Using CommentProcessor as prot ot ype bean
@Service
public class CommentService {
@Autowired
private ApplicationContext context;
public void sendComment(Comment c) {
CommentProcessor p =
context.getBean(CommentProcessor.class);
A new CommentProcessor
instance is always provided here.
p.setComment(c);
p.processComment(c);
p.validateComment(c);
c = p.getComment();
// do something further
}
}
Don’t make the mistake of injecting the
CommentProcessor directly n the
Service bean.The
CommentService bena isangleton,whichmeansthatSpringcreates only an instance of this clas. As a consequenc, Spring wil also inject the
depndenocies thf juclasi ot nwhce encratihs e
CommentService beanitIslf.
CommentProcessor . Each cal of
this cae, you’l end up with only an instance of the
the
sendComment() method wil use this unique instance, so with multipe threda s
you’l run into the same rac onditon isue as with a singleton bean. The next lisingpresnthisap roach.Usethisanexrcistoy utandprovethisbehavior.
Comment-
Using the prototype bean scope
Listing 5.10
119
Inject ing a prot ot ype int o a singlet on
@Service
public class CommentService {
@Autowired
private CommentProcessor p;
Spring injects this bean when creating
the CommentService bean. But because
CommentService is singleton, Spring
will also create and inject the
CommentProcessor just once.
public void sendComment(Comment c) {
p.setComment(c);
p.processComment(c);
p.validateComment(c);
c = p.getComment();
// do something further
}
}
coI ncludthe scionbgivny og umyopinonabout sinpg rot ypbe angeIs. eraly pref to avoid using them, and mutable instances in genral, in the ap s I
devlop. But sometimes you ned to refacto or work with old ap licatons. In my
facedIs, uchseanriowhenwoI rkedina p refactoinfog adr inSpg rintog
anoldap licatonTh. apt usedmutainog binjects manpy anlces, drefactoinalg
thes places in a short ime was imposible. We ned to use prot ype ban, which
alowedthetamtorefac hofthescaprogesivly.
Asarecp,lt’shavequickomparisonbetwensinlegtonandprot ypescopes.
Table5.1showstheircharcteisd-byside.
Table 5.1
A quick comparison bet ween singlet on and protot ype bean scopes
Singlet on
1 The framework associates a name with an actual
Prot ot ype
1 A name is associated with a type.
object instance.
2 Every time you refer to a bean name you’ll get the
same object instance.
3 You can configure Spring to create the instances
when the context is loaded or when first referred.
4 Singleton is the default bean scope in Spring.
2 Every time you refer to a bean name, you get
a new instance.
3 The framework always creates the object
instances for the prototype scope when you
refer to the bean.
4 You need to explicitly mark a bean as a
prototype.
5 It’s not recommended that a singleton bean to
have mutable attributes.
5 A prototype bean can have mutable
attributes.
120
CHAPTER 5
Summary
In Spring, the scope of beans defines how the framework manages the object
instances.
Springoferstwobeanscopes:ingletona dprot ype.
– With singleton, Spring manages the object instances directly in its contex.
Each instance has unique name, and using that name you always ref to
thatspecifnstance.SinlegtonisSprng’sdefault.
– With prot ype, Spring consider only the object type. Each type has a
unique name asocited with it. Spring creats a new instance of tha type
evrytimeyoureftoheban ame.
YoucanconfigureSpring tocrea singletonbeaneitherwhenthecontex is
intiazled (eagr) or when the bean is refd for the first time (lazy). By
default,beaniseagrlynstantiaed.
In ap s, we most often ues singleton beans. Because anyone refing to the
same name gets the same object instance, multipe difernt threads could
aces nd use this nstance. For this reaon, it’s advisble to have the instance
immutable. If, howevr, you pref to have mutaing operations on the bean’s
atribute,i’syouresponsibltyoakecr fthethreadsynchronizaton.
If you ned to have a mutable object like a bean, using the prot ype scope
couldbeago doption.
Becarefulwithinjectinapg rot ype-scopedbeani toasingleton-scopedbean.
When you do something like this, you ned to be aware tha the singleton
instance always use the same prot ype intsance, which Spring injects when it
creatshesingletoninstance.Thisu alyvicousdeignbecausthepoint
ofmakingabenprot ype-scopedistogeadifernti stanceforvyuse.
The Spring context: Bean scopes and life cycle
withSprngAOP
Usingaspect
This chapter covers
Aspect-oriented programming (AOP)
Using aspects
Using the aspect execution chain
Thus far, we have discued the Spring contex, and the only Spring capbilty we
have used is DI, which is up orted by the IoC princple. With DI, the framework
manages objects you define, and you can request to use thes objects wher you
nedthem.Aswediscuedinchapters2hrough5,torequestabn’srefnce,
in most case, you use the
object from the Spring contex, we say that Spring “injects” the object wher you
requestd it. In this chapter, you’l earn how to use another powerful technique
sup ortedbytheoI Cprincple:asct.
@Autowired an otai n. When you request such an
121
122
CHAPTER 6
Using aspects with Spring AOP
Aswapa rectshy frame ewoinrk tecpmes thodancls dposibthaleryxcution of methods. You can afect he xecution of specif method cals you selct.
Thteischniquhe lpyos uexptrac othf loe bgic longintog hexcutinmeg thod.
In certain scenraios, decoupinl g a part of the code helps make tha method easir to
understanlodItw(figu6.1) hreds evlopft ercuons ly threvandteailscusedwhenradinthg mee thodloIngic. thc is apweter, d’l iscuhowtoimplement
aspect and when you should use them. Aspects are a powerful to l, and, as Petr
Parke’s uncle say, “With great power comes great responsiblty!” If you don’t use
aspect carefuly, ou might end up with a les maintainable ap , which is quite the
op owhsitef yoatuwantoachThiev. apis roachledpsirotg-mn ming
(AOP).
Figure 6.1 Sometimes it ’s not relevant t o have parts of t he code in t he same place with t he business
logic because it makes the app more difficult t o underst and. A solut ion is to move part of t he code
aside from the business logic implementat ion using aspect s. In t his scene, Jane, t he programmer, is
discouraged by the logging lines writt en toget her wit h the business code. Count Dracula shows her
the magic of aspect s by decoupling t he logs int o an aspect .
How aspects work in Spring
Anotheimr portantreasonfolerani agspetcihaSprinug sethminmplementing a lot f the cruial cpabiltes ofers. Understanding how the framework works
canyovse umanhy ouorsdf ebuginwhlaterg enyouspafce i roblemA. pertine t example of Spring capbilty hat use apects i transcio,ly which we’l discuins chapTr1t3e.r ansactionoisalty noe thf mae incapbimoltes apst us toe day
to kep the persitd dat’s consitency. Another important capblity relying on
aspectis urityconfiguratons,whichhelpyourap protecisdat ndmake sure
dat can ot be sen or changed by unwanted indiv uals. To properly understand
whathap ensinpa suingthesfunctionalites,youfirstnedtolearnaspect.
Wewistar’l tha eoinrtcal oductiontospa inect sonYo6.1 ulearn’ how
aspect work. Once you understand thes basic, in section 6.2, you’l learn how to
implement an aspect. We’l star with a scenario, and we’l devlop an example that
we’l use to dcisu the most practil syntaxes for uisng aspect. In section 6.3, you’l
learn what hap ens when you define multipe aspect o intercp the same method
and ealwithsuchscenarios.
6.1
How aspects work in Spring
In this section, you’l learn how aspect work and the esntlia terminol gy you’l
encounterwhenusingaspect.Bylearni gtoimplementaspec,you’lbea ltouse
new techniques to make your ap more maintainable. Moreo,v you’l also understandhowcertainSpringfeatursae plugedinto ap s.Wediscu thes thingsfirt
and then go straight into an implementaion example in section 6.2 But it helps if
youhavenideaofwhatwe’reimplementingbefordivngintowritngcode.
An aspect is mply a peic of l gic the framework excuts when you cal specif
methodsofy urchoice.Whendesigni ganspect,youdefinethefol wing:
What code you want Spring to excut when you cal ps ecif method.s This
namedanaspect.
When the ap shoudl excut his ol gic of the aspect (.g, befor or afte he
methodcal,insteadofthemethodcal).Thisnamedtheadvic.
Which methods the fmra ework neds to intercp and excut the aspect for
them.Thisnamedapointcu.
Withasptecrminol yog, ualso’ findthcoe ncepot afjinpwh, cihdefinthes
evnt hat riges the xcution of an aspect. But with Spring, this evnt is always
methodcal.
Asinthecasofthedpendencyinjection,touseapctyounedtheframework
to manage the objects for which you want o ap ly aspect. You’l use the ap roaches
youlearnedinchapter2 oad beanstoheSpringcontexoenabletheframework
to control them and ap ly aspect you define. The bean that declars the method
intercpdbyanspectinamedthetargobjc.Fiure6.2s mmarizesthestrms.
123
124
CHAPTER 6
Using aspects with Spring AOP
To become an aspect target, the object needs to
be a bean in the Spring context. Spring needs
to know the objects it has to manage.
Spring context
@Service
public class CommentService {
Adds the bean
commentService
public void publishComment(Comment comment) {
// do something
}
}
The aspect
The advice
We want some logic to be executed before each
execution of method publishComment(),
which belongs to the CommentService bean.
The pointcut
The join point
The target object
Figure 6.2 The aspect t erminology. Spring execut es some logic (t he aspect ) when someone calls
a specific method (the point cut ). We need t o specify when the logic is execut ed according t o the
point cut (e.g., before). The when is t he advice. For Spring to intercept t he met hod, the object t hat
defines the intercepted met hod needs t o be a bean in t he Spring cont ext. So, the bean becomes the
target object of t he aspect .
But how does Spring intercp each method cal and ap ly the aspect logic? As discusedarlienthisecton,theobjectnedstobea nintheSpringcontex.But
becaus you made the object an aspect targe, Spring won’t directly give you an
instancerfnceforthebanwhenyourequestifromthecontex.Instead,Spring
giyoves uanobthjec als pe loct ginsteadothf aceumel thodWe. sathy at
Springiveyos uproxay bjectinseadoftherbal nYo. uwinl owrecivtheproxy
instead of the bean anytime you get he bean from the contex, iher if you directly
usethe
getBean() methodofthecontexorify u seDI(figure6.3)Thisap roach
isnamedweaving.
How aspects work in Spring
125
Spring context
@Configuration
public class ProjectConfig {
commentService
Adds the bean
@Bean
public CommentService commentService() {
return new CommentService();
}
}
public class Main {
Gets the proxy
to the bean
public static void main(String[] args) {
var c = new AnnotationConfigApplicationContext(ProjectConfig.class);
var service = c.getBean(CommentService.class);
System.out.println(service.getClass());
}
}
If the bean is an aspect target, Spring doesn’t
provide you a reference to the actual object.
Instead, Spring gives you a reference to a proxy
object that can manage each call to the intercepted
method and apply the aspect logic.
If you print the type of this object, you can see
it’s not just a CommentService. It’s an object that
“ enhances” the behavior of the CommentService object.
Notice the “ EnhancerBySpring” in the type name!
The output will look similar to the next line:
class services.CommentService$$EnhancerBySpringCGLIB$$12491022
Figure 6.3 Weaving an aspect. Inst ead of giving you a reference t o t he real bean, Spring gives
you a reference t o a proxy object , int ercept s t he met hod calls, and manages the aspect logic.
In figure 6.4, you find a comparison betwen caling the method when it sn’t interceptd by an aspect vrsu an aspect intercping the method cal. You observ tha
caling an aspectd method asumes you cal the method through the proxy object
provide by Spring. The proxy ap lies the pas ect logic and delgats he cal to the
actulmethod.
126
CHAPTER 6
Using aspects with Spring AOP
Without aspect
CommentService
publishComment()
void publishComment() {
// publish comment
}
When the method isn’t intercepted
by aspects, someone calling the
publishComment() method directly
calls the logic implemented in the
CommentService class.
With aspect
Proxy to CommentService
CommentService
Delegates
publishComment()
void publishComment() {
// aspect logic
}
void publishComment() {
// publish comment
}
When we define an aspect for the method,
someone calls the method through the
proxy Spring provides. The proxy applies
the aspect logic and then further delegates
the call to the actual method.
Figure 6.4 When a method isn’t aspected, t he call goes directly t o that met hod. When we define
an aspect for a met hod, the call goes through t he proxy object . The proxy object applies the logic
defined by t he aspect and then delegat es t he call t o the real met hod.
Now that you haev the big picture of pas ect and how Spring manages them, we go
further and discu the syntaxes you ned to implement aspect with Spring. In section 6.2, I describ a scenario, and then we implement he rquirements of the scnariousingaspect.
6.2
Implementing aspects with Spring AOP
Inthisecton,you’leranthemostrelvantaspectyntaxesudinreal-worldexamples. We’l consider a scenario and implement its requirements with aspect. At the
end of this ecton, you’l be able to ap ly aspect syntaxes o solve the most frequent
problemsinreal-worldscenarios.
Implementing aspects with Spring AOP
127
uS p ose you have n ap iclaton that implements multipe use ca in its ervc
clase.Somenewregulationsrequireyourap tos rethetimeitsardandende
for each use case excution. In your team, you deci d to take responsiblty for
implementi gafunctionalityo galthevntswherauscebginsandends.
Insection6.21,we’luseanaspectos lvethiscenarionthesimplestwayposible. By doing so, you’l earn what you ned to implement an aspect. Further, in this
chapter,I’l ogresivlyad moredtailsnregadtousni gaspect.Insection6.2,
wed’l iscuhowanspuect os evnr atlhes intercpdmethodp’s armoetrs
the value retuned by the method. In section 6.23, youl’ learn how to use an otations to mark methods you want o intercp for a specif purpose. Developers often
use an otai ns to mark the method an aspect neds to intercp. Many featurs in
Sprni gusean otai ns,ayou’learni thenextchapters.Scion6.24wilgiveyou
morealtnativesfordvicean otai nsyoucanusewithSpringaspect.
6.2.1
Implementing a simple aspect
In this ecton, we discu implementing a simple aspect o solve our scenario. We’l
creat new project and defin a servic las contain g a method that we’l use to
tesourimplementaionandprovetheaspctwe defineworksadeir nthend.
You find this example in the project named “sq-ch6-ex1.” In ad iton to the
spring-context depndency, for this example we also ned the
depndency. Make sure to update your pom.xml fie and ad the ned depndencies,aprntedinthenxtcodesnip et:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
spring-aspects
We need this dependency
to implement the aspects.
Tomakeourexampleshorteandalowyoutof cusonthesyntaxreldtoaspect,
weo’l ncoly nsidoer noservic bnject amed
CommentServiceandua itcse fnes
n am e d
publishComment(Comment comment) . This method, defined in the
Comment . Comment is a model cas nd is
Service clas, recivs a parmetr of type
presntedinthenxtcodesnip et:
public class Comment {
private String text;
private String author;
// Omitted getters and setters
}
Comment-
128
CHAPTER 6
Using aspects with Spring AOP
NOTE Rememberfomchapter4hatmodelcsai thatmodelsthe
d at p ro ce s d b y th e a p . In o u r c as e, th e
ment withitsarbutes: x andauthor.Aservic la mplementsuecas
of an ap . In chapter 4, we discued more of thes rponsiblte, and we
usedtheminexamples.
In listng 6.1, you find the defintion of the
CommentService clas with the
the Spring contex. The
comment) method,repsntingourscenario’sueca.
Youalso binserv thexamis pthle ina steadouf sing
typoef
Loggerwrtomeite inthcosage Inreal-swo. oarpldyodus, onus’et
.out to write mesage in the console. You’l generaly use a loging framework tha
yomoufers incuflexbtsyor miznthlogafeustrgnd ardiznthlog-e
ginmesage.Somego doptionsforal gingframeworkaesf lows:
Log4j(
Logback(
JavLogingAPI,whichcomeswiththeJDK(
Comment clas describ a com-
CommentService clas. We an otae the
@Service steroype an otai n to make it a bean in
CommentService clas defines the
publishComment(Comment
System.outuI, sedanobject
System
hlotgipn/s:g.apche.org/log4j/2.x
)
hlogbtp/ack.q: os.ch/
)
hmtp/: ng.bz/v4Xq
)
The loging frameworks ae compatible with any Jav p , whether it’s using Spring
ornot.AstheyarnotreladtoSpring,Ihaven’tusetheminourexamplestoav id
distracng you. But we are f nough now with Spring that we can star o use thes
ad itonal frameworks in our examples to familarze you with syntaxes closer to
production-readyp s.
Listing 6.1
The Service class used in t he examples
We use the stereotype annotation to
make this a bean in the Spring context.
@Service
public class CommentService {
To log a message in the app’s
console every time someone
calls the use case, we use a
logger object.
private Logger logger =
Logger.getLogger(CommentService.class.getName());
public void publishComment(Comment comment) {
logger.info("Publishing comment:" + comment.getText());
}
}
In this example, I use the JDK login capblites o avoid ad ing other depndencies to our project. When declaring a loger object, you ned to give t a name as
parmetr. This name then ap ears in the logs and makes it easy for you to observ
the log mesage os urce. Often, we use the clas name, which I di in our example:
CommentService.class.getName() .
This method defines
the use case for our
demonstration.
Implementing aspects with Spring AOP
Wealsonedtoa dcoanfiguratonSptelcas ri whg toler fthkr clase
an otaedwithserotypane otai nI mys. da I cse,indthlapservc aka ge n a m e d
an otai n,asyouobservfomthenxtcodesnip et:
129
"services" , and this is what I ned to specify with the
@ComponentScan
@Configuration
@ComponentScan(basePackages = "services")
public class ProjectConfig {
}
Let’s write he
andobservthecurntbehavior,showni thefol wingslitng.
Main clas that cls he
Listing 6.2
We use@ComponentScan to tell Spring
where to search for classes annotated
with stereotype annotations.
publishComment() method in the srvic la
The Main class we use t o t est t he app’s behavior
public class Main {
public static void main(String[] args) {
var c = new AnnotationConfigApplicationContext(ProjectConfig.class);
var service = c.getBean(CommentService.class);
Comment comment = new Comment();
comment.setText("Demo comment");
comment.setAuthor("Natasha");
service.publishComment(comment);
}
Gets the CommentService
bean from the context
Creates a Comment instance
to give as a parameter to the
publishComment() method
Calls the publishComment() method
}
If you run the ap , you’l observ an output in the console similar to what you se in
thenextsnip et:
Sep 26, 2020 12:39:53 PM services.CommentService publishComment
INFO: Publishing comment:Demo comment
You wil se the output genrated by the
ap lo ks befor we solve the example we discued. Remember, we ned to print
mesage in the console befor and after he srvic method cal. Let’s now enhance
the project with an aspect clas tha intercps the method cal and ad s an output
b efo r an d a fter he c al .
Tocreatnaspect,youfol wthestp(figure6.5):
1
2
Enable the aspect mechanism in your Spring ap by an otaing the configurationclaswiththe
Creat new clas, nd an otae i with the
@Bean osrte ypaen otai nsa,d ba enfotrhcislanthSeprincgontex.
publishComment() method. This how the
@EnableAspectJAutoProxy an otai n.
@Aspect an otai n. Using either
130
CHAPTER 6
3
4
Using aspects with Spring AOP
DefineamethodthatwilimplementheaspctlogiandtelSpringwhenand
whichmethodstointercpusinga dvicean otai n.
Implementheaspctlogi.
2. Create an aspect class, and add
an aspect bean to the Spring context.
1. Enable aspects in your Spring app.
@Configuration
@ComponentScan(basePackages = "services")
@EnableAspectJAutoProxy
public class ProjectConfig {
}
@Aspect
public class LoggingAspect {
}
4. Implement the aspect logic.
@Around("execution(* services.*.*(..))")
public void log(ProceedingJoinPoint joinPoint) {
// aspect logic here
}
3. Defi ne a method to implement
the aspect logic, and use an advice
annotation to tell Spring when and
what to intercept.
@Around(" execution(* services.*.*(..))" )
public void log(ProceedingJoinPoint joinPoint) {
}
Figure 6.5 To implement an aspect, you follow four easy steps. First , you need to enable t he aspect capability
in your app. Then you create an aspect class, define a method, and inst ruct Spring when and what to intercept.
Finally, you implement the aspect logic.
STEP 1: ENABLING THE ASPECTS MECHANISM FOR YOUR APPLICATION
Fothr efirstp,younedtoeSpl ringyou’l asepcitnyouapr .Whenveyor u
useapcifmechanismprovide bySpring,youhavetoxplictyenableit yan otainyoguc rnfiguratowinclas ptharicunla otai nI mo. thcnase, moesf
thanes otai winstar h“EnabYole.”uwilearnmosurechan otai nthes a ble
difernSpityocapusgbthroile gs ughtboeInthxamk. is pwenle, d
touhse
configuratonclasnedstol oklietheoneprsntedinthefol winglistng.
@EnableAspectJAutoProxyan otai ntoe abthlespca t bThiltes. e
Implementing aspects with Spring AOP
Listing 6.3
131
Enabling t he aspect s mechanism in a Spring app
@Configuration
@ComponentScan(basePackages = "services")
@EnableAspectJAutoProxy
public class ProjectConfig {
}
Enables the aspects mechanism
in our Spring app
STEP 2: CREATE A CLASS THAT DEFINES THE ASPECT, AND ADD AN INSTANCE FOR THIS CLASS IN THE
SPRING CONTEXT
We ned to creat a new bean in the Spring contex that defines the aspect. This
object holds the methods, which wil intercp specif method cals and augment
themwithspeciflog.Inthenxtlisng,youfindthedfintionofthisnewcsla.
Listing 6.4
Defining an aspect class
@Aspect
public class LoggingAspect {
public void log() {
// To implement later
}
}
Youcanuseanyoftheap roachesyoulearnedinchapter2oad aninstanceofthis
clas to the Spring contex. If you deci to use the
changetheconfiguratonclas, presntedinthenextcodesnip et.Ofcourse,you
canalsousetroypean otai nsifyou’dklie:
@Bean an otai n, you have to
@Configuration
@ComponentScan(basePackages = "services")
@EnableAspectJAutoProxy
public class ProjectConfig {
@Bean
public LoggingAspect aspect() {
return new LoggingAspect();
}
Adds an instance of the LoggingAspect
class to the Spring context
}
Remembeyro, unedtomathke ois bjaect ni thSpe rincgontexbcauSpse ring
nedstoknowaboutanyobjectinedstomanage.ThiswhyIstronglyemphasized
the ap roaches to manage the Spring contex ni chapters 2 through 5. You’l use
theskliamostevrywherwhendevlopni gaSpringap .
Also, the
telSprintghatheclasimplementshedfinitonofanspect,butSpringwon’talso
creat beanforthiscla.Younedtoexplictyuseoneofthesyntaxesyoulearned
inchapter2ocabenfory urclasndlaowSpringtomanageithisway.It’s
acommonmistakeof rgethatn otaingtheclaswith
beantohecontex,andI’vesnmuchfrustaioncausedbyforgetingthis.
@Aspect an otai n isn’t a steroype an otai n. Using
@Aspect, you
@Aspect doesn’talsod a
132
CHAPTER 6
Using aspects with Spring AOP
STEP 3: USE AN ADVICE ANNOTATION TO TELL SPRING WHEN AND WHICH METHOD CALLS TO INTERCEPT
Now that we have defined the aspect clas, we cho se the advice and an otae the
methodacordingly.nI thenextlisnyog, usehowIan otaedhemethodwiththe
@Around an otai n.
Listing 6.5
Using an advice annot ation t o weave t he aspect t o specific met hods
@Aspect
public class LoggingAspect {
Defines which are the
intercepted methods
@Around("execution(* services.*.*(..))")
public void log(ProceedingJoinPoint joinPoint) {
joinPoint.proceed();
Delegates to the actual intercepted method
}
}
Other than using the
stringexprsionasthevalueofthean otai n,andIhaved edaprametrothe
aspectmethod.Whatrehes?
Let’s ake them one by one. The peculiar exprsion used as parmetr o the
@Aroundan otai nSptels rinwhg ichmethodtcalsintercpDo. nb’tine tmi di ate
by this exprsion! Thisexprsion languae is cld AspectJpointcu languae, nd
youwon’t edtolarnbithy oeaurt Ini.s pyoractie, udonu’t cose mpexl rssions. When I ned to write such an exprsion, I always ref to the documentaion
( hmtp/: ng.bz/4K9g
Theorticaly, ou can writevry compxleAspectJ pointcu exprsions to identify
pa rticuoselamef thodtcoalsbine trcpedTh. lanis guprealyis owerfuBul. t
aswe’ldisculaterinthischapter,i’salwaysbetroav idwritngcomplexpressions.Inmostcae,youcanfindsimpleratnatives.
LookathexpresionIused(figure6.)ItmeansSpringintercpsanymethod
defined in a clas that is in the servic packge, regadls of the method’s retun
type, the clas it belongs to, the name of the method, or the parmetrs he method
recivs.
Onsecondlo thk, exprsiondoesnem’t soc mplicated, oknIit?es owthes
AspectJ pointcu exprsions tend to scare bgin ers, but rust me, you don’t have to
becomeanAspectJx rousethesxprionsinSpringap s.
Now let’s o k at he scond elment I’ve ad ed to he method: the
JoinPoint parmetr,whichrepsntsheintercpdmethod.Themainthingyou
do with this parmetr is l the aspect when it should delgat further to he actul
method.
@Around an otai n, you also observ I’ve writen an unus al
.)
Proceeding-
Implementing aspects with Spring AOP
133
The parameter given to execution()
specifies the methods whose
execution is intercepted.
execution() is equivalent to saying
“ When the method is called . . .”
execution(* services.*.*(..))
This (..) means the
intercepted method
can have any parameters.
This (*) means the intercepted
method may have any returned type.
This means the intercepted method
must be in the services package.
This (*) means the intercepted method
can have any name. All the methods
are intercepted.
This (*) means the intercepted method can
be in any class.
Figure 6.6 The AspectJ point cut expression used in the example. It t ells Spring to intercept t he calls
for all t he methods in the services package, regardless of t heir ret urn type, the class t hey belong t o,
name, or t he paramet ers they receive.
STEP 4: I MPLEMENT THE ASPECT LOGIC
Inlistng6.,I’vead edthelogcif rouraspect.Nowtheaspct
1
2
3
4
Intercpshemethod
Displayomethingintheconsolebforecalingtheintercpdmethod
Calstheintercpdmethod
Displayomethingintheconsoleaftrcingtheintercpdmethod
Figure6.7visualypresntsheaspct’behavior.
1. The LoggingAspect
intercepts the method.
Main
2. The LoggingAspect displays
something in the console before
delegating to the intercepted
method.
LoggingAspect
3. The LoggingAspect calls the
intercepted method.
CommentService
logger.info("Method will execute");
main()
joinPoint.proceed();
publishComment()
logger.info("Method executed");
4. The LoggingAspect displays
something in the console after
the intercepted method executes.
Figure 6.7 The aspect behavior. LoggingAspect wraps the met hod execution by displaying something
before and after the met hod call. This way, you observe a simple implement ation of an aspect .
134
CHAPTER 6
Listing 6.6
Using aspects with Spring AOP
Implement ing t he aspect logic
Prints a message in the console before
the intercepted method’s execution
@Aspect
public class LoggingAspect {
private Logger logger = Logger.getLogger(LoggingAspect.class.getName());
@Around("execution(* services.*.*(..))")
public void log(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info("Method will execute");
Calls the intercepted method
joinPoint.proceed();
logger.info("Method executed");
Prints a message in the console after
}
the intercepted method’s execution
}
Themethod
proceed() of the
ProceedingJoinPoint parmetrcals heintercpd
method,
publishComment() , of the
CommentService bean. If you don’t cal
proceed()th, pase nct devr fulgats rhtoerhine trcpedmethod(figu6.8)re
If you don’t call the proceed()
method of the ProceedingJoinPoint
parameter, the aspect never delegates
to the intercepted method.
Main
LoggingAspect
CommentService
logger.info("Method will execute");
main()
publishComment()
logger.info("Method executed");
The aspect executes its logic
and directly returns to the main()
method. For the main() method,
it still looks like publishComment()
method executed.
Figure 6.8 If you don’t call t he proceed() met hod of the ProceedingJoinPoint paramet er of t he
aspect , t he aspect never delegat es furt her t o t he int ercept ed met hod. In this case, t he aspect simply execut es
inst ead of t he intercept ed met hod. The caller of t he method doesn’t know t hat the real met hod is never
executed.
You can evn implement logic wher the actul method isn’t caled anymore. For
example,anaspecthatp liesomeauthorizat nrulesdeci swhethertodelgta
further to a method the ap protecs. If the authorizat n rules aren’t fulied, the
aspectdoesn’tdelgatoheintercptdmethoditprotecs(figur6.9)
Implementing aspects with Spring AOP
135
Figure 6.9 An aspect can decide not t o delegat e at all t o the met hod it int ercepts.
This behavior looks like t he aspect applies a mind trick to t he caller of t he met hod.
The caller ends up execut ing anot her logic than t he one it act ually called.
Also, bthserv a e
is designed to throw any excption coming from the intercpd method. In this
example, I chose the asy way to propagte i furthe, but you can use a
finally blockt reahisthrowableifyounedit.
Rerun the ap licaton (q“s -ch6-ex1”). In the console output, youl’ nfi d the logs
from both the aspect and the intercpd method. The output you se should lo k
similartoheoneprsntedinthefol wings ip et:
proceed()methodthrowas
ThrowableTh. mee thod
proceed()
try-catch-
Sep 27, 2020 1:11:11 PM aspects.LoggingAspect log
This line is printed from the aspect.
INFO: Method will execute
Sep 27, 2020 1:11:11 PM services.CommentService publishComment
INFO: Publishing comment:Demo comment
This line is printed from
Sep 27, 2020 1:11:11 PM aspects.LoggingAspect log
the actual method.
INFO: Method executed
This line is printed from the aspect.
6.2.2
Altering the intercepted method’s parameters and the returned value
Itoldyouaspect ra lypowerful.Not onlycantheyintercpamethodandalter
itsexcution, but hey can alsointercp the parmetrsusedto cal the method and
posibly ater hem orthe value the intercpdmethod retuns. In this ecton, we’l
change the example we’ve ben working on to prove how an aspect can afect the
parmetrs and the value retuned by the intercpd method. Knowing how to do
thisgveyouevnmoreop ortunitens whatyoucanimplementusingaspect.
Sup ose y u want o l g the parmetrs usedto cal the srvic method na d what
themethodretuned.Todemonstraehowtoimplementsuchascenario,Isepartd
this example into a project named “sq-ch6-ex2.” Because we also ref to what the
136
CHAPTER 6
Using aspects with Spring AOP
method retuns, I changed the servic method and made it retun a value, as presentedinthenextcodesnip et:
@Service
public class CommentService {
private Logger logger = Logger.getLogger(CommentService.class.getName());
public String publishComment(Comment comment) {
logger.info("Publishing comment:" + comment.getText());
return "SUCCESS";
For our demonstration, the
}
method now returns a value.
}
The aspect can easily find the name of the intercpd method and the method
parmetrs. Remember that the
method repsnts the ni tercpd method. You can use this parmetr to get any
information relatd to the intercpd method (parmetrs, method name, targe
obanject, dso nTh). ne coxt dsne ip shet owyos uhowtohge methodnamane d
theparmetrsudtocalhemethodbeforintercpingthecal:
ProceedingJoinPoint parmetr of the aspect
String methodName = joinPoint.getSignature().getName();
Object [] arguments = joinPoint.getArgs();
Nowwecanhanthge asploect thg des Intail. hne ilstx yog, ufindthe
changeyounedtomaketoheaspctmethod.
Listing 6.7
Obt aining t he met hod name and paramet ers in t he aspect logic
@Aspect
public class LoggingAspect {
private Logger logger = Logger.getLogger(LoggingAspect.class.getName());
@Around("execution(* services.*.*(..))")
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
String methodName =
Obtains the name and parameters
joinPoint.getSignature().getName();
of the intercepted method
Object [] arguments = joinPoint.getArgs();
logger.info("Method " + methodName +
" with parameters " + Arrays.asList(arguments) +
" will execute");
Calls the
intercepted
method
Logs the name and
parameters of the
intercepted method
Object returnedByMethod = joinPoint.proceed();
logger.info("Method executed and returned " + returnedByMethod);
return returnedByMethod;
}
}
Returns the value returned by
the intercepted method
Implementing aspects with Spring AOP
The main() method calls publishComment() of the
CommentService bean, but an aspect intercepts
the call.
137
The aspect logs the call as well
as the parameters of the method
and the value it returns.
Main
Comment
parameters
LoggingAspect
Comment
parameters
CommentService
main()
Returned
value
log()
Returned
value
publishComment()
The main() method is unaware of the aspect’s existence. From
its side, it looks like it directly calls the publishComment()
method of the CommentService bean.
Figure 6.10 The aspect intercept s t he met hod call, so it can access t he parameters and t he value
ret urned by t he int ercept ed method after execut ion. For t he main() method, it looks like it direct ly
calls the publishComment() met hod of the CommentService bean. The caller isn’t aware t hat
an aspect int ercept ed the call.
Figure6ma.10 keistarovualiztehfelow.Observhowthasepctintercpshe
calndcanacestheparmetrsandthertunedvalue.
chI’ve angedthe
asprentedinthefol winglistng.
Listing 6.8
main()methodtoprinthvaluert nedby
publishComment() ,
Print ing t he ret urned value t o observe t he aspect ’s behavior
public class Main {
private static Logger logger = Logger.getLogger(Main.class.getName());
public static void main(String[] args) {
var c = new AnnotationConfigApplicationContext(ProjectConfig.class);
var service = c.getBean(CommentService.class);
Comment comment = new Comment();
comment.setText("Demo comment");
comment.setAuthor("Natasha");
String value = service.publishComment(comment);
logger.info(value);
}
}
Prints the value returned by the
publishComment() method
138
CHAPTER 6
Whenrun ingthe ap , intheconsole y use the valueslogd from theaspect and
thertunedvalueogdbythe
Using aspects with Spring AOP
main() method:
Parameters printed by the aspect
Sep 28, 2020 10:49:39 AM aspects.LoggingAspect log
INFO: Method publishComment with parameters [Comment{text='Demo comment',
➥ author='Natasha'}] will execute
Sep 28, 2020 10:49:39 AM services.CommentService publishComment
INFO: Publishing comment:Demo comment
Message printed by the
Sep 28, 2020 10:49:39 AM aspects.LoggingAspect log
intercepted method
INFO: Method executed and returned SUCCESS
Sep 28, 2020 10:49:39 AM main.Main main
Returned value printed by the aspect
INFO: SUCCESS
Returned value printed in main
But aspect ar evn more powerful. They can alter he xcution of the intercpd
methodby
Changi gthevaluoftheparmetrsntohemethod
Changi gthertunedvaluercidbythecalr
Throwing an excption to the caler or cathing and treaing an excption
thrownbytheintrcepdmethod
You can be xtrmely fxible in altering the cal of an intercpd method. You can
evnchangeitsbhaviorc mplety(figu6.1re)Butbecarful!Whenyoualterhe
lothgic roughanspyoect, umapakeorthf loetrangic sparenMat. suke yor udon’t
When calling the publishComment()
method, main() sent a parameter,
but the aspect changed the value of
this parameter when further calling
the intercepted method.
The main() method calls
publishComment() of the
CommentService bean, but
an aspect intercepts the call.
Main
main()
Some
comment
parameters
Another
returned
value
LoggingAspect
log()
The publishComment() method returned a value,
but the aspect changed this value when returning
it to main(). For the main() method it looks like the
changed value comes directly from publishComment().
Another
comment
parameter
Some
returned
value
CommentService
publishComment()
Figure 6.11 An aspect can change t he
paramet ers used t o call t he int ercept ed
met hod and t he ret urned value received
by the intercepted met hod’s caller. This
approach is powerful, and it gives flexible
control of t he int ercept ed method.
Implementing aspects with Spring AOP
hidethingsthat ren’tobvious.Thewholeideaofdecouplingapartofthelogicsto
avoid dupcliatng code and hide what’s irelvnt, so a devloper can easlyi focus on
thbe usinloes cgi dWhe. enconsidernwrg tinag spect, uyot uinrself thde vloper’shoes.S meonewhonedstounderstandthecodeshouldeasiyrlzwhat’s
hap eni g.
In the project “sq-ch6-ex3,” we demonstrae how aspect can alter the cal by
changi the parmetrs or the value rtuned by the intercpd method. The following listng shows tha when you cal the
parmetrs, he pas ect snds the orignal parmetrs o the intercpd method. But
you can cho se to provide a parmetr when caling the
parmetr is an ary of objects tha the aspect sends to the intercpd method
instead of the orignal parmetr values. The aspect logs the value retuned by the
intercpdmethod,butire nstohecalrdifentvalue.
Listing 6.9
139
proceed() method without sending any
proceed() method. This
Alt ering t he paramet ers and t he ret urned value
@Aspect
public class LoggingAspect {
private Logger logger =
Logger.getLogger(LoggingAspect.class.getName());
@Around("execution(* services.*.*(..))")
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getName();
Object [] arguments = joinPoint.getArgs();
logger.info("Method " + methodName +
" with parameters " + Arrays.asList(arguments) +
" will execute");
Comment comment = new Comment();
comment.setText("Some other text!");
Object [] newArguments = {comment};
We send a different comment
instance as a value to the
method’s parameter.
Object returnedByMethod = joinPoint.proceed(newArguments);
logger.info("Method executed and returned " + returnedByMethod);
return "FAILED";
}
}
Run ing the ap genrates n output like he one in the next snip et. The values of
thpe armrectsivdbthy e
sent when caling the method. The
main() getsadifrntone:
We log the value returned by the intercepted method,
but we return a different value to the caller.
publishComment()methodare ifnthanthoe nes
publishComment() method retuns a value, but
140
CHAPTER 6
Using aspects with Spring AOP
The publishComment() method is called with a
comment having the text “ Demo comment.”
Sep 29, 2020 10:43:51 AM aspects.LoggingAspect log
INFO: Method publishComment with parameters [Comment{text='Demo comment',
➥ author='Natasha'}] will execute
Sep 29, 2020 10:43:51 AM services.CommentService publishComment
INFO: Publishing comment:Some other text!
The publishComment() method
Sep 29, 2020 10:43:51 AM aspects.LoggingAspect log
receives a comment with the text
INFO: Method executed and returned SUCCESS
“ Some other text!”
Sep 29, 2020 10:43:51 AM main.Main main
INFO: FAILED
The method publishComment()
The returned value main()
receives is “ FAILED.”
NOTE
returns “ SUCCESS.”
I know I repta myself, but this point is quite important. Be careful
with using aspect! You should only use them to hide irlvant lines of c de
that cn easily be implied. Aspects ar so powerful they can bring you to the
“dsiark oe”hf idnrelvag cot dane dmayoke uapr modre ficutolmaintain.Useaspctwithcaution!
Okay, but would we evr want o have n aspect hat changes the parmetrs of the
intercpd method? Or its retuned value? Ys. Sometimes it hap ens that us ch an
ap roachuis ef xpIl. ainedthal pes roachbes cauinse thne chxt aptewers ’l
use crtain Spring cpa biltes hat rely on aspect. For example, in chapter 13 we’l
discu transctions. Transactions in Spring rely on aspect. When we get o that subject,you’lfindunderstandingaspectvryuesf l.
Byfirstunderstandinghowaspectworkyougainsgnifcantadvntageinunderstanding Spring. I often se devlopers staring to use a framework without understanding what’s behind the functionalites they use. Not surpisngly, in many caes,
thes devlopers introduce bugs or vulnerabilts to their ap s, or they make them
ples rfomant dmaintainabMyle. adtoisvcealwlearyns howthinwogs brk efor
usingthem.
6.2.3
Intercepting annotated methods
In this section, we discu an important ap roach, often used in Spring ap s, for
markingthemethodsthatnedtobeintercpdbyaspect:usingan otai ns.Have
youobservdhowmanay notai nwes a’lrevduy sedinouexamr pAnles? notai ns
arecomfortableouse,andsincetheyap eardwithJav5,theybcamethedfacto
ap roach in configurng ap s that use pecif rameworks. Ther’s proba ly no Jav
framework today that doesn’t use an otai ns. You can also use them to mark the
methodyos uwanat sptoecintercpwithcoa mfortabsynle thax lot wyos ualso
toav idwritngcomplexAspectJ ointcuexprsions.
We’l creat a separt example to learn this ap roach, similar to those we’ve
discuedsofar inthcishaptIenr. he
CommentService cwelas, ’adl thmere thods:
publishComment() , deleteComment() , and
editComment() . You find this example in
the project “sq-ch6-ex4.” We want to define a custom an otai n and log only the
Implementing aspects with Spring AOP
141
excution of the methods we mark using the custom an otai n. To achiev this
objectiv,younedtodothefol wing:
1
2
Define a custom an otai n, and make it acesbl at runtime. We’l ca this
a n o ta i n
Use a difernt AspectJ pointcu exprsion for the aspect method to tel the
aspectointercphemethodsan otaedwithhecustoman otai n.
@ToLog .
Figure6.12visualyrepsntshestp.
1. Define a custom annotation.
2. Use an AspectJ pointcut expression
to tell the aspect to intercept the
method with the newly created annotation.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ToLog {
}
@Aspect
public class LoggingAspect {
@Around("@annotation(ToLog)")
public Object log(ProceedingJoinPoint jp) {
// Omitted code
}
}
Figure 6.12 The steps for int ercept ed annot ated methods. You need to creat e a cust om annot ation you want
to use t o annot at e t he met hods your aspect needs t o int ercept . Then you use a different Aspect J pointcut
expression to configure the aspect t o intercept t he methods annotat ed wit h the cust om annotat ion you creat ed.
Wedon’t edtochanthge logicthf aspe Fct.ohr examis pole, uaspr dect ohes
samethingastheprviousexample:sogtheintercpdmethod’sexcution.
In the next code snip et, you nfi d the declartion of the custom an otai n. The
defintonothf rentionpowilicy th
ical. By default, in Jav an otai ns can ot be intercpd at runtime. You ned to
expsthlicyoef mat eonca ie trcpan otai nsetbhyrng e tionpolicy
to RUNTIMETh. e
an otai n for. By default, you can an otae ny languae lment,s but is’ always
go thdianreosc otai not whly yoatumafoitr—ke inomeucase, r thods:
@Retention(RetentionPolicy.RUNTIME)crit-s
@Targetan otai nspwhecif ichlanguelma enwets canuthse i
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ToLog {
}
In the fol wing listng, you find the definton of the
now defines thre methods. We an otaed only the
expctheaspctwilintercponlythisone.
Enables the annotation to
be intercepted at runtime
Restricts this annotation to only be used with methods
CommentService clas, which
deleteComment() method, so we
142
CHAPTER 6
Listing 6.10
Using aspects with Spring AOP
The CommentService class defining t hree met hods
@Service
public class CommentService {
private Logger logger = Logger.getLogger(CommentService.class.getName());
public void publishComment(Comment comment) {
logger.info("Publishing comment:" + comment.getText());
}
We use the custom annotation for the
methods we want the aspect to intercept.
@ToLog
public void deleteComment(Comment comment) {
logger.info("Deleting comment:" + comment.getText());
}
public void editComment(Comment comment) {
logger.info("Editing comment:" + comment.getText());
}
}
To weave the aspect to the methods an otaed with the custom an otai n (figure
6.13), we use the fol wing AspectJ pointcu exprsion:
exprsiontorefsanmey thodan otaedwith ane otai n amed
is, n this cae, our custom an otai n). In the next lisng, you now find the aspect
clas, which use the new pointcu exprsion to weave the aspect logic to the interceptdmethods.Pretysimple,isn’ti?
Listing 6.11
@annotation(ToLog) . This
@ToLog(which
Changing t he point cut expression t o weave aspect t o annot at ed methods
Weaving the aspect to the methods
annotated with @ToLog
@Aspect
public class LoggingAspect {
private Logger logger = Logger.getLogger(LoggingAspect.class.getName());
@Around("@annotation(ToLog)")
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
// Omitted code
}
}
@Aspect
public class LoggingAspect {
@Service
public class CommentService {
private Logger logger =
Logger.getLogger(LoggingAspect.class.getName());
private Logger logger =
Logger.getLogger(CommentService.class.getName());
Weaves to
@Around(" @annotation(ToLog)" )
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
// Omitted code
}
public void publishComment(Comment comment) {
logger.info("Publishing comment:" + comment.getText());
}
@ToLog
public void deleteComment(Comment comment) {
logger.info("Deleting comment:" + comment.getText());
}
}
Figure 6.13 Using an Aspect J point cut expression,
we weave the aspect logic t o any met hod annotat ed
wit h t he cust om annot at ion we defined. This is a
comfortable way t o mark t he met hods t o which
specific aspect logic applies.
public void editComment(Comment comment) {
logger.info("Editing comment:" + comment.getText());
}
}
Implementing aspects with Spring AOP
Whenyour ntheap ,onlythean otaedmethod(
intercpd, and the aspect logs the excution of this method in the console. You
shouldseanoutputintheconsoleimilartoheoneprsntedinthenxtsnip et:
deleteComment() ,inourcase)i
Sep 29, 2020 2:22:42 PM services.CommentService publishComment
INFO: Publishing comment:Demo comment
Sep 29, 2020 2:22:42 PM aspects.LoggingAspect log
INFO: Method deleteComment with parameters [Comment{text='Demo comment',
➥ author='Natasha'}] will execute
Sep 29, 2020 2:22:42 PM services.CommentService deleteComment
INFO: Deleting comment:Demo comment
Sep 29, 2020 2:22:42 PM aspects.LoggingAspect log
INFO: Method executed and returned null
Sep 29, 2020 2:22:42 PM services.CommentService editComment
INFO: Editing comment:Demo comment
The aspect intercepts only the deleteComment()
method, which we annotated with the custom
@ToLog annotation.
6.2.4
Other advice annotations you can use
Inthisecton,wediscualternativedcan otai nforaspectinSpring.Sofairn
this chapter, we’ve used the advice an otai n
of the advice an otai ns in Spring ap s becaus you can cover any implementaion
case: you can do things befor, afte or evn instead of the intercpd method. You
canalterhelogicanywayouwantfromtheaspct.
But you don’t necsarily ways ned al this flexbity. A go d idea is to l ok f r
the most straightforward way to implement what you ned to implement. Any ap
implementaion should be defined by simplicty. By avoidng complexity, you make
the ap easir to maintain. For simple scnarios, Spring ofers our altenative dvice
an otai ns that are les powerful thna
whentheircapbiltesarnoughtokeptheimplementaionsimple.
Otherthan
@Around ,Springofersthefol wingadvicen otai ns:
@Around . This nde the most used
@Around . It’s recommende you use thes
@Before —Cals the method defin g the aspect logic befor the excution of
theintercpdmethod.
@AfterReturning —Cals the method defin g the aspect logic after the
methodsucef lyretuns,andprovidesthertunedvalueas parmetro
the aspect method. The aspect method isn’t caled if the intercpd method
throwsanexcption.
@AfterThrowing —Calsthemethod efin gtheaspctlogiftheintercpd
methodthrowsanexcption,andprovidesthexcptioninstanceasparmeteroheaspctmethod.
@After —Casl ht e meht od dnife g ht e psa tce olcig onyl retfa ht e ni pecrtd
meht od ucex oit n, whhte r ht e meht od usfecyl uter nde or ht wer na
pecx oit n.
You sethesadvicen otai nsthesamewayasfor
anAspectJointcuexprsiontowehave asplot emecgi f thodexcutions.
@Around .Youprovidethemwith
143
144
CHAPTER 6
Using aspects with Spring AOP
Thaspe mect thods onthreciv’
not deci when to delgat o the intercped method. This evnt alredy hap ens
basedonthane otai np’s urpo(fexasmr pfole,r
calwilawayshap enafterheaspctlogiexuton).
You find an example that use
ex5.” In the next code snip et, you find the
Observthaweuseithesamewaywedi with
The AspectJ pointcut expression specifies
which methods this aspect logic weaves to.
@Aspect
public class LoggingAspect {
ProceedingJoinPointparmanetr, dthcaney @Beforeth, ine trcpedmethod
@AfterReturning in the project named “sq-ch6@AfterReturning an otai n used.
@Around .
Optionally, when you use @AfterReturning, you can
get the value returned by the intercepted method. In
this case, we add the “ returning” attribute with a
value that corresponds to the name of the method’s
parameter where this value will be provided.
private Logger logger = Logger.getLogger(LoggingAspect.class.getName());
@AfterReturning(value = "@annotation(ToLog)",
returning = "returnedValue")
public void log(Object returnedValue) {
logger.info("Method executed and returned " + returnedValue);
}
The parameter name should be the same as the value
of the “ returning” attribute of the annotation or
missing if we don’t need to use the returned value.
}
6.3
The aspect execution chain
Inalourexma plesthusfar,wediscuedwhathap enswhenoneaspectintercpsa
method. In a rel-world ap , a method is often intercpd by more than one aspect.
For example, we have a method for which we want to log the excution and ap ly
some scurity constraints. We often have spect akni g care of such responsiblte,
so we have two aspect acting on the same method’s excution in this scenario.
Ther’s nothing wrong with having as many aspect as we ned, but when this hpa pens,wenedtoask urselvthefol wingquestions:
Inwhichorde oesSpringexcuthesapct?
Doesthexcutionordemater?
Inthisecton,we’lanalyzenexampletoanswerthestwoquestions.
Sup osfe, mear thodwe, nedtoap soly mescurityonweas loas itg
excutions.Wehavetwoaspecthatkecrofthesrponsiblte:
SecurityAspect —Applies the security resticons. This aspect intercps the
method, validtes he cal, nd in some conditons doesn’t forward the cal to
the intercpd method (the details about how the
aren’t relvant for our curent discuon; just remember that sometimes this
aspectdoesn’tcalheintercpdmethod).
LoggingAspect —Logs the begin ing and end of the intercpd method
excution.
Whenyouhmuave ltipas ewect avedtohsame mee thodth, ney dtoexcut one
afternother.Onewayistohavethe
SecurityAspect works
SecurityAspect excutfirsandthendelgat
The aspect execution chain
145
tohe
LoggingAspect,whichfurthdoerlignats ercptdmethodTh. second
optionistohavethe
LoggingAspect excutfirsandthendelgatohe
Aspect , which evntualy delgats further to the intercpd method. This way, the
a spe ct r a n ex cu tio nc h ain .
Thoe rdeinwhicht aespctxuimse portanbt ecausx tinhg asepct
in difernt ordes can have difernt result. Take our example: we know that the
SecurityAspect doesn’t delgat he xcution in al the cas, o if we cho se this
aspect o excut frs,i ometimes the
LoggingAspect won’t excut. If we expct he
LoggingAspect to log the xcutions tha filed due to security escons, this n’t
thewaywenedtog (fiure6.14)
In some cases, the SecurityAspect doesn’t
further delegate. So if the SecurityAspect
is executed first, the LoggingAspect won’t
always have the chance to execute. In such
a case, the method calls won’t be logged.
Security-
Aspect execution chains
Main
SecurityAspect
LoggingAspect
CommentService
main()
secure()
log()
publishComment()
Main
LoggingAspect
SecurityAspect
CommentService
main()
log()
secure()
publishComment()
If we expect the LoggingAspect to log all the calls,
even those that were rejected by the SecurityAspect,
we need to make sure the LoggingAspect executes first.
Figure 6.14 The aspect execution order mat t ers. Depending on your app’s requirements, you need t o choose
a specific order for t he aspect s t o execute. In t his scenario, the LoggingAspect cannot log all t he met hod
executions if t he SecurityAspect execut es first .
Okay,thexcutionordeoftheaspctiometimesrlvant.Butcanwedefinethis
ordthe nBy? defauSplt, rindg oesngu’t arnthe ordine whichtwoaspinect he
same xcution chain are cld. If the xuc tion orde is not relvant, hen you just
ned to define the aspect and leav the framework to excut them in whatevr
orde. If you ned to define the aspect’ excution orde, oy u can use the
@Order
146
CHAPTER 6
Using aspects with Spring AOP
an otai nTh. anis otai nrecaivs ordin(al umbrep) sntinhg oe rdine
the excution chain for a specif aspect. The smaler the number, the earli that
aspect excuts. If two values are the same, the orde of excution is agin not
defined.Let’sryhe
@Order an otai ni anexample.
Inthpe ronject amed“sq-chdI6-ex,” fintwe oaspthec ina tercphe
Comment() methodofa
CommentService bean.Inthenextlisng,youfni dtheaspect
n am e d
LoggingAspect .Wedon’tni talydefineanyordefor uraspect.
Listing 6.12
publish-
The implement at ion of t he LoggingAspect class
@Aspect
public class LoggingAspect {
private Logger logger =
Logger.getLogger(LoggingAspect.class.getName());
@Around(value = "@annotation(ToLog)")
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info("Logging Aspect: Calling the intercepted method");
Object returnedValue = joinPoint.proceed();
logger.info("Logging Aspect: Method executed and returned " +
returnedValue);
return returnedValue;
}
The proceed() method here delegates further in
the aspect execution chain. It can either call the
next aspect or the intercepted method.
}
Thescondaspect we define for urexampleisnamed
the fol wing listng. To kep our example simple and alow you to focus on the discusion, this apect doesn’t do anything special. Like the
mesageintheconsole, weeasilyobservwhenitsexcud.
Listing 6.13
SecurityAspect ,as hownin
LoggingAspect , it prints a
The implement at ion of t he SecurityAspect class
@Aspect
public class SecurityAspect {
private Logger logger =
Logger.getLogger(SecurityAspect.class.getName());
The proceed() method
here delegates further
in the aspect execution
chain. It can call either
the next aspect or the
intercepted method.
@Around(value = "@annotation(ToLog)")
public Object secure(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info("Security Aspect: Calling the intercepted method");
Object returnedValue = joinPoint.proceed();
logger.info("Security Aspect: Method executed and returned " +
returnedValue);
The aspect execution chain
147
return returnedValue;
}
}
The
CommentServicesimclas thonweelair definedthprevioxamus pBules. t
tomakeyoureadingmorecomfortable,youcanlsofinditnthefol winglistng.
Listing 6.14
The implement at ion of t he CommentService class
@Service
public class CommentService {
private Logger logger =
Logger.getLogger(CommentService.class.getName());
@ToLog
public String publishComment(Comment comment) {
logger.info("Publishing comment:" + comment.getText());
return "SUCCESS";
}
}
Also, remember that both aspect ned to be beans in the Spring contex. For this
example,Ichoset use the
figuratonclasiprentednext.
Listing 6.15
@Bean ap roach toad thebansinthecontex.Mycon-
Declaring t he aspect beans in t he Configuration class
@Configuration
@ComponentScan(basePackages = "services")
@EnableAspectJAutoProxy
public class ProjectConfig {
@Bean
public LoggingAspect loggingAspect() {
return new LoggingAspect();
}
Both aspects need to be added as
beans in the Spring context.
@Bean
public SecurityAspect securityAspect() {
return new SecurityAspect();
}
}
The
main() method cals the
bean. In my case, the output afer the xcution lo ks lie the one in the next code
snip et:
publishComment() method of the
CommentService
148
CHAPTER 6
Using aspects with Spring AOP
The LoggingAspect is called first and
delegates to the SecurityAspect.
The SecurityAspect is
Sep 29, 2020 6:04:22 PM aspects.LoggingAspect log
called second and
INFO: Logging Aspect: Calling the intercepted method
delegates to the
Sep 29, 2020 6:04:22 PM aspects.SecurityAspect secure
intercepted method.
INFO: Security Aspect: Calling the intercepted method
Sep 29, 2020 6:04:22 PM services.CommentService publishComment
The intercepted
INFO: Publishing comment:Demo comment
method executes.
Sep 29, 2020 6:04:22 PM aspects.SecurityAspect secure
The intercepted
INFO: Security Aspect: Method executed and returned SUCCESS
method returns to
Sep 29, 2020 6:04:22 PM aspects.LoggingAspect log
the SecurityAspect.
INFO: Logging Aspect: Method executed and returned SUCCESS
The SecurityAspect returns
to the LoggingAspect.
Figure 6.15 helps you visualze the excution chain and understand the logs in the
console.
2. The LoggingAspect delegates
to SecurityAspect.
1. The LoggingAspect is the
first to intercept the call.
3. The SecurityAspect executes
and delegates to the
intercepted method.
Main
LoggingAspect
SecurityAspect
CommentService
main()
log()
secure()
publishComment()
6. The LoggingAspect returns
to main().
5. The SecurityAspect returns
to LoggingAspect.
4. The intercepted method
returns to the SecurityAspect.
Figure 6.15 The execut ion flow. The LoggingAspect was first to int ercept t he met hod call. The
LoggingAspect delegat es furt her in t he execut ion chain t o the SecurityAspect , which furt her
delegat es t he call t o the int ercepted method. The intercept ed met hod ret urns to t he SecurityAspect ,
which ret urns furt her to t he LoggingAspect .
To revs the orde in which
the
@Orderan otai nOb. inserv thne coxt dsne ip het owuI sedthe
taion to specify an excution posit n for
project“sq-h6-ex7”):
LoggingAspect and
@Aspect
@Order(1)
public class SecurityAspect {
// Omitted code
}
SecurityAspect excut, we use
@Orderan o-
SecurityAspect (se this example in the
Gives an execution order
position to the aspect
The aspect execution chain
Forthe
presntedinthenextsnip et:
LoggingAspect ,Iuse
149
@Order toplacetheaspctinahig eroderposit n,as
@Aspect
@Order(2)
public class LoggingAspect {
// Omitted code
}
Places the LoggingAspect
as second to be executed
Rerun the ap licaton and observ tha the orde in which the aspect excut has
changed.Thelogingshouldnowlo klietheoneinthenxtsnip et:
The SecurityAspect is first to intercept the method call and
delegates further in the execution chain to LoggingAspect.
The LoggingAspect executes
and delegates further to the
intercepted method.
Sep 29, 2020 6:38:20 PM aspects.SecurityAspect secure
INFO: Security Aspect: Calling the intercepted method
The intercepted
Sep 29, 2020 6:38:20 PM aspects.LoggingAspect log
method executes
INFO: Logging Aspect: Calling the intercepted method
and returns to the
Sep 29, 2020 6:38:20 PM services.CommentService publishComment
LoggingAspect.
INFO: Publishing comment:Demo comment
Sep 29, 2020 6:38:20 PM aspects.LoggingAspect log
The LoggingAspect
INFO: Logging Aspect: Method executed and returned SUCCESS
executes and
Sep 29, 2020 6:38:20 PM aspects.SecurityAspect secure
returns to the
INFO: Security Aspect: Method executed and returned SUCCESS
SecurityAspect.
The SecurityAspect returns to the main()
method, which made the initial call.
Figure 6.1 helps you visualze the excution chain and understand the logs in the
console.
2. The SecurityAspect delegates
to LoggingAspect.
1. The SecurityAspect is the
first to intercept the call.
3. The LoggingAspect executes
and delegates to the
intercepted method.
Main
SecurityAspect
LoggingAspect
CommentService
main()
secure()
log()
publishComment()
6. The SecurityAspect
returns to main().
5. The LoggingAspect returns
to SecurityAspect.
4. The intercepted method
returns to the LoggingAspect.
Figure 6.16 The execut ion flow aft er changing t he order of t he aspect s. The SecurityAspect was first t o
int ercept t he met hod call and delegat es furt her in the execut ion chain t o t he LoggingAspect , which furt her
delegat es t he call t o t he int ercept ed met hod. The int ercept ed met hod ret urns t o t he LoggingAspect , which
ret urns further to t he SecurityAspect .
150
CHAPTER 6
Using aspects with Spring AOP
Summary
An aspect is an object that intercps a method cal na d can excut logic
befora,tndevni steadoexfcutintghientercpdmethodTh. ihs elps
you decouple part of the code from the busines implementoai n and makes
yourap easirtomaintain.
Usni a gspyoect,uanwrlothiegcxuawit es tmeha thodexcutionwhile
being complety decoupled from that method. This way, someone who reads
thecodeonlysewhat’srelvntregadingthebusinesimplementaion.
Howevr, aspect can be a dangerous to l. Overnginering your code with
aspwiectmal youkaepmarls intainaYboleud. on’tuedaspovry- ct
wher.Whenusingthem,makesurtheyralhelpyourimplementaion.
Aspects up ort many esntial Spring capblites k transactions and securingmethods.
To defni e an aspect in Spring, you na otae he clas implementing the aspect
logicwiththe
@Aspect an otai n.ButrememberthatSpringnedstomanage
aninstanceofthiscla,oy unedtoals d abenofitsypeintheSpring
contex.
To tel Spring which methods an aspect neds to intercp, you use AspectJ
pointcu exprsions. You write thes pex rsions as values to advice an otations. Spring ofers you five advice an otai ns:
@AfterThrowing ,and
@AfterReturning .Inmostcaeweuse
alsothemostpowerful.
Multipe aspect can intercp the same method cal. In this case, it’s recommende that you define an orde for the aspect o excut using the
a n o ta i n .
@Around , @Before , @After ,
@Around ,whichs
@Order
Part2
I
Implementaio
npyo2,art ulea’rntoimpelmenapt us inSpg rni capg blyiotes uo’l ften
ned in the ral world. We’l star by discung web ap s. Further, you’l eran
howtoexchandgebat wenap ans dwowirk thpersitdYoat.ufin’l dtha
Springmakesthistraghtforwardndeasy.We’lendthebo kwithwritngunit
andintegraiontesforhefunctionalitesyouimplementinyourSpingap s.
The skil you’l learn in part 2 rely on understanding the foundation tha
sup ortsSpring:theSpringcontexandaspect.Youcan stardeictlywith part
2 if you alredy know how Spring contex and aspect work and you’re ag to
implement ap s that use Spring capbiltes. Howevr, if you are not ye confident with the Spring contex and aspect, i s a betr idea to star with part 1
andlearnthesthingsfirt.
UnderstanigSp
BotandSprigMVC
This chapter covers
Implementing your first web app
Using Spring Boot in developing Spring apps
Understanding the Spring MVC architecture
Now that you know al the ned Spring basic, let’ focus on web ap s and how
youSpse rintogimplementhemYo. ucanuthlaseSprincapg bweitles d’ve iscused to mi plement any kind of ap . But often with Spring, the ap licatons you
implementarewebap s.Inchapters1hrough6,wediscuedtheSpringcontex
and aspect that are mandatory for understanding what comes next in the bo k
(including what youl’ find in this chapte.r) If you jumped directly o this chapter,
andyoudonk’t owhyet owtowowirk th Spe rincog natex daspyoect, umight
find our discuon difcult o understand. I strongly recommend you make sure
youknowthebasicofusingtheframeworkbeforg ingfurther.
Spring makes web ap devlopment sraightforward. We’l star his chapter by
discungwhatwebap sarendhowtheywork.
153
154
CHAPTER 7
Understanding Spring Boot and Spring MVC
Toimplementwebap s,we’luseaprojectinhSepringecosytmnamedSprni g
Boot.Insection7.2,we’ldsciuSpringBootandwhyit’sentialnap implementaions. In section 7.3, wel’ discu the standar architecur of a smi ple Spring web
ap , and we’l implement a web ap using Spring Boot. At the nd of this chapter,
you’l understand how a web ap works, and you’l be a le to implement a basic web
ap withSpring.
Thsi chapter’s main purpose i to help oy u understand the foundatoi n that supports web ap s’ implementaion. In chapters 8 and 9, we wil implement the major
capbitles you find in most web ap s in production. But evrything we discu in
thesnextchapterslionthefoundationinthischapter.
7.1
What is a web app?
Inthsecionwe, lowhatk weat bap mI’is. suyore u wese bap ds Yoaily. uprobably just left a few tabs open in a web browser befor staring to read this chapter.
Maybe you don’t evn read this bo k on pa er and use the Man ing liveBo k web
ap forthis.
Any pa you aces through your web browser is a web ap . Years ago, we used
desktop ap s instaled on our computers for almost anything we were doni g (fiure
7.1)Withtime,mostofhesap sbecameacsiblevaweb rowser.Accesingan
ap inba rowmaser moiktes core mfortabole uYsoe. udonh’t aveoinasntl yhing,
and you cna use it from any devic that has ce to the internet, such as table or
smartphone.
Figure 7.1 Times change. In t he 1990s, we used a deskt op app for everyt hing. Today, almost any application
we use is a web app. As developers, it ’s essential you learn how to implement web apps.
What is a web app?
155
In this ecton, I want o make sure you have clera overiw of what we’re going to
implemenWht. wea is tbap an, dwhdat owenedtobuildandexcus t chanp ?
Onwepyoclearituhpbf weave ,continuime plementiongwie thSpring.
7.1.1
A general overview of a web app
orfwewhmpasitbohl giakcneltsvh-oidwecekantlhpI ,soin.t
Thwoeisvr lawusot ducsinf htr doeliaturpoitnofaerscweg bpa .s
First,awebap iscomposedoftwoparts:
The clint sde i what he user directly nteracs with. A web browser presnts
the client side of a web ap . The browser sends request to a web serv,
recivs ponse from it, and provides a way for the user to interac with the
ap .Wealsoreft heclintsideofawebap asthefront.d
Thesrvidc questfromtheclintandsendsbackdtinresponse.
Thservidmplemenlots ghic atprocesandsometimsteorhclient
requestd dat befor sending a response. We also ref to the srv ide of a
webap asthbaecknd.
Figure7.2psentshebigpctureofawebpa .
Frontend
The web client
(browser) directly
interacts with
he user.
Backend
The web client makes
requests to the web
server to get or
process specific data.
The server-side app sometimes
needs to store, get, and change
data in a database.
The user
REQUEST: Give me the product list
page I need to display.
RESPONSE: Here is what you need
to display to the user.
The web client uses the data
it gets from the server to
display something.
The web server gets the client requests
and processes the data it receives. In
the end, the server responds to the
client’s request.
Figure 7.2 The big pict ure of a web app. The user int eract s with t he app through it s front end. The front end
communicates wit h the backend to execut e logic at t he user’s request and get the dat a to display. The backend
executes business logic and sometimes persists data in a dat abase or communicates wit h ot her external services.
156
CHAPTER 7
Understanding Spring Boot and Spring MVC
Whendiscungwebap s,weus alyreftoaclientandaserv,buti’smportant
tokepinmindthat be ackndmuserv ltipcenots ncurenNutly. meroups eople may use the same ap at he same time on difernt platforms. Users can aces
theap throughabrowseronacomputer,phone,tablndso n(figure7.3)
Frontend
Backend
User
REQUEST: Send my order and
make the payment.
RESPONSE: Could you please
authenticate first?
User
REQUEST: Give me the product list
page I need to display.
RESPONSE: Here is what you need
to display to the user.
REQUEST: Could you
cancel my order?
User
RESPONSE: Done.
Figure 7.3 When discussing web apps, we refer t o t he client as being one instance, but keep in mind that
multiple users access a browser and use t he same web app concurrent ly. Each user makes t heir own request s
on specific act ions t hey need to execut e. This is import ant because it means that some operat ions on the
backend execut e concurrent ly. If you writ e code that accesses and changes the same resource, your app might
wrongly behave because of race condition scenarios.
7.1.2
Different fashions of implementing a web app with Spring
Inthsiectonwe, discuthewomaindesignysoucanusteoimplement wea bap lication. We’l implement ap s in both thes ways in chapters 8 through 10, and we’l
discu the implementaion details when we go depr into implementi g each. But
What is a web app?
157
for now I want you to be aware of your choices and have general understanding of
thes optoi ns. tI’ important o know how you can creat your web ap to avoid gettingconfusedlatrwhenimplementi gexamples.
Weclasifytheap roachesofcratingawebap asthefol wing:
1
2
Aps wher t backend provis the fuly pread viw in respo t a client’s rqu.
Thbe rowdser inctly erpths de ratciv fomthbe ackndand isplay
thisnformationtoheuserinthesap s.Wediscuthisap roachandimplementasimpleap toproveitnthischapter.Wethenconti ueourdiscuon
withmorecomplexdtaisrlevntoproductionap sinchapters8nd9.
AfruonsitFedpg-bacokh. rpes ths,beackndonrawsev ly
dat. The browser doesn’t display the dat in the backend’s reponse directly.
Thbe rowruse nsepa frot ntendap thgesat backendresponpse, roces the dat, and instruc the browser what to display. We discu this
a p ro a ch a n d im p lem e n tex a m p le so fit n ch a p ter 9.
Fpigu7.4 resnthapsfir e rocha inwhicht ape doesnfroua’tnse tnd-backend
separtionF.othr aeps alms, oevstryhni hg ap enos nthbe ackndsi The. be ackend gets rquest rpesnti g user actions and excuts ome logic. In the nd, the
respv ondwis thwhthaberownser dtos ipThlay. beackndrespondwis th e
dinatformthas tberowcanseri terpand ispulay, chHTML,
s CSS, images,
andsonca Itlsoe. dscripwrt itenlanguthaes tberowcanesrunderstand
andexcut(s chasJvScript).
Frontend
Backend
The user
REQUEST: Give me the product list
page I need to display.
RESPONSE: Here is precisely what
you need to display to the user.
HTML/CSS/JavaScript
In a standard web app, the client receives
a response from the server containing
exactly what the browser needs to
display. The server-side app sends data
in HTML, CSS, and JavaScript formats
that the browser interprets and displays.
Figure 7.4 When a web app doesn’t provide front end-backend separat ion, t he browser precisely displays what
it get s from t he server. The server gets request s from the browser, executes some logic, and then responds. In
response, t he backend provides cont ent format ted as HTML, CSS, and other fashions that t he browser int erprets
to display.
158
CHAPTER 7
Understanding Spring Boot and Spring MVC
Figure 7.5 shows an ap using frontend-backend separtion. Compare the serv’
responseinfgiure7.5withthersponsethesrvndsbackni figure7.4Insteadof
teling the browser precisly what o dispyl,a the srv now only sends raw dat. The
browser runs an indepndent frontend ap it loads at an intial request from the
serv. This frontend ap takes the serv’ raw response, interps it, and deci s
how the information is displaeyd. We’l discu more details about this ap roach in
chapter9.
Frontend
Backend
REQUEST: Give me the product list
page I need to display.
RESPONSE: Here is the
JSON-formatted list of products. It’s
you who decides how to display it.
When we use frontend-backend separation,
the server sends raw data to the client.
For example, it might send just the list of
products in a specific format. The client
uses this data and decides how the browser
will display it.
Figure 7.5 Using front end-backend separation. The server doesn’t respond wit h t he exact dat a t hat needs t o
be displayed by t he browser. The backend sends t he dat a t o the client but doesn’t tell t he browser how t o
display this dat a or what t o do wit h it . The backend now only sends raw dat a (usually in an easily parsable
format like JSON or XML). The browser execut es a frontend app t hat t akes t he server’s raw response and
processes it t o display t he data.
You wil find both thes ap roaches in production ap s. Sometimes devlopers f
tohefrontend-backendsepartionap roachabs einagmodernap roach.Thseparation of ront- and backend helps in making the devlopment easir to manage for
large ap s. Difernt teams take the responsiblty of implementing the back- and
frontend, alowni g more devlopers to colaborate to devlop the ap s. Also, the
deployment of the front- and the backend can be indepndently managed. For a
largep ,thisflexbtyaonicebnefit.
The other ap roach that doesn’t use frontend-backend sepration is mostly for
smalp s.Afterdiscunbg othap roachesindetaIi’l,chyouthaedvntageos f
both methods, and you’l know when to cho se an ap roach based on your ap ’s
n e d s.
What is a web app?
7.1.3
159
Using a servlet container in web app development
In this section, we more deply anlyze what and why you ned to build a web ap
withSpring.Thusfarwe’vesnthatwebap hasfronte dandabckend.Butwe
di n’texplictydiscumi plementingawebap withSpring.Ofcourse,ourpurpose
tios learnSprinag dtoimplemenapt wis thsio, wehtaove spk forwardnd
findoutwhatwenedtoimplementwebap swithheframework.
One of the most important hings to consider is the communicaton betwen the
clienta dthserv.Aweb rowsuer aprot colnamedHypertTrx ansfPer ot col (HTTP) to communicate with the serv over the network. This prot col acurately describ how the client and the serv exchange dat over the network. But
unyoles upare isonabte ount eworkinyog, udon’t edtounderstandhowHTTP
works in detail o write web ap s. As a sowft are devloper, you’re xpectd to know
tha the web ap compone ts use this prot col to exchange dat in a requestresponse fashion. The client sends a request o the serv, and the serv responds.
The client waits for the response after evry requtes it sends. In ap endix C, you’l
find al the details you ned to know about HTTP to understand the discuon in
chapters7hrough9.
But does that mean your ap neds to know how to proces the HTTP mesage?
Wel, youcanimplementhiscapbiltyf ouwish,butunlesyouwantohavesome
fun writng low-lev functionalite,s you’l use a compone t alredy designed to
understandHTTP.
In fact, what you ned is not only something tha understands HTTP, but somethintghcatnr slateheHTTPrequeanst drespontsoe Javp Th. siomething
is a ervlt conaie (sometimes rfd to as web serv): a trnslator of the HTTP
mesfoageyr uapJvr Th. wais yo, uapJvr doens ’t edtocarekimf plementing the communicaton layer. One of the most ap reciatd servlt container
implementaions i Tomcat, which is alo the depndency we’l use for the xamples
inthisbo k.
WeuTose mcafot hr exampinles thbis o bk, uyot ucanualitsernatives for your Spring ap . The list of solutions used in real-world ap s is
long. Among thes, you find Jety (
( hwtp/ww.s: jbos. rg/
NOTE
Fgiure 7.6 is a visual repsntaion of a servlt container (Tomcat) in our ap ’s
architecur.
But if this evrything a servlt container does, why name it “servl” container?
What is a servlt? A servlt is nothing more than a Jv object hat directly nteracs
withthesrvltcontainer.WhenthesrvltcontainergtsanHTTPrequest,ical
servlt object’s method and provides the request as a parmetr. The same method
also gets a parmetr presnting the HTTP response used by the srvlt o set he
responsentbackotheclinthatmadetherquest.
),andPayr(
hwtp/ww.s: ecilps.org/jety
hwtp/ww.s: payr.fish/
), JBos
).
160
CHAPTER 7
Understanding Spring Boot and Spring MVC
The client uses the HTTP
protocol to communicate with
the server-side app.
HTTP REQUEST
The Spring app implements the
logic requested by the client,
but it cannot get the HTTP
requests on its own.
Tomcat
servlet
container
Spring app
HTTP RESPONSE
A web server takes care of what’s
needed to communicate with the
client using the HTTP protocol.
The web server gets the client’s requests
and transforms them into objects the
app understands. It also gets the details
from the Spring app and sends them
back to the client in a proper HTTP
response form.
Figure 7.6 A servlet container (e.g., Tomcat ) speaks HTTP. It t ranslates the HTTP request t o our Spring app
and the app’s response into an HTTP response. This way, we don’t need to care about the protocol used for
communication on the net work, as we simply writ e everyt hing as Java object s and met hods.
Some time ago, the servlt was the most crital compone t of a backend web ap
fromthde vloper’s oinotviewf Su. p odase vlopher adtoimplemenat ewpage
acesibptl ecif athinthURL
e (e/.g, home/profile/dfoetic.), wear bap .
Thedvloperned tocreanewservltinstance,onfiguretinthesrvltcontainer, dasigntopecif ath(figuTh7.)re coservlt ntainedthloeasgic ciatedwiththeusr’equestandtheabiltyopre a response,includinginfo r
thbe rowoser nhowtodispthlay responFse.oanr py ath wee bclienot uldctha, e
devloper ned to ad the instance in the servlt container and configure it.
Because such a component manages servlt instances you ad into its contex, we
name it a servlt contai er. It basicly has a contex of servlt instances it controls,
juSpast rindg owies thbis eanFs.othr easoi nwe, coalmpone sut chToas mcat
aservltcontainer.
Asyoulearn’ i thcis apweter, dontyp’inservlca tnWeces. u’lase
servlt with the Spring ap s we devlop with Spring, but you won’t ned to write his
What is a web app?
161
The servlet container translates
the HTTP request and response
to Java objects when calling the
servlet associated with the path.
When the client sends a request
to a specific path, the servlet
container calls the servlet registered
at that specific path.
HTTP REQUEST
HTTP GET /Invoice
Tomcat
servlet container
ProductPageServlet
/product
ClientPageServlet
/client
InvoicePageServlet
/invoice
HTTP RESPONSE
PaymentPageServlet
/payment
The servlet container registers multiple
servlet instances. Each servlet is a Java
object registered for a specific path.
Figure 7.7 The servlet cont ainer (Tomcat) registers multiple servlet inst ances. Each servlet is associated wit h
a path. When t he client sends a request , Tomcat calls a method of t he servlet associat ed wit h the pat h t he
client request ed. The servlet get s the values on the request and builds t he response that Tomcat sends back
to t he client .
yourself, so you don’t have to focus on learni g to implement servlt. But you do
ned to remember the srvlet is the ntry point o your ap ’s logic. It’s he component he srvlet container (Tomcat, in our case) directly interacs with. It’s how the
requestdat entrsyourap andhow thersponsego throughTomcatbkto he
client(figure7.8)
The Spring web app defines a servlet
object. We register this object, so Tomcat
calls it for any path of the client’s request.
This servlet becomes the entry point to
our app’s logic.
Tomcat
servlet container
Spring app
HTTP REQUEST
HTTP RESPONSE
Spring app’s servlet
Figure 7.8 The Spring app defines a servlet object and registers it int o the servlet cont ainer. Now bot h Spring
and the servlet cont ainer know this object and can manage it . The servlet cont ainer calls this object for any
client request , allowing t he servlet to manage t he request and the response.
162
7.2
CHAPTER 7
Understanding Spring Boot and Spring MVC
The magic of Spring Boot
To creat Spring web ap , we ned to c nfigure a svlt contai er, cat servl
instance, na d then make sure we coretly configure this servlt instance such that
Tomcat cals it for any client request. What a headche to write so many configurations! Many ears go, when I was teaching Spring 3 (the lats Spring version at hat
timane) dweconfiguredwebap ths, wai ths pe bart oth steudenats dhI atedhe
most. Fortunate,ly imes changed, and today I don’t have to bother you by teaching
suchonfiguratons.
In this ecton, we’l discu Spring Boot, a o l for implementing modern Spring
ap s. Spring Boot is now one of the most ap reciatd projects in the Spring ecosytem. It helps you creat Spring ap s more ficntly and focus on the busines code
youwritebyeliminat gahugepartofthecodeyou sedtowriteforc nfiguratons.
Espinecaly worldoservicf- ntedarchitecu(SOrs A)andmicrosewhvi, er
you creat ap s more often (discued in ap endix A), avoidng the pain of writng
configuratonsihelpful.
Listed her are what I consider the most crital Spring Boot featurs, and what
theyofr:
Simplifed project creation —You can use a project intalizon servic to get an
emptybutconfiguredskltonap .
Dependyc stare —Spring Boot groups certain depndencies used for a specif purpose with depndency stare. You don’t ned to figure out al the
must-hdave pendenyocies unedtoa dtoy upr ofject r npe articupl urposenorwhichversionsyoushoulduseforc mpatibly.
Autocnfigra based on depn cis —Based on the depndencies you ad ed
to your project, Spring Boot defines some default configuratons. Instead of
writng al the configuratons yourself, you only ned to change the ones provdi e by Spring Boot that don’t mahtc what you ned. Changing the confgis
likeyrquireslcode(ifany).
Let’s discu thes esntial featurs of Spring Boot more in-depth and ap ly them.
ThefirstxampleisthefirstSpngwebap wewrite.
7.2.1
Using a project initialization service to create a Spring Boot project
Inthis ecton,wediscu usingaprojectinitalzonservictocreat SpringBoot
project. Some people don’t consider the project intialzon servic a much, but I
can’t el you how thankful I am this featur exist. As a devol per, you don’t crea
multipe rodajectsy,oudonthes’ faui bre’sadig vnFtage.obr thsudents
and teachers who write numerous Sprni g Boot projects a day, this featur spare you
hours of work on reptiv, insgnifcant actions you’d ned to do if you stared a
profject mscrathTo. learnhowcanit helpyoule,t’s pa roinject ialzonservicetorapojectnamed“sq-ch7-ex1.”
Some IDEs integra directyl with a project intialzon servci, and some don’t.
For example, in InteliJ Ultimate or STS, you’l find this featur avilbe when creatinganewproject(figure7.9)—butifyou seInteliJCommunity,oudon’t.
The magic of Spring Boot
163
From the New Project menu, select
the Spring Initializr project type.
Figure 7.9 Some IDEs integrat e wit h a project initializer service directly. For example, in Int elliJ Ult imate, you
can select Spring Init ializr from the New Project menu t o creat e a Spring Boot app wit h a project initializer
service.
If your IDE sup orts this featur, you’l proba ly find it named Spring Initalzr in
yourproject aionmenu.ButifyourIDEdoesn’tsup ortdirectntegraion witha
Spring Boot project intialzon servic, you cna use this featur by acesing
hstar.p/in: g.io
ectyoucanimportintoanyIDE.Let’suethisap roachtocrea urfistpoject.
Thfoe l winlgisut mmaritzehs tpwes ’taloke crhSeprinBog opt roject
usingstar.ping.io(fure7.10):
1
2
3
4
5
Accestar.pinog.i naweb rowser.
Selctheprojectpropertis(languae,thevrsion,thebuildto l,andos n).
Selcthened depndenciesyouwantoad toy urpoject.
UsetheGeneratbutontodownloadthearchivedproject.
UnarchivetheprojectandopenitnyourIDE.
Onceyouacestr.ping.ionwea b rowsyer,ou’flindani terfascimilartohe
oneinfigure7.1Youhavetospecifysompe rojectpropertis,lkhebuildto lyou
pref betwen Maven and Gradle and the Jav ersion you want o use. Spring Boot
evnofersy utheposibltyochangethesyntaxofy urap toKotlinorGro vy.
directly n your bowser. This ervc wil help you creat proj-
164
CHAPTER 7
Understanding Spring Boot and Spring MVC
1. Access “ start.spring.io” in your browser.
2. Select the project properties.
Just access the link in the address bar
Language, language version, Spring Boot version, build tool
4. Use the Generate button to download
the archived project.
The project downloads as an archive.
3. Select the needed dependencies.
For the first project, you only need to select Spring Web.
5. Unarchive the project
and open it in your IDE.
You can use any IDE that supports Maven: IntelliJ,
Eclipse, STS, Netbeans, and so on.
Figure 7.10 St eps t o generate a Spring Boot project using st art .spring.io. Access start .spring.io in your
browser, select t he propert ies and t he needed dependencies, and download t he archived project . Then open
the project in your browser.
Here you will search and add
dependencies to your project.
Here you select certain properties of your project,
like the Java version, which build tool you prefer,
and even the language you’d like to use. If you
prefer to use a different syntax than Java, you can
also develop your Spring Boot project with Kotlin
and Groovy.
After configuring your project and selecting the needed dependencies,
click this button to download the project in a zip archive.
Figure 7.11 The st art .spring.io int erface. After accessing st art .spring.io, you can specify your project ’s main
configurat ions, select the dependencies, and download t he archived project .
The magic of Spring Boot
165
Spring Boot ofers us many options, but we’l conti ue using Maven and Jav 1
throughouthbe o tkepthexampcoles nsitenFt.igush712re owyos uanexmple of ilng the filds for generating a new Spring Boot project for our example. In
this example, we only ned to ad a depndency named Spring Web. This depndencyad sevrythingourpojectnedstobecomeaSpringwebap .
Click ADD DEPENDENCIES and select
Spring Web. Spring Web is the only
dependency you need for this example.
Give your
project
a name
here.
After adding the Spring Web
dependency, you see it here.
When you click on the GENERATE button,
your browser downloads a zip archive
with the Maven project.
Figure 7.12 For our example, we need t o add t he Spring Web dependency. You can add it using t he Add
Dependencies but ton on the right upper-hand side of the window. You also need to give a name t o your project .
WhenyoucliktheGeneratbuton,thebrowserdownloads ziparchivecontai ng
a Spring Boot project. Now we discu the main things Spring Initalzr configured
intoy urMavenproject(figur7.13):
TheSpringap mainclas
TheSpringBootPOMparent
Thedpendencies
TheSpringBootMavenplugin
Thepropertisfl
You ned to be aware of how your project lo ks. For this reason, we’l discu each
c o n f i g u rt a o n .
166
CHAPTER 7
Understanding Spring Boot and Spring MVC
1. The main class
2. The Spring Boot POM parent
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/>
</parent>
4. The dependencies
3. The Spring Boot Maven plugin
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
5. The properties fi le
application.properties
application.yml
Figure 7.13 When generat ing a Spring Boot project with Spring Init ializr, it makes some configurations t o the
project t hat you don’t find in a plain Maven project .
THE APP’ S MAIN CLASS CREATED BY START.SPRING.IO
The first hing to lo k at is the ap licaton’s main clas. Unarcheiv the downloade
file and open it in your IDE. You can observ that Spring Initalzr ad ed the
clastoy urap andaols meconfiguratonsinthepom.xmlfie.TheMainclasof
a Spring Boot ap is an otaed with the
lo ksimilartohenextcodesnip et:
@SpringBootApplication
public class Main {
Main
@SpringBootApplication an otai n, and it
This annotation defines the Main
class of a Spring Boot app.
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
The magic of Spring Boot
Spring Intialzr generatd al this code. In this bo k, we’l only focus on what’s relvanto uexamr pleFs.oxamr pwoIle, nd’t ewhail tha e
method oesandhowprecislySprngBootusehe
taion.Thesdtailrn’trelvantowhatyou’relani gnow.SpringBootisaubject for a whole bo k. But a some point you’l undoubtedly want o understand how
Spring Boot ap s work in detail, and for this I recommend you read Craig Wals’
SpringBotAction(Man ing,2015)andMarkHeckler’sSpingBot:UpandRunig
O’ReilyMedia,201).
167
SpringApplication.run()
@SpringBootApplication an o-
THE SPRING BOOT M AVEN PARENT CONFIGURED BY START.SPRING.IO
Second, we lo k at he pom.xml fei. I you open your project’s pom.xml fie, you’l
find that the project intialzon servic also ad ed some details her. One of the
mostimportantdeilasyou’lfindistheSpringBootparentnode,whichlo ksimilar
tohenextcodesnip et:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/>
</parent>
Onoethf sne thial nthgs pi arendt opiser vidoye u withcompatibversol nfosr
thde pendencyiesouad’l toy upr oject.Y uo’l bserthv weat donsp’t veracfy-i
dsioaepnf r denweiucymose Wecase. t (anrecoltmid’s mendeSp)rinBog ot
cho sethevrsionofadepndencytomaksue rwedon’truni toincompatibles.
THE SPRING BOOT M AVEN PLUGIN CONFIGURED BY START.SPRING.IO
Newext ol ht aSpke nri Bog oMat nve plungi coniguf redbp.stayinr og.whenat-cr
ni ht gpe orY.tcjufindht psi ul nig oslac nguif edr inthpe omxm. The.lfi neocxtde
ns pi hset owhts pe ul nig doitarlec nwh, hci you us nfiyla dtha endothf pe omxm. l
ni htdeslf
foadr ni pg orta hf edfauotcl nugif otar noys uol’ bnivers oy urpo:ectj
<build> <plugins> … </plugins></build>Th.gsta pesruli ong bsi el
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
THE M AVEN DEPENDENCIES ADDED BY START.SPRING.IO WHEN CREATING THE PROJECT
Alsointhepom.xmlfie,youfindthedpendencyouad edwhencreatingtheproject in star.ping.o, Spring Web. You’l find thsi depndency provdi e , as hown in
the next code snip et. I is a depndency stare named sprin-bg o t-sareweb. We
168
CHAPTER 7
Understanding Spring Boot and Spring MVC
discu what depndency stare i n detail n section 7.2 For now, know that i
doesn’tspecifyavron.
For al the xamples we have writen, we also specifd a verios n for each depndency. The reason you don’t specify one now is to let Spring Boot cho se the right
onfoeyr uAs. wediscuedinarl thsecionth, whis wey nedthSpe nri Bog ot
parentohepom.xmlfie:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
THE APPLICATION PROPERTIES FILE
Thlaestntihal nSpg ringI itadlzr edtoy upr ofnailejsct med“ap lication.propertis.” You find this fle in the rsources folder of your Maven project. nI iemis thfle iay,s exapmnthfirsyo,d thwawepLaikesl y.d’ter, isclu
usingthisfletoc nfigurepopertyvaluesyourap neds uringitsexcuion.
7.2.2
Using dependency starters to simplify the dependency management
NowthayoulearnedhowtouseaSpringBootprojectintiazlonservicandhave
a betr overiw of the Spring Boot project you creatd, let’s focus on the second
esntial advntage Spring Boot ofers: depncy staer. Dependency stare save
youplentyofime,andthey’raninvalublefaturSpingBoot fers.
A depndency stare i a group of depndencies you ad to configure your ap
for a specif purpose. In your project’s pom.xml fie, the star lo ks lie a normal
depndency, as presnted in the next code snip et. Observ the name of the depndency: A stare name us aly str with “spring-bo t-sare” fol wed by a relvnt
namethatdescribthecpa biletsad edtoheap :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Say ou want o ad web capbiltes to your ap . In the past, o configure a Spring
web ap you had to ad la the ned depndencies to your pom.xml fie yourself
andmakesurtheirvsonswerecompatibleonewiththeother.Configurngalthe
depndencies you ned is not an easy job. Taking care of the vrsion compatibly is
evnmorecomplicated.
With depndency stare, we don’t request depndencies directly. We request
capbiltes(fgure7.14)Youad adepndencystarefoparticulapbiltyou
ned, say web functionalites, a datbse, or security. Spring Boot makes ure to ad
the right depndencies to your ap with the proper compatible version for your
requestd capbilty. We can say that depndency stare are capbilty-orentd
groupsofc mpatibledpendencies.
The magic of Spring Boot
169
Without dependency starters
The application directly declares all its
dependencies. The developer needs to know
all the needed dependencies and their compatible
Depends on
versions for implementing a specific capability.
Spring app
Tomcat
<Dependency>
Depends on
Spring AOP
Depends on
<Dependency>
Depends on
Spring context
<Dependency>
<Dependency>
...
<Dependency>
With dependency starters
Spring Web (dependency starter)
Tomcat
<Dependency>
Spring app
Depends on
Spring AOP
Spring context
<Dependency>
<Dependency>
The application declares a dependency to a starter based
on the capability it needs (e.g., web). The starter
contains all the needed dependencies for that specific
capability. The developer doesn’t need to know the
exact dependencies it needs nor their compatible versions.
...
<Dependency>
<Dependency>
Figure 7.14 Using dependency st arters. Inst ead of individually referring t o specific dependencies, the app now
depends on only a st art er. The st art er cont ains all t he needed dependencies for implement ing a specific
capability. The start er also makes sure t hese dependencies are compat ible wit h one another.
Look at your pom.xml fie. You only ad ed the sprinbg- o t-sareweb depndency,
no Spring contex, no AOP, no Tomcat! But, if you lo k in the “External Libraies”
folderofy urap ,you’lfindJARarchivesforalthes.SpringBootknewyouwould
nedthemand ownloade themwithspecifvrsonsitknowsarecompatible.
7.2.3
Using autoconfiguration by convention based on dependencies
Spring Boot also provides autoc nfiguraton for your ap licaton. We say that it
ap lies the oncveit-rfguaon principle. In this section, we discu what
convention-overc nfiguraton is and how Spnri g Boot helps us by ap lying this principle.Outof al the previousSpringBootfeaursdiscuedin thischpa ter, heautoconfiguratonisproba lythemostap reciatdndthemostknown.
Just ar your ap , and you’l understand why. Yes, I know, you di n’t evn write
anything yet—only downloade the project and opend it n your IDE. But you can
star he ap , and you’l find oy ur ap bo ts a Tomcat instance by default acesibl
onport80.Inyourconsole,y ufindsomethingsimilartohenextsnip et:
170
CHAPTER 7
Understanding Spring Boot and Spring MVC
Spring Boot configured Tomcat and
starts it by default on port 8080.
Tomcat started on port(s): 8080 (http) with context path ''
Started Main in 1.684 seconds (JVM running for 2.306)
Based on the depndencies you ad ed, Spring Boot reaizls what you expct from
your ap and provdi es you some default configuratons. Spring Boot gives you the
configuratons,whicharegnerlayusedforthecapblitesyourequestdwhenad ingthedpendencies.
For example, Spring knows when you ad ed the web depndency ou ned for a
servltcontainerand configuresyouaTomcat instna ce bause,inmostcea,devlopers use this mplementaion. For Spring Boot, Tomcat is he conve tion for a sevletcontai er.
The conve tion repsnts he most-ued way to configure the ap for a specif
purpose. Spring Boot c nfigures the ap by convention such that you now only ned
to change those places wher your ap neds a more particul configuraton. With
thisap roach,you’lwritelscodeforc nfiguraton(ifany).
7.3
Implementing a web app with Spring MVC
In this ecton, we’l implement our fist web page in a Spring web ap . It’s rue we
alredy have Spring Boot project with the default configuratons, but his ap only
star Tomcat serv. Thes configuratons don’t make our ap a web ap yet! We
stil have to implement he pages tha someone can aces using a web browser. We
conti uime plementinhg “sqe ch- p7ex1” rotjecad wea bpwiage thcosai nten.
With thes changes, you’l earn to implement a web page nd how your Spring ap
worksbehindthescnes.
Toad awebpagetoy urap yo, ufol wtwostep(figure7.15):
1
2
Write an HTML document with the content you want to be displayed by the
b ro w se r.
Writeacontrolewithanctionforthewebpagecrtdapoint1.
1. Write the HTML document.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Home Page</title>
</head>
<body>
<h1>Welcome!</h1>
</body>
</html>
2. Write a controller with an action
for the HTML document to display.
@Controller
public class MainController {
@RequestMapping(" /home" )
public String home() {
return "home.html";
}
}
Figure 7.15 The st eps for adding a stat ic web page t o your applicat ion. Add the HTML document containing
the informat ion t he browser will display and then write a cont roller wit h an act ion assigned t o it .
Implementing a web app with Spring MVC
171
Inthe“sq-ch7-ex1”project,wefirstad ingasticwebpagewiththecontentwe
wantodisplaynthebrowser.ThiswebpageisjutanHTMLdocument,andfor ur
example the pgae onyl dspi lay short ex in a heading. The fol wing listng shows
you what the content of this file should lo k like. You ned to ad the file in the
“resources/tai”folderofy urMavenproject.Thisfolderisthedfaultpacewher
theSpringBootap expctsofindthepagstorender.
Listing 7.1
The cont ent of t he HTML file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Home Page</title>
</head>
In a standard HTML document,
<body>
we display a heading text.
<h1>Welcome!</h1>
</body>
</html>
The scond step you take is wrting a controle with a method that links the HTTP
requtoes hpe yoag uwanyot uapr toprovidne rps onThse. coe ntrocaislempone t of the web ap that contai s methods (often named acoti ns) excutd for a
specif HTTP request. In the nd, the controle’s action retuns a refnce to the
web page the ap retuns in response. We’l kep our first example simple, and we
wonma’t thke controexcluant spy ecloif g thr equfoestnr owWe. ju’l st
configureanactiontoreuninresponsetohecontentofhehome.htmldocument
wecreatdndstoredinthe“rsources/taic”folderinthefirstp.
Tomacoasnl rk toyel, uonly edtouhse
steroype an otai n (like
@Component and
means that Spring wil aso ad a bean of this cla to is contex o manage it. Inside
this clas, you can define controle actions, which are methods asocited with specifHTTPrequets.
Sayouwanthebrowserto displaythispage’scontentwhentheusrace the
/home path. To achiev this result, you an otae the action method with the
@RequestMapping an otai n specifyng the path as a value of the an otai n:
@RequestMapping("/home") . The method neds to retun, as a string, the name of
thedocumentyouwanthpea tosendasreponse.Thefol winglistngshowsthe
controlecasndtheactionitmplements.
Listing 7.2
@Controlleran otai na,
@Service , dicsued in chapter 4). This
The definit ion of t he cont roller class
@Controller
We annotate the class with the @Controller stereotype annotation.
public class MainController {
@RequestMapping("/home")
public String home() {
We use the @RequestMapping annotation to
associate the action with an HTTP request path.
172
CHAPTER 7
Understanding Spring Boot and Spring MVC
return "home.html";
We return the HTML document name that contains
the details we want the browser to display.
}
}
knI owyouhpave lnoty qf uestions owAl! myl studendts ohat pis oinwht entacIh
Spring clas—questionsuchast es:
1
2
3
4
Canthismethod os methingotherthanretuntheHTMLfilename?
Canitgeparmetrs?
Isawexamplesonthewebusingan otai nsotherthan
theybtr?
CantheHTMLpagecontaindynamicontent?
@RequestMapping ;are
We wil answer al thes questions with examples in chapter 8. But for the moment, I
thask oyt ufocuos nthsimpale ptounderstandwhweat juwrst oFte.yirs, uned
to know how Spring manages the request and cals this controle action we implementedCo. reuctly nderstandinthg frame ewowark’s oy maf naginthg wee brequiset
a vluable ski tha wil help you later n the details fr nd implement any featureyounedinawebap .
We now star the ap licaton, analyez its behavior, and discu, with visual, the
mechanismbehindthape thmaa thkes riuplt osibWhle. enstari hg ape yo, u
wil se the log. It els you Tomcat sred and the port i use in the ap console. If
you use the default (you di n’t configure something not explained in this chapter),
Tomcatuseport80.
Tomcat started on port(s): 8080 (http) with context path ''
Open a browser window on the same computer wher you run the ap and write he
fol wing ad res in the ad res bar: htp:
not forget to write the path /home you map ed with the controle’s action; otherwise,you’lgetaneroandanHTTPresponsewiththestau“40NotFound.”
/ locahost:80/home (figure 7.16) Do
http:// means you send requests to
the backend app using the HTTP protocol.
You use localhost because the backend app runs
on the same system as the client. Localhost means
“ local system” or “ the current system.” If your app
will be installed on a public server, this would change
to an easier-to-remember name that is accessible
on the public web (e.g., example.com).
http://localhost:8080/home
You make the request on port 8080 because
this is the port the Tomcat instance your
app started uses.
You request the “ / home” path, because this is
the path you associated with the controller’s
action using the @RequestMapping annotation.
Figure 7.16 Testing t he implement ation. Using a browser, send a request to the backend app. You need
to use t he port Tomcat opened and the pat h you specified with t he @RequestMapping annot at ion.
Implementing a web app with Spring MVC
When you access the page exposed by the app,
the browser gets the content of the home.html
HTML document in response. The browser interprets
the HTML content and displays the data. For this
app, your will see the heading text “ Welcome!”
173
Figure 7.17 Accessing
t he page in a browser,
you’ll see t he heading t ext
“ Welcome!” The browser
interprets and displays the
HTML received in response
from the backend.
Figure7.1showsyouthersultofacesingthewebpageinabrowser.
Now tha you’ve sen the ap ’s behavior, let’s discu the mechanism behind ti.
Spring has a set of compone ts that interac with each other to get the result you
observd. Figure 7.18 presnts hes compone ts and the flow in which they manage
anHTTPrequest.
1
2
3
4
5
6
7
Theclintmakesna HTTPrequest.
Tomcatgesheclint’sHTTPrequest.Tomcathastoclaservtompone t
fortheHTTPrequest.InthecasofSpringMVC,TomcatlservSpring
Bootc nfigured.Wenamethiservlt dpach.
ThedispatchersvltihentrypointofheSpringwebap .(It’shatservl
wediscuedinfguinearl7.8 thcis aplsoit’er;nfiguTo7.18)re mcat
cals the dispatcher svlt for any HTTP request i gets. I responsiblty is to
managtehrquesft rheinr sdthe Sprinagp Iht. asofindwhcaot ntrole
action to cal for the rquest and what o send back in response to the clint.
Thiservltaofdtoas“fr ntcontrole.”
The first hing the dispatcher svlt neds to do is fnd a controle action to
cal for the rquest. To find out which controle action to cal, the dispatcher
sedrvlt goasc mpone nt amedhanmalr pinThg. he andmaler p ing
finds the controle action you asocited with the rquest with the
Mapping an otai n.
Aftefinr dinog uwht ichontroaclie ntocalh, de ispatchservlcathat
specifontroleaci nIfth. ehandlemar p incgouldn’tfindanyactionasociated with the rquest, he ap responds to he clint with an HTTP “40 Not
Found”stau.Thecontroleurnsthepagnameitnedstorenderfo the
response to the dispatcher servlt. We ref to this HTML page also as “the
vie w .”
At this moment, the dispatcher selrvt neds to find the view with the name
recivd from the controle to get its content and send it as response. The dispatchersvdtl gaeshersponsibltoy fgeingthviewcontenot ac mpone tnamed“ViewResolver.”
Thedispatchersvlturnsthernder viwintheHTTPresponse.
@Request-
174
CHAPTER 7
1. The client makes
an HTTP request.
Understanding Spring Boot and Spring MVC
2. Tomcat accepts the request
and delivers it to the Spring app.
A component named dispatcher
servlet takes gets the HTTP request
and manages the flow.
Tomcat
3. The dispatcher servlet first
needs to find out what method
of the controller to call depending
on the path and HTTP method of
the request. To find the method it
uses the handler mapping.
Spring app
Handler mapping
Dispatcher servlet
4. Once it knows what controller
method to call, the dispatcher
servlet calls the method.
After execution, the controller
method provides the view name
and data that needs to be
rendered in the view.
Controller
View resolver
7. The browser interprets the HTTP
response and displays the data.
5. The dispatcher servlet finds
the view and renders it with the
data provided by the controller.
To find the view to render, the
dispatcher servlet uses a component
named view resolver.
6. Through Tomcat, the HTTP
response is returned to the client.
Figure 7.18 The Spring MVC architect ure. In t he diagram, you find the main component s of Spring MVC. These
components and t he way t hey collaborat e are responsible for a web app’s behavior. The cont roller (shaded
differently) is the only component you implement . Spring Boot configures the ot her component s.
In this chapter, I describd the handler map ing as the compone t
thafindsthecontroleaci nbytheHTTPrequestpath.Thehandlermappingalsoerchesbyomethingnamde theHTTPmethod,whichIleftiout
of my explantions for the moment so tha you can more asily focus on the
flow.Wel’discuHTTPmethodsinmoredtailnchapter8.
NOTE
Spring (with Spring Boot) considerably simplifes the devlopment of a web ap by
arngi this setup. You only ned to write controle actions and map them to
request using an otai ns. A large part of the logic s hid en in the framework, and
thishelpsyouwriteheap sfaterndcleaner.
Summary
175
In chapter 8, we continue with more details on what you can do with a controle
clas. Real-world ap s are often more complex than just retuni g the content of a
staic HTML page. In most cae, the page display dynamic details procesd by the
ap befor endering the HTTP response. But ake moment now and reviw what
youlearnedinthsichapter.UnderstandinghowSpringwebap sworkisentialfor
the next chapters’ discuons and is defintely necsary for becoming a profesi nal
Sprni dg evlop“Der. onru’t shintoealrni dg betails fopre opuerly ndetrasndinthg e
basic”ruleofthumbIusewhenlearni ganytechnol gy.
Summary
Peopleuswebap smoreoftntodaythantheyusdektopa ps.Forthisreason,youmustunderstandhowwebap sworkandlearntoimplementhem.
A web ap is an ap licaton the user interacs with using a web rowser. A web
ap has client ids e and a serv ide wher the dat is procesd and stored.
The client dsi e (fronte d) esnds request to the serv side (backend). The
backendexcutsheactionrequestdbythefrontendandrespondsback.
Spring ofers you the capbilty of impelmenting web ap s. To avoid writng
many configuratons, you can use Spring Boot: a Spring ecosytm project hat
ap lies the convention-overc nfiguraton principle providng you default configuratonsforthecapbiltesyourap neds.
Sprni g Boot also helps you more asily configure your depndencis through
thedpendencystareiofs.Adepndencystareigoupofdepndencieswithcomparblevsionsto feryourap aspecifapbilty.
To get he HTTP request and delivr the rsponse, a Jv backend web ap
nedcsorvlta ntainTo(e.g,r msocat): fwwiare th cape btoilyranslate
HTTP request and response to the Jav ap . With servlt containers, you
don’t edtoimplementhcoe mmunicatonothver netwourk sinthg HTTP
e
prot col.
Youcanersilyot uwer bap projSecpast rinBog opt rojewhct, ichautoconfiguresavltcontai erandcomeswiththecapbiltesyounedtowrite
theuscaeofy urwebap .SpringBootals configuresa tofc mpone ts
that intercp and manage HTTP requets. Thes components are part of a
clasdeignwenameSpringMVC.
BecauSseprinBog otauoc nfiguthres Spe rinMVC
g compone ants dthservlet contai er, oy u only ned to write heHTML documentcontain g the dat
theap sendsa reponseandacontrolecasfor minimalHTTPrequestre sp o ns eflo w a ctio n .
You use an otai ns to configure your controle and the controle’s actions.
To mark a clas as a Spring MVC controle, use the
an otai n. To saign a controle action to a specif HTTP request, use the
@RequestMapping an otai n.
@Controller steroype
Implementigwebaps
withSprngBoad
SpringMVC
This chapter covers
Using a template engine to implement dynamic
views
Sending data from client to server through HTTP
requests
Using GET and POST HTTP methods for your HTTP
requests
In chapter 7, we made proges in understanding how to use Spring to write web
ap Wes. d’ve iscuedwea bap co’s mpone ths, de pendenweacies bap neds,
and the Spring MVC architecur.We evnwrote afrsi web ap to provealthes
compone tsworktogeher.
176
Implementing web apps with a dynamic view
nI this chapter, we’l take a step further and implement some capbiltes you’l
find in any modern web ap . We star with implementing pages whose content
changesacordingtohowyourap procesthedatforspecifrquest.Todaywe
raely se staic pages on website. You proba ly think, “Ther has to be a way to
deci whcoat nte oad onthpe bags fodre livnthg HTTP
e responbsetoack
thebrowser.”Therawaysoucandothis!
In section 8.1, we’l implement dynamicvews using template ngines. A template
engineisadepndencythatlowsyouto easilygtnd isplayvribledathecontrole snds. We’l demonstrae how the tmplate ngi e works in an example aftr
reviwingtheSpringMVCflow.
In section 8.2, you’l earn how to send dta from the clint o the srv through
the HTTP request. We’l use tha dat in the controle’s method and creat the
dynamicontentontheviw.
In section 8.3, we discu HTTP methods, and you’l earn tha the rquest path
isn’t enough to identify a client’s request. Together with the rquest path, the clint
useanHTTPmethodrepsntedwithaverb(GET,POST,PUT,DELETE,PATCH,
etc.), which exprs the client’s intention. In our example, we’l implement an
HTMLformthsoat meoncae utosendvaluthes backendhtoasproLaces. inter,
chapters 12 and 13, you’l earn to persit uch dat in a datbse, and your ap s wil
getclosrandcol esrt whatproduction-drea y elivrabo kslie.
8.1
Implementing web apps with a dynamic view
Sup ose y u impelment he cart page of an onli e shop. Thispage shouldn’t display
thsaemde faot ervy nalsoIte. doesnv’et showthsame ine formationevtiryme
fothsrame uThesr. pshiage owpthsrecily odpua rticsuhla sedr edto
thIncaryfo.igue81, ndanexmdpoaynlef amviewc presntedwithMae nni weg bfucasirte’ nctionObality. hserv owrequtoeshsame pe maag nig.com/
cart eiv difernt dat in response. The information displayed is difernt, evn if
thepagisthesame.Thepaghasdynamicontent!
177
178
CHAPTER 8
Implementing web apps with Spring Boot and Spring MVC
The same web page
manning.com/cart
displays different data.
This is a dynamic view.
After adding one book to the cart, I
can see the product has been added
and the price is calculated for that
product only.
On the same page, when I added one more book,
both products are now displayed. Moreover, the
prices are recalculated and specific discounts
are applied. The server sends different details
in the HTTP response even if the request path
is the same.
Figure 8.1 A dynamic view present ed wit h the Manning shopping cart funct ionality. Even if t he request ed
page is the same, t he cont ent of t he page is different . The backend sent different dat a in t he response before
and after adding one more product to t he cart .
Inthseictonwe, implemenweat bap withda ynamviecwMo. satp tos dnay edto
display dynamic dat to the user. Now, for a user’ request exprsd through an
HTTP request nt by the browser, the web ap recivs ome dat, proces it, na d
then sends back an HTTP response that the browser neds to display (figure 8.2)
Implementing web apps with a dynamic view
179
The web client makes requests
to the web server to get or
process specific data.
The web client (browser) directly
interacts with the user.
Sometimes the backend needs
to store a part of the data.
The user
HTTP REQUEST: Give me the product
list page content I need to display.
HTTP RESPONSE: Here is what you
need to display to the user.
The web client uses the data
it gets from the server to
display something.
The web server gets the client requests
and processes the data it receives. In
the end, the server responds to the
client’s request. The data the backend
sends back to the client might be
different for each request.
Figure 8.2 A client sends data t hrough the HTTP request . The backend processes t his dat a and builds a
response t o send back t o t he client . Depending on how t he backend processed t he data, different requests
may result in other dat a displayed to t he user.
We’l reviwtheSpring MVC flow and then workon an example to demonstraehow
theviwcangetdynamicvaluesfromthecontrole.
Inthexampwele implementdha endochf apth7e,r browsecor’ ntenwat s
the same for evy HTTP request for ur page. Remember the Spring MVC flow (figure8.3):
1
2
3
4
5
TheclintsendsanHTTPrequestohewebserv.
The dispatcher servlt use the handler map ing to find out what controle
actiontocal.
Thedispatchersvltcahecontrole’saci n.
After excuting the action asocited with the HTTP request, the controle
retuns the view name the dispatcher servlt neds to render into the HTTP
re sp o ns e.
Thersponseintbackotheclint.
Number 4 is wher we ned to make a change. We want the controle not onyl to
retunthviewnambuesotmehowalsoendtohviaewTh. viewwiinl corporate
180
CHAPTER 8
Implementing web apps with Spring Boot and Spring MVC
Tomcat
Spring app
Handler mapping
Dispatcher servlet
Controller
The controller returns
the view name that the
dispatcher servlet needs
to find and render into
the HTTP response.
Product list
View resolver
In the case of the cart of an online shop,
the controller has to send the product
list to be displayed with other details
like the calculated prices.
In addition to returning the view name,
we want to send data from controller
to the view, which will be displayed by
the view. This way, the same view might
display different data for each request.
Figure 8.3 The Spring MVC flow. To define a dynamic view, t he cont roller needs to send dat a to t he view. The
data the controller sends can be different for each request . For example, in an online shop’s cart funct ionalit y,
the cont roller init ially sends a list of one product to t he view. Aft er t he user adds more products, the list t he
controller sends contains all t he product s in the cart. The same view shows different informat ion for t hese request s.
thisdatodefinetheHTTPresponse.Thisway,ifthesrvndsalitof neproduct, and the page display the list, he page wil display one product. If he controle
sendtws oproducftos hr seamveiwn, owthde isplayed awit bl de ifrnbt ecaus
thepagwilshowtwoproducts(hbe haviory uobservdinfgure8.1)
Lemet showyouhowtosend froat mthcoe ntrole hviewinpa ronject ow.
Youcanfindthisexampleintheproject“sq-h8-ex1.”Thisexma pleismpletoa w
you to focus on the syntax. But you can use this ap roach to send any dat from the
controle theviw.
Leasut’ mfoe nr owwewantosendna mnae dpnri wit thpsa eciof l Irn. a
real-world scenario, you’d maybe ned to print he name of the user omewher on
the page. How you do that? How do you get dat that could be difernt from one
requestoanotherandprintonthepag?
WeSpcrea’lt inBog opt roje(“sqct -h8eanx1”) da dtema pelant gi toe he
depndencies inthpe om.xmWefile. utem’la s penlat gine amedThymThelaf. e
templatengineisadepndencythalowsutoeasilynd atfromthecontrole
to the viw and display this dat in a specif way. I chose Thymelaf becaus it’ les
complexthanothers,andIfinditeasrounderstandandlearn.Asyou’lobservin
ouexamr pthle, mpulates dwithThymsimarelf pHTML
le Thfilest.ac ne xt
codesnip etshowsthedpendencyounedtoad tohepom.xmlfie:
Implementing web apps with a dynamic view
181
<dependency>
The dependency starter
<groupId>org.springframework.boot</groupId>
that needs to be added
<artifactId>spring-boot-starter-thymeleaf</artifactId>
to use Thymeleaf as a
</dependency>
template engine
<dependency>
Though you’re building a web
<groupId>org.springframework.boot</groupId>
app, you still need to add the
<artifactId>spring-boot-starter-web</artifactId>
dependency starter for web apps.
</dependency>
Inlistyo8.1,ugfindthe fintonothfcenotrWe.le an otheamethodtmap
the action ot a specif rquste phat using
rte 7. We now also defin a parmert o the method. This parmert of type
store the dat we want he controel to send to the wvi . In this
ad the valuse we want o nse d to the viw and identify ache of them with a unique
namToo(alsrefd.ky)t adna ewvaluthe acoentrosenl dtohs view,
we cal the
methodistheky; scondparmisthre valuyoe usendtoheviw.
@RequestMapping , as you arlend in chpa Model
Model inast ce, we
addAttribute() method. The first parmter of the
Listing 8.1
addAttribute()
The cont roller class defines t he page act ion
The @Controller stereotype annotation marks
this class as Spring MVCcontroller and adds a
bean of this type to the Spring context.
@Controller
public class MainController {
We assign the controller’s action
to an HTTP request path.
The action method defines a parameter
of type Model that stores the data the
controller sends to the view.
@RequestMapping("/home")
public String home(Model page) {
page.addAttribute("username", "Katy");
We add the data we want the
page.addAttribute("color", "red");
controller to send to the view.
return "home.html";
}
The controller’s action returns the view
to be rendered into the HTTP response.
}
Studensot metimmeskae whthy ange rothif dey airctl dto
the browser’ ad res bar “locahost:80” without a path like “/home.” It’s
corethatneroap ear.Ths eroiasdefuplt ageyousediplayedby
a Spring Boot ap when you get an HTTP 40 (Not Found) response taus.
Whenyoucadl iret“oy calhost:80y” ureftohpe tah“/Be.” cauysoe u
di n’t asign any controle action to this path, it’s normal to get an HTTP
40. If you wish to se something els instead, asign a controle action to
thispathasweluins gthe
NOTE
Todefintheviw,younedtoad anew“home.html”fietoy urSpingBootproject’s “rources/tmplates” folder. Be atentive o the smal difernce: in chapter 7,
we ad ed the HTML file n the “rsources/taic” folder becaus we creatd a stic
view. Now that we’re using a template ngi e to creat dynamic vew, you ned to
ad theHTMLfiletohe“rsources/tmplates”foderinstead.
@RequestMapping an otai n.
182
CHAPTER 8
Implementing web apps with Spring Boot and Spring MVC
Listing 8.2 shows the content of the “home.html” fie I ad ed to the project. The
imfrst portanht intog nointce hfilce’os nte his e
<html>twhag adIer edthe
xmlns:th="http://www.thymeleaf.org" .Thisdefinitonisequivalentoan
atribute
import in Jav. It alows us further to use the prefix “th” to ref to specif atures
provide byThymelafintheviw.
A lite bit further in the viw, you find two places wher I used this “th” prefix to
toref hcoe ntrodle’s toa hviewWi. th e
${attribute_key}synotax, uref
to any of the atributes you send from the controle using the
Model instance. For
${username} to get the value of the “username” atribute na d
example, I used the
${color} togehevaluofthe“col r”atibute.
Listing 8.2
The home.ht ml file represent ing t he dynamic view of t he app
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Home Page</title>
</head>
<body>
<h1>Welcome
<span th:style="'color:' + ${color}"
th:text="${username}"></span>!</h1>
</body>
Defines the Thymeleaf
“ th” prefix
Uses the “ th” prefix to use the
values sent by the controller
</html>
Totesifvryhni gworks,taheap licatona dacesthewebpageinabrowser.
Yourpagewilo klietheoneinfigure8.4
The displayed name
took the value sent by
the controller. The style is
in red, which is the value
sent by the controller.
Now, whatevr your controle sends, the view use.
8.1.1
Getting data on the HTTP request
In this section, we discu how the client sends dat to the serv through HTTP
requInest. ap wes, often edthogiv clenthaboesnilty dinformationtohe
Thseprv. ogtdcaens i thdenispolayednthviwruaseindcto,
8.1 Here are some examples of use case wher the client has to send dat to the serv:
Figure 8.4 The result .
Running t he app and
accessing t he page in a
browser, you observe t he
view t hat uses the values
t he controller sent.
Implementing web apps with a dynamic view
You implement he orde functionality of an online shop. The clint neds to
send to the srv the products hat he user ordes. Further, the srv takes
careoftheorde.
You implement a web forum wher you alow user to ad and edit new pots.
The client sends the post details to the serv, which store or changes the
detailsnadtbase.
You implement he login functionality of an ap . Users write heir cdentials,
which ned to be validte . The clint sends the crdentials o the srv, and
thesrvalidteshescrdntials.
Youimplementhecontacpageofawebap .Thepage display form wher
theusercanwriteamesageubjectna dbody.Thesdetailsnedtobesntin
an email to a specif ad res. The clint sends thes values to the srv, and
the srve takes care of procesing them and sending an email to the desir
e m a il d re s .
Inmosentoca,dhst roughtHTTP
e requyoest nhof le winwag ys:
AnHTTPrequstpametrpresnt asimple way to send vaul es from cliento
serv in a key-valu(s) pair format. To send HTTP request parmetrs, you
ap endthemtohURIe reinqauest xpry esionTh. alsocedr qyu
parmYoueshtr. ouldthapsei roachnseforlydsmina g qual ndoftiay.
An HTTP requst headr is milar to the rquest parmetrs in tha the rquest
headrs are sent through the HTTP headr. The big difernce is that they
don’tap eianr theURIb, utyoutcsilan otsendlargequantiesofdatusing
HTTPheadrs.
Asevnariblpth dstha rought requpest ahiItself.mfoasther
requestparmetrap roach:you seapthvaribletosndasmalquantiyof
dat.Butweshouldusepathvaribleswhenthevaluyousendismandatory.
The HTTP requst bdoy is mainly used to send a lrge quantiy of dat (formattedas tring,butsometimesvnbinarydatsuchas file).We’ldiscuthis
ap roachinchapter10,wheryou’learntoimplementRESTendpoints.
8.1.2
Using request parameters to send data from client to server
In this ection, we implement an example to demonstrae the use of HTTP request
parmetrs—simple ways to send dat from the client to the backend. You often
encounter his ap roach ni production ap s. You use rquest parmetrs in the followingscenarios:
The quantiy of dat you send is not large. You set the request parmetrs using
query vaibles (a shown in this ecton’s exampel). This ap roach limits you
toabout2,0charctes.
You ned to send optial d. A request parmetr is a clen way to deal with a
valuthe clinmit ghnt osent dTh. casnerv xptoecnovaluget f spr ecifrequestparmetrs.
183
184
CHAPTER 8
Implementing web apps with Spring Boot and Spring MVC
An often-encounterd use ca for equest parmetrs used is defini g some sarch
andfiltern(cfigua yoS8.5)reuapr display rodudct ineals tbEale. ch
product is dentifed by a name, a price, and a brand. You want o alow the user to
search for products by any of thes. The user might deci to search by price or by
name na d brand. Any combination is posible. For such a scenario, request parmeters are the right choice for implementaion. The ap sends each of thes values
(name, price, and brand) in optional requets parmetrs. The client only neds to
sendthevalusbywhichtheusrdeci stoearch.
Let’suearquestparmetrbychanginthexamplewediscuedinsection8.1
to get he col r in which the username is displayed from the clint. Listing 8.3 shows
you how to change the controle clas to get the client’s col r value in a request
parmsepItr. adthexamis pinle topa r nject amed“sq-chso8ex2”y ucan alyzethechangesmore asily. To get hevaluefrom a request parmetr,you ned to
ad onmoe pre amtoerhcoe ntroacile’s nmethodandan othae parmeterwith e
@RequestParam an otai n.The
@RequestParam an otai ntelSspringit
This is a query parameter expression. You use it
to define request parameters in the path. We
discuss the syntax later in this section.
Here, the client sends a parameter identified with
a key “ brand” having the value “ honda.”
http://example.com/products?brand=honda
REQUEST: Show me all the motorbikes
produced by Honda.
RESPONSE: Here are the products
produced by Honda.
The server returns all the products
produced by the brand the user requested.
The client can also send the price request
parameter. This parameter is optional.
The server searches by its value only
if the client sends it.
http://example.com/products?brand=honda&price=7000
REQUEST: Show me all the motorbikes
produced by Honda that cost $7,000.
RESPONSE: Here are the products
produced by Honda that cost $7,000.
Figure 8.5 A request paramet er can be opt ional. A common scenario for using request parameters is
implement ing a search funct ionalit y where the search crit eria are optional. The client sends only some of the
request parameters, and t he server knows t o use only t he values it receives. You implement the server t o
consider it might not get values for some of t he paramet ers.
Implementing web apps with a dynamic view
185
neds to get he value from the HTTP request parmetr with the same name as the
method’sparmetrname.
Listing 8.3
Get t ing a value t hrough a request paramet er
We define a new parameter for
the controller’s action method and
annotate it with @RequestParam.
@Controller
public class MainController {
@RequestMapping("/home")
public String home(
We also add the Model parameter that we use
@RequestParam String color,
to send data from the controller to the view.
Model page) {
page.addAttribute("username", "Katy");
page.addAttribute("color", color);
The controller passes the color
return "home.html";
sent by the client to the view.
}
}
Figure8.6hs owshowthecol rpametrvaluetravlsfomtheclintohecontroller’sactiononthebackndtobeusdbytheviw.
The client sends the color through
an HTTP request parameter.
Tomcat
Spring app
Handler mapping
The controller action
gets the value of the
HTTP request parameter.
color = blue
color = blue
Dispatcher servlet
Controller
color = blue
View resolver
The controller sets the
value as a Model attribute
to send it to the view.
Figure 8.6 The value sent by the client from the Spring MVC perspective. The controller act ion gets t he
request parameters t he client sends and can use t hem. In our example, the value is set on t he Model and
delivered t o the view.
Runthape licatona dactesh/e hompe athTo. sethrequpest armetvar’slu,
younedtousethenxtsnpi et’sny tax:
http://localhost:8080/home?color=blue
186
CHAPTER 8
Whensti HTTP
g requpest armyoetrs, uextndthpe athwitha
bypairsof
alsoendthenameasrquestparmetr,Iwrite:
Implementing web apps with Spring Boot and Spring MVC
?symbofl wed
key=value parmetrspatedbythe
& symbol.Forexample,ifIwanto
http://localhost:8080/home?color=blue&name=Jane
You can ad a new parmetr o the controle’s action to get his parmetr as wel.
The next code snip et shows this change. You can also find this example in the project“sq-h8-ex3”:
@Controller
public class MainController {
@RequestMapping("/home")
Gets the new request
public String home(
parameter
“ name”
@RequestParam(required = false) String name,
@RequestParam(required = false) String color,
Model page) {
page.addAttribute("username", name);
Sends the “ name” parameter’s
page.addAttribute("color", color);
value to the view
return "home.html";
}
}
In the group
parmetr,anditsvaluewritenrightaferhe
Figure8.7visualy mmarizestheyns taxforequestparmetrs.
key=value (for example,
color=blue ), “key” is the name of the rquest
= symbol.
Each parameter is given
as a key-value pair.
The request parameter
query starts here.
http://localhost:8080/home?color=blue&name=Jane
This is the key (or name)
of the request parameters.
The key-value pairs are
separated by an “ &” symbol.
This is the request parameters’s value.
Figure 8.7 Sending data t hrough request paramet ers. Each request parameter is a key-value pair. You provide
t he request paramet ers wit h t he path in a query st art ing wit h the quest ion mark symbol. If you set more t han
one request parameter, you separat e each key-value pair wit h the “ and” (&) symbol.
NOTE
a ulv e of r ,ti hervsnds bkca pesr ones wiht ht e utas HTTP 04“ Bad
Reoy wiubfhtIpqoneluaisv”y.cpxelt,ioad
ht nae oitanunis htg oepitnbrual:et
Aqerupmtsa masi ret ndhtnboeialcfuyIr . onsept’ordiv e
@RequestParam(optional=true).
Implementing web apps with a dynamic view
8.1.3
187
Using path variables to send data from client to server
Let’s discu the use of path varibles and compare it o the ap roach you learned in
section 8.21 for sending dat from client o serv. Using path varibles i alo a way
of sendingdat fromclient o serv.Butinsteadofusingthe HTTPrequestparmeters,youdirectlysvabuesinthepath,asprentedinthenextsnip ets.
Usingrequestparmetrs:
http://localhost:8080/home?color=blue
Usingpathvaribles:
http://localhost:8080/home/blue
Youdonid’t enthify value withankey moYre. uj thakes vlut froe mpa recis
posit ni thepath.Onthesrvide,youextrachatvluefromthepathfromthe
specifost nYo.umahmoy ave thre ano valupe ropvidathersblu,it’
avogentubidrsanlymog thcoureanYopule.thbp’ srvathebcomes
more chalenging to read if you go with more than two path varibles. I pref using
requestparmetrsfomorethantwovaluesinsteadofpathvaribles,ayoulearned
insectoAln8.21 yos uh, ouldnup’tseahofvribpls tiorecnvalumI es. mend
you use path varibles only for mandatory parmetrs. If you have optional vues to
senithdHTTP
e reqyuoshet, oureqldpus aremt wedas icuetr, nsdio
8.21Table8.1comparesthrequestparmetrs,andpathvaribelsp roaches.
Table 8.1
A quick comparison of t he request parameters and pat h variables approaches
Request paramet ers
Pat h variables
1 Can be used with optional values.
1 Should not be used with optional values.
2 It is recommended that you avoid a large number
2 Always avoid sending more than three path
of parameters. If you need to use more than three,
I recommend you use the request body, as you’ll
learn in chapter 10. Avoid sending more than three
query parameters for readability.
variables. It’s even better if you keep a maximum of two.
3 Some developers consider the query expression
3 Easier to read than a query expression. For a
more difficult to read than the path expression.
publicly exposed website, it’s also easier for
search engines (e.g., Google) to index the
pages. This advantage might make the website easier to find through a search engine.
When the page you write depnds on only one or two values that re the core of the
end result, i’s betr o write hem directly n the path to make the rquest air to
read.TheURLisaloert findwhenyoubo kmarkitnyourbowserandeasir
toindexwithaserchengi e(iftmatersfoy urap ).
Lewrt’s anite xmptoledmonthsrae ynotax unedtowrinte youcorntroller for geting values as path vraibles. I changed the examples we implemented in
188
CHAPTER 8
section8.2b1 ustepardthcoe deintoanotherpoje“sctq, -h8-ex4,”tomakietasierfoy utoesi.
To refnce a path varibel in the conrtole’s action, you simply give t a name
andad itothepathbetwencurlybaces, presntedinthefol winglistng.You
then use the
get the path varible’s value. Listing 8.4 shows you how to change the controle
action to ge the col r vaue with a path varible (the rst of the xample is the same
as“q-ch8-ex2,”whichwedscui edinsection8.1)
Listing 8.4
Implementing web apps with Spring Boot and Spring MVC
@PathVariable an otai n to mark the controle’s action parmetr o
Using pat h variables t o get values from t he client
@Controller
public class MainController {
To define a path variable, you assign it
a name and put it in the path between
curly braces.
@RequestMapping("/home/{color}")
public String home(
@PathVariable String color,
Model page) {
page.addAttribute("username", "Katy");
page.addAttribute("color", color);
return "home.html";
}
}
You mark the parameter where you
want to get the path variable value
with the @PathVariable annotation.
The name of the parameter must be
the same as the name of the variable
in the path.
Runtheap andacesthepaginyourbowserwithdiferntvaluesforthecol r.
http://localhost:8080/home/blue
http://localhost:8080/home/red
http://localhost:8080/home/green
Eachrequecost l thrs ne amde isplayedbthy pe aignthgivencol Fr.iguv8sre alyrepsntshelinkbetwenthecodeandtherquestpah.
http://localhost:8080/home/blue
The { color} path variable
represents the value provided
in the path.
@RequestMapping("/home/{color}")
public String home(
@PathVariable String color,
Model page) {
page.addAttribute("username", "Katy");
page.addAttribute("color", color);
return "home.html";
}
The action method’s parameter
with the name of the path variable,
annotated with @PathVariable,
gets the value from the path.
Figure 8.8 Using pat h variables. To get a value from a path variable, you give the variable a
name between curly braces when defining the pat h on t he controller act ion. You use a paramet er
annotat ed wit h @PathVariable to get the value of t he pat h variable.
Using the GET and POST HTTP methods
8.2
Using the GET and POST HTTP methods
In this section, we discu HTTP methods and how the client use them to exprs
whatcion(creath, anregtiv,dle)itwilap toly herquestdrourceA.
pathndvaerbidentiafynHTTPrequesThut. fsarwehaeov nlyrefdtohepath,
and, without noticng, we used the HTTP GET method. Its purpose i to define what
action the client request. For example, by using GET, we repsnt an action tha
onretdilyvswaaI’. foythr clientowaisay ntos btainsomethinfrog mthe
serv, but the cal won’t change dat. But you’l ned more than this. An ap also
nedstochange,ad ,ordelt a.
Be careful! You can use an HTTP method aginst its designed purpose,buthisncoret.Forexampel,youcoulduseHTTPGETandmi plement a functionality that changes dat. Techncialy, this posibel, but ’si a
bad,badchoice.NeverusanHTTPmethodaginstdeignedpurpoes.
NOTE
We’ve rlid on the rquest path to reach a specif aton of the controle, but in a
more complex scnario you can asign the same path to multipe actions of the controlase nyoasg u dse ifrnHTTP
t methodWes. wo’l ork na exmptole ap ly
suchacse.
ThHTTP
e methodis efnedbevray ndrepsnthclient’s entionthIf. e
clienrqt’s uoetsndrievslyweat, implementhendpoinwit thHTTPGET.Buif t
the clint’s request omehow changes dat on the srv side, we use other vbs to
repsntheclint’sintentioncleary.
Table 8.2 presnts he sntial HTTP methods you’l use in ap s and which you
shouldearn.
Table 8.2
Basic HTTP met hods you’ll often encount er in web apps
HTTP met hod
Descript ion
GET
The client’s request only retrieves data.
POST
The client’s request sends new data to be added by the server.
PUT
The client’s request changes a data record on the server side.
PATCH
The client’s request partially changes a data record on the server side.
DELETE
The client’s request deletes data on the server side.
Figure8.9visualypresntshesntialHTTPmethodstohelpyourememberthem.
NOTE
Even if it’s a go d practie to make a distnction betwen entirely
replacingarecod(PUT)andchanginonlyaprtofi(PATCH)inproductionap ,ths isdnt ctionsi otalwyasmade.
Nowleimt’s plemenat exmpthle ua smoe rtehanjuHTTP
st GET.Thscenarios
thfoe l winWeg: htoavencr ap thsoalitrepf oduEacts. chproduhct as
189
190
Implementing web apps with Spring Boot and Spring MVC
CHAPTER 8
Give me this book!
HTTP
GET
Add this book to the stock!
/book?title=Spring Start Here
HTTP
POST
Here they are!
Done!
Change only the stock for this book!
Change the details of this book!
HTTP
PUT
/book?title=Spring Start Here
/book?title=Spring Start Here
HTTP
PATCH
/book?title=Spring Start Here
Done!
Done!
Remove the book from the stock!
HTTP
DELETE
/book?title=Spring Start Here
Done!
Figure 8.9 The basic HTTP met hods. You use GET for ret rieving dat a, POST for adding data, PUT for changing
a record, PATCH for changing a part of the record, and DELETE to remove data. The client must use t he
appropriate HTTP met hod to express the act ion execut ed by a specific request .
a name and a price. The web ap display list of al products and alows the user to
ad onemorepoducthroughanHTMLform.
Observ the two use case describd by the scenario. The user neds to do the
fol wing:
Viewalproductsinthelist;her,we’lcontinue singHTTPGET.
Addproductsohelist;her,we’luseHTTPPOST.
We creat a new project, “sq-ch8ex5,” with the depndencies (in the pom.xml file)
forwebandThymelaf,sdcribedbythenextcodesnip et:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Intheproject,wecreat
atribuThtes. e
ateinapckgenamed“model.”Thefol winglstingpresntshe
Product clastodescribaproduwict thisnameandprice
Productmoaiscl dweascle, discuedinchapso5,terwecre-’l
Product clas.
Using the GET and POST HTTP methods
Listing 8.5
The Product class describes a product with name and price as at t ribut es
public class Product {
private String name;
private double price;
// Omitted getters and setters
}
Nowthweat hwaa ve torpy esnpatroduthcreals’wh,i ther ap store
thpe roduThcts. wee bapwidlispthlay e roduinctholisnwea bpange, dinthis
listheusrcanad morepoducts.Wewilimplementhetwouseca(gtingthe
oplistf r dutodcs ipanly da dina gewprodmeuas ct) thoLedclas.inerv t’
creatnewserviclanamed
The next lisngpresnts he srvic la,which instantiaes l and efines two
methodsforad inganewproductna dgetingt.
Listing 8.6
ProductService inapckgenamed“srvice.”
The ProductService class implement s the app’s use cases
@Service
public class ProductService {
private List<Product> products = new ArrayList<>();
public void addProduct(Product p) {
products.add(p);
}
public List<Product> findAll() {
return products;
}
}
NOTE This design is a simplifcaton to alow you to focus on the discuon
othf HTTP
e methodRes. membther Spa rinbg eansc’opbe dy efauisnlt gleton, as we discued in chapter 5, and a web ap licaton mi plies multipe
threads(one for eachrequest).Changin alistdefinedas n atribute ofthe
bean would cause race conditon situaons in a real-world ap wher more
clients ad products msi ultaneously. For now, we’l kep our simplifcaton,
becaus in the next chapters we’l replac the list with a datbse, so this
problem wil no longer ocur. But kep in mind this is a vicous ap roach,
and, as we discued in chapter 5, you shouldn’t use something similar in a
production-readyp .Singletonbeansaren’thread-fs!
Chapter12discuedatsources;we’luseadtabse ost rehedatclosert how
aproductionap lo ks.Butforhemoment,i’sbertof cusonthediscuedsubject,HTTPmethods,andbuildourexamples rogesivly.
191
192
CHAPTER 8
Implementing web apps with Spring Boot and Spring MVC
A controle wil cal the use case implementd by the servic. The controle gets
dat bout a new product from theclint and ad s it o theislt by caling thesrvic,
andthcoe ntrohgesl itpf roduancts dsendtoishviewYo. ulearnedhowto
implement thes capbiltes earli in this chapter. First, let’s creat a
Controller clas in a packge named “controles” and alow this controle to inject
thesrvicban.Thefol winglistngshowsyouthedfintonofthecontrole.
Listing 8.7
Product-
The ProductController class uses t he service t o call t he use cases
@Controller
public class ProductsController {
private final ProductService productService;
public ProductsController(
ProductService productService) {
this.productService = productService;
}
We use DI through the
controller’s constructor
parameters to get the service
bean from the Spring context.
}
Nowweexposethefirstuecas:displayngtheproductlisonapage.Thisfunctionality should be straightforward. We use a
controle theviw,asyoulearnedincsteion8.1Thefol winglistngpresntshe
implementaionforthecontroleaci n.
Listing 8.8
Model parmetr o send the dat from the
Sending t he list of product s t o t he view
We map the controller action to the /products path. The
@RequestMapping annotation, by default, uses the HTTP GET method.
@Controller
public class ProductsController {
private final ProductService productService;
public ProductsController(ProductService productService) {
this.productService = productService;
We define a Model parameter that we
}
use to send the data to the view.
@RequestMapping("/products")
public String viewProducts(Model model) {
var products = productService.findAll();
model.addAttribute("products", products);
return "products.html";
}
}
We get the product list
from the service.
We send the product list to the view.
We return the view name, which will be taken
and rendered by the dispatcher servlet.
Using the GET and POST HTTP methods
193
To display the products in the view, we define the products.html page in the
“resources/tmplates”foderof theproject,asyoulearnedinsection8.1Thefol wing listng shows you the content of the “products.html” file, which takes the list of
productshecontrolesndsand isplaytinanHTMLtable.
Listing 8.9
Displaying t he product s on t he page
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Home Page</title>
</head>
<body>
<h1>Products</h1>
We define the
“ th” prefix to use the
Thymeleaf capabilities.
<h2>View products</h2>
<table>
<tr>
<th>PRODUCT NAME</th>
We define a static
<th>PRODUCT PRICE</th>
header for our table.
</tr>
We display the name
<tr th:each="p: ${products}" >
and the price of each
We use the th:each feature
<td th:text="${p.name}"></td>
product on one row.
from Thymeleaf to iterate on
<td th:text="${p.price}"></td>
the collection and display a table
</tr>
row for each product in the list.
</table>
</body>
</html>
Figure 8.10 presnts he flow for caling the /products path with HTTP GET on the
Sprni gMVCdagirm:
1
2
3
4
5
6
TheclintsendsanHTTPrequestforhe/productspah.
Thedispatchersvltusethehandlermap ingtofindthecontrole’saci n
tocalf rthe/productspah.
Thedispatchersvltcahecontrole’saci n.
Thecontrolequestheproductlisfromthesrvicandsendsitobernder withheviw.
Theviwisrender intoanHTTPresponse.
TheHTTPresponseintbackotheclint.
Buwet nstil edtoimplementhsecondubcase fower thes ap fu’s nctionality. We’l se nothing more than an empty able if we don’t have n option to ad a
product o the list. Let’s change the controle and ad an action to alow ad ing a
productoheproductlis.Listing8.10presntshedfintionofthisacton.
194
Implementing web apps with Spring Boot and Spring MVC
CHAPTER 8
Tomcat
Spring app
Handler mapping
GET /products
Dispatcher servlet
ProductService
ProductController
Product list
View resolver
Figure 8.10 When calling / product s wit h HTTP GET, t he cont roller get s t he product list from t he service and
sends it t o the view. The HTTP response cont ains t he HTML t able with t he product s from the list .
Listing 8.10
Implement ing t he act ion met hod for adding a product
@Controller
public class ProductsController {
We map the controller action
to the /products path. We use
the method attribute of the
@RequestMapping annotation to
change the HTTP method to POST.
// Omitted code
@RequestMapping(path = "/products",
method = RequestMethod.POST)
public String addProduct(
@RequestParam String name,
We get the name and the price for the
@RequestParam double price,
product to add using request parameters.
Model model
) {
Product p = new Product();
We build a new Product instance
p.setName(name);
and add it to the list by calling
p.setPrice(price);
the service use case method.
productService.addProduct(p);
var products = productService.findAll();
model.addAttribute("products", products);
return "products.html";
}
}
Weusedtharibeumet thodthf e
method.Ifyoudon’tseamethod,bydefault
becaus both the path and the method are esntial for any HTTP cal, we want to
alwcoays nfirmbothF.othr easoi nd, evlopuers ualy dse icatedn otai nfos r
eachHTTPmethodinsteadof
We get the list of products
and send it to the view.
We return the name of
the view to be rendered.
@RequestMappingan otai ntosphecifHTTP
y
@RequestMapping useHTTPGET.But
@RequestMappingFapo. r yos,u’lfteni devlopers
Using the GET and POST HTTP methods
using
@GetMapping to map a GET request to an action,
using HTTP POST,and so n. We’l aso change our example to use thes de icatd
an otai nHTTP
fors methodThs. fole winlst pg resnthcos ne futrcloas’ e
conte ,includingthechangesonthemap ingan otai nsfortheactions.
Listing 8.11
195
@PostMapping for a request
The ProductController class
@Controller
public class ProductsController {
private final ProductService productService;
public ProductsController(ProductService productService) {
this.productService = productService;
@GetMapping maps the HTTP GET
}
@GetMapping("/products")
public String viewProducts(Model model) {
var products = productService.findAll();
model.addAttribute("products", products);
return "products.html";
}
@PostMapping("/products")
public String addProduct(
@RequestParam String name,
@RequestParam double price,
Model model
) {
Product p = new Product();
p.setName(name);
p.setPrice(price);
productService.addProduct(p);
@PostMapping maps the HTTP
POST request with a specific path
to the controller’s action.
var products = productService.findAll();
model.addAttribute("products", products);
return "products.html";
}
}
Wecanhlso anthviewgalot whcotualne sr tHTTP
oler’s POSTaction
anda pdrodutoWehclis. e uan’lHTML
se formtomathHTTP
ke is requThest. e
fol winlst gpresnthc e anwegesnedtomaokenthperoducts.htmp(olageur
viewtoad) thHTML
e formTh. resuothlfpedag sinedwithlsin8.12og wn
infigure8.1
request with a specific path to the
controller’s action.
196
CHAPTER 8
Listing 8.12
Implementing web apps with Spring Boot and Spring MVC
Adding an HTML form t o t he view for adding a product to t he list
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Home Page</title>
</head>
When submitted, the HTML
<body>
form makes a POST request
<!-- Omitted code -->
for path /products.
An input component allows
<h2>Add a product</h2>
the user to set the name of
<form action="/products" method="post">
the product. The value in the
Name: <input
component is sent as a request
type="text"
parameter with the key “ name.”
The user
name="name"><br />
uses a
Price: <input
An input component allows the user to set the price
submit
type="number"
of the product. The value in the component is sent as
button to
step="any"
a request parameter with the key “ price.”
submit the
name="price"><br />
form.
<button type="submit">Add product</button>
</form>
</body>
</html>
Run and tes he ap . You aces the page in your browser on htp:
product,s and you should be able to ad new products and se those alrdy ad ed.
F igu re 8 .1 sh o w sth e r su lt.
/ locahost:80/
You find all the existing products
displayed here in the HTML table.
You add a new product using
the HTML form here. Fill the
input components and click the
“ Add product” submit button to
make the request for adding a
new product.
Figure 8.11 The final result. A user sees t he product s in the HTML t able on t he
page and can add a new product t hrough t he HTML form.
Summary
Inourexample,Iusedthe
tion 8.21 I used this an otai n her to make it clar how the clint sends the dta.
ButsometimesSpringalowsyouto mitcode.Forexample,youcouldusea
as parmetrofthecontroe’slaci ndirectly,asprentedinlistng8.13Because
the request parmetrs’ names are the same as the
Spring knows to match them and automaticly res the object. For someone who
alredy knows Spring, this exclnt becaus it spare you from writng code lines.
But begin ers might ge confused by al thes details. Sy ou find an example in an
article that ues this syntax. It might be unclear wher the
from. If you’ve just begun learni g Spring and find yourself in such a situaon, my
adtoisvcebawthare Sprinteg dtoshpave lnoty snf toaxeshidmuase chode
pas osibWhle. enyover ufindsyna otx udonuclear’ty nderstandina exmpole r
article,yfndingtheframeworkspecifatondetails.
This mla change is parted in a project named “sq-ch8ex6” if you want o tes
andcompareitwiththeproject“sq-h8-ex5.”
Listing 8.13
197
@RequestParameter an otai n,whichyoulearnedinsecProduct
Product clas atributes’ names,
Product instance comes
Direct ly using t he model as a paramet er of the cont roller’s act ion
@Controller
public class ProductsController {
// Omitted code
@PostMapping("/products")
public String addProduct(
Product p,
Model model
) {
productService.addProduct(p);
You can use the model class as a parameter of the
controller’s action directly. Spring knows to create the
instance based on the request attributes. The model class
needs to have a default constructor to allow Spring to
create the instance before calling the action method.
var products = productService.findAll();
model.addAttribute("products", products);
return "products.html";
}
}
Summary
Today’s web ap s have dynamic pages (also refd to as dynamic views). A
dynamicpagemightdisplaydiferntcontentfordifentrequest.
Toknowwhdtoynaispmly, frodthvaibmewlgs ic cothne trole.
An easy way to implement dynamic pages in Spring ap s is using a template
engi e such as Thymelaf. Alternatives to Thymelaf are Mustache, FreMarke,andJavSerPages(JS ).
Atempelatngindase pendenthcy pat rovideysouarp with caepbiltoy
easilygthedathecontrolesndsand isplaytontheviw.
198
CHAPTER 8
Implementing web apps with Spring Boot and Spring MVC
Theclintcanesnd atohesrvthroughrequestparmetrsopathvariables.Acontrole’saci ngetshedtailsheclintsendsinparmetrsan otaedwith
@RequestParam or
Arequestparmetrcanbeoptional.
Youshouldonlyusepathvariblesformandtaorydatheiclntsends.
A path and an HTTP method identify an HTTP request. The HTTP method is
repsntedbya verb tha identifes he clint’s intention. The sntialHTTP
methods you’l often find in production ap s are GET, POST, PUT, PATCH,
andDELETE.
– GET exprs the clint’s inte tion to retiv dat without changin dat
onthebacknd.
– POSTexprstheclint’sintentiontoad newdatonthesrvid.
– PUTexprsthclientin’s tentiontochandgea rtcodonthbe acknd
e ntir ely.
– PATCHexprs theclint’sinteniontochangeaprtofadtarecodon
thebacknd.
– DELETEexprstheclint’sinteniontoremovedatonthebacknd.
Throughba rowser’ HTMLformprocesdirtyol, ucanuose nHTTP
ly GET
and HTTP POST. To use other HTTP methods uch as DELETE or PUT, you
nedtoimplementhecalusingaclientlanguaes chasJvScript.
@PathVariable .
Usingthe
Springwebscop
This chapter covers
Using the Spring web scopes
Implementing a simple login functionality for a
web app
Redirecting from one page to another in a web app
Inchapter5, we discued Springbeancsopes.Youlearnedthat Springmanages a
bean’s life cy diferntly depnding on how you declar the bean in the Spring
contex.Inthischapter,we’lad some newwaysSpringmanagesthebansinthe
contex. You’l earn Spring has custom ways to manage instances for web ap s by
usingtheHTTPrequestapointofrence.Springsipretyco l,isn’ti?
Ina ySpringap ,youcancho setodeclarbnasoneofthefol wing:
Singleto —The default bean scope in Spring, for which the framework
uniquelyidntifesachinstancewitha nameinthecontex
Protype —ThebanscopeinSpring,forwhichtheframework nlymanages
thype andcrenats winstanoce thf eicvmlarys soe meonrequest
it(dreclyfomthecontexorhroughwiringorautow- irng).
199
200
CHAPTER 9
Using the Spring web scopes
In this chapter, you’l earn tha in web ap s you can use other bean scopes that re
relvantonlytowebap licatons.Wecalthemwebscpo:
Requst scope —Spring creats an instance of the bean clas for evry HTTP
request.TheinstancexistonlyforthatspecifHTTPrequest.
Sesion cp —Spring creats n instance and keps the instance in the srv’
memorfy thefulHTTPseion.Springlinktshine stancie thecontexwith
theclint’seion.
Aplicatonse —Theinstanceisuniqueintheap ’scontex,andit’savlbe
whiletheap isrun ing.
To teach you how thes web osc pes work ni a Spring ap licaton, we’l work on an
example in which we implement a login functionality. Most of the web ap s today
ofertheiruser the posibltyo l g inandaces nacount,so the xampleisao
relvantfromarel-worldpers ctiv.
In section 9.1, we’l use a request-coped bean to take the user’ credntials for
login and make sure the ap use them only for the login request. Then, in section
9we.2, u’l seaion-scopedbane tos halre vndt eweails nedtokepfor
the loged-in user a long as the user remains loged in. In section 9.3, wel’ use the
ap licaton-scoped bean to ad a cpba ilty o count logni s. Figure 9.1 shows you the
stepwetakeoimplementhisap .
STEP 1
STEP 2
Implement the login logic.
Keep the logged in user details.
If the user provides a correct
set of credentials, the app
recognizes the user and confirms
a successful login.
We don't want Spring to keep the
credentials in the app’s memory for
more than it takes the login request to
finish, so we’ll use a request-scoped
bean to implement this functionality.
Once the user correctly authenticates
with their credentials, we want to keep
them logged in for a period of time.
To store the user details and keep the
user logged in for a longer period of time,
we use the HTTP session through a
session-scoped bean.
STEP 3
Count the login requests.
Finally, we want our app to count all the
login requests from all the users. We need
to store the total number of requests
received by the app.
To implement this functionlity, we’ll
need to use an application-scoped bean.
Figure 9.1 We’ll implement t he login funct ionality in t hree steps. For each step we implement, we’ll need
to use a different bean scope. In sect ion 9.1, we’ll use a request -scoped bean t o implement t he login
logic wit hout risking storing t he credent ials for longer t han the login request . We’ll then decide what det ails
we need t o store for the aut henticat ed user in a session-scoped bean. Finally, we’ll implement a feat ure
to count all t he login request s, and we’ll use an application-scoped bean t o keep t he number.
Using the request scope in a Spring web app
9.1
201
Using the request scope in a Spring web app
In this ecton, you’l eran how to use rquest-coped beans in Spring web ap s. As
you leraned in chapters 7 and 8, web ap s are focused on HTTP request and
response.Forthisreaon,and oftenin webap s, certainfunctionaitlesr to
manage if Spring ofers you a way to manage the bean life cy in relationship with
theHTTPrequest.
A request-coped bean is an object managed by Spring, for which the framework
creats newinstanceforveyHTTPrequest.Theap canusetheinstanceonlyfor
the rquest hat cred it. Any new HTTP request (from the same or other clints)
creatsnduseadifrntinstanceofthesameclas(figure9.2)
Richard is the user.
For the first HTTP request,
Spring creates an instance of
the LoginProcessor bean, which
is request-scoped.
Spring manages the type of the
bean and creates a new instance
for each HTTP request. In this
figure, the coffee plant is the bean
type Spring manages, and the coffee
bean is the instance.
Spring context
Richard
HTTP REQUEST 1
For a second HTTP request, Spring creates
another instance of the LoginProcessor
bean. Observe the hash of the instance
is different in the Spring context.
LoginProcessor@56b49ef9
Spring context
Richard
HTTP REQUEST 2
LoginProcessor@4be2b62e
Figure 9.2 For every HTTP request , Spring provides a new inst ance for t he request -scoped bean. When using
a request -scoped bean, you can be sure the dat a you add on the bean is available only on t he HTTP request
that creat ed the bean. Spring manages t he bean t ype (the plant) and uses it t o get inst ances (coffee beans)
for each new request .
Letd’s emonstraeheusofarequest-copedbeani anexampleWe. ’limplemenat
web ap licaton’s login functionality, nd we’l use a request-coped bean to manage
theusr’cedntialsforheloginlogic.
202
CHAPTER 9
Using the Spring web scopes
Key aspect s of request -scoped beans
Before diving into implementing a Spring app that uses request-scoped beans, I’d like
to shortly enumerate here the key aspects of using this bean scope. These aspects
will help you analyze whether a request-scoped bean is the right approach in a realworld scenario. Keep in mind the very relevant aspects of request-scoped beans,
explained in the following table.
Fact
Consequence
To consider
To avoid
Spring creates
a new instance
for every HTTP
request from
any client.
Spring creates a lot
of instances of this
bean in the app’s
memory during its
execution.
The number of instances is
usually not a big problem
because these instances
are short-lived. The app
doesn’t need them for
more than the time the
HTTP request needs to
complete. Once the HTTP
request completes, the
app releases the
instances, and they are
garbage-collected.
However, make sure you
don’t implement a timeconsuming logic Spring
needs to execute to create the instance (like getting data from a database
or implementing a network
call). Avoid writing logic in
the constructor or a @PostConstruct method for
request-scoped beans.
Only one
request can
use an
instance of
a requestscoped bean.
Instances of
request-scoped
beans are not prone
to multithreadrelated issues as
only one thread (the
one of the request)
can access them.
You can use the instance’s
attributes to store data
used by request.
Don’t use synchronization
techniques for the attributes of these beans.
These techniques would be
redundant, and they only
affect the performance of
your app.
A login example, such as this one, is exclnt for di act purpoes.
Howevr, in a production-ready ap , it’s betr to avoid implementi g
authenticaona dauthorizat nmechanismyos uInrself. a-worldSpring
ap , we use Sprni g Security o impelment anything relatd to authentcaion
andauthorizat nUs. inSpg rinSecug (writy hic alsopoarthf Spe rni ecog sytem) simplifes your impelmentaions and ensure you don’t (by mistake)
introduce vulnerabilts when writng the ap licaton-lev security logic. I
recommend you also read Spring uecty in Actnio (Man ing, 20) which is
another bo k I authored and that describ, ni detail, how to use Spring
Securityoprotecy urSpingap .
NOTE
Tomakethingstraihtforward,wewilconsdi erastofcredntiaslhatwebakeinto
our ap licaton. In a real-world ap , the ap store the user in a datbse. It also
encryptshepaswordstoprotechem.Fornow,wefocusonlyonthepurpose fthis
chapter: discung the Spring web bean scopes. Later, in chapters 1 and 12, you’l
learnmoreaboutsoringdatinadtbase.
Using the request scope in a Spring web app
203
LectrSe’spa inBog otprojeactnda dthne de depndencieYos. uwifilnd
thisexampleintheproject“sq-h9-ex1.”Youcand thedpendenciesdrctlywhen
creatinhg pe ro(fjectxamr pule, sintar.gping.io)afterwardinyoupr om.xml.
For this example, we wil use the web depndency and Thymelaf as a templating
engi e(likwedi nchapter8).Thenecoxt desnip etshowsthedpendenciesyou
nedtohaveinyourpom.xmlfie:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
We’lcreat pagethatcontainsaloginformaskingforauser’nameandpasword.
The ap compares the username and the psaword with a set of credntials knows
(in my case, user “natlie” with paws ord “pasword”). If we provide coret credntials (hey match with the crdentials he ap knows), then the page display message “You are now loged in” under the login form. If the crdentials we provide ar
notc re,hentheap displaymesage:“Loginfailed.”
As you learned in chapters 7 and 8, we ned to implement a page (rpesnti g
our view) and a controle cas. The controle snds the mesage it neds to display
toheviwacordingtohelogin’serult(fig re9.3)
The client sends an HTTP request
containing the login credentials.
HTTP Request
POST /?username=natalie&password=password
Tomcat
Spring app
Handler mapping
Dispatcher servlet
The controller finds out
if the credentials are valid
and sends a message to
the view according to the
login’s result.
LoginController
Message
View resolver
The view displays the message
it receives from the controller.
Figure 9.3 We need t o
implement t he cont roller and
the view. In the cont roller, we
implement an action t hat
finds out if t he credentials
sent in t he login request are
valid. The controller sends a
message t o the view, and the
view displays t his message.
204
CHAPTER 9
Using the Spring web scopes
Listing 9.1 shows the HTML login page that defines the view in our ap . As you
learned in chapter 8, you have to s re the page in the rsources/tmplates folder of
your Spring Boot project. Let’s name the page “login.html.” To display the mesage
with the logic’s reult, we ned to senda parmetr fom the controle the viw. I
namedthisparmetr“mesag,” youcanse inthefol wing listng,wherIused
thesyntax
${message} todisplaythisnaprg hundertheloginform.
Listing 9.1
The definit ion of t he login page login.ht ml
We define the “ th” Thymeleaf
<!DOCTYPE html>
prefix to use the templating
<html lang="en" xmlns:th="http://www.thymeleaf.org">
engine’s capabilities.
<head>
<meta charset="UTF-8">
<title>Login</title>
The input fields
We define an HTML form
</head>
are used to write
to
send
the
credentials
<body>
the credentials,
to
the
server.
<form action="/" method="post">
username, and
Username: <input type="text" name="username" /><br />
password.
Password: <input type="password" name="password" /><br />
<button type="submit">Log in</button>
When the user clicks the
</form>
<p th:text="${message}"></p>
</body>
We display a message with the result of
</html>
Submit button, the client
makes an HTTP POST request
with the credentials.
the login request under the HTML form.
Acontroacile n edtoshge HTTPrequ(froest mthde ispatchyoservlt,u
learnedinchapte7nrs d8so), ledt’ finthe controleandthaceionthrecativs
the HTTP request for the page we creatd in listng 9.1 In lsitng 9.2, you find the
defintionothf coe ntroclWease. mapthcoe ntroalce’si ntohwee bap ro’s t
path(
"/" ).Iwilnamethecontrole
Listing 9.2
LoginController .
The cont roller’s act ion mapped t o t he root pat h
@Controller
public class LoginController {
@GetMapping("/")
public String loginGet() {
return "login.html";
}
}
Now tha we have login page, we want o implement he login logic. When a user
cliksonthe Submit buton,wewanthepagetodisplya propermesage underthe
loginformthIf. ue sr bmitedhcoe str df entihals, mee “Yoisage uare
nowlogedin”;otherwise,thedisplayedmesagewilbe“Loginfailed”(gure9.4)
We use the @Controller stereotype annotation
to define the class as a Spring MVCcontroller.
We map the controller’s action to the
root ("/ ") path of the application.
We return the view name we
want to be rendered by the app.
Using the request scope in a Spring web app
205
The app displays a login form
where a user specifies their
credentials to log in.
YES
The login form
Are the credentials valid?
If the credentials the user
specified are valid, the app
tells the user they logged in.
NO
If the credentials the user
specified are wrong, the app
says that the login failed.
Figure 9.4 The funct ionality we implement in this sect ion. The page displays a login form for the user. Then
the user provides valid credentials, and the app displays a message that t hey successfully logged in. If t he user
provides incorrect credent ials, t he app t ells t he user that t he login failed.
ToprocestheHTTPPOSTrequesthatheHTMLformcreatswhentheusrclik
ontheSubmitbuton,wenedtoad onemoracetionto ur
actoi n takes the client’s request parmetrs (the username and the pasword) and
senmeda s tohsageviwacordintohgl einrsuLilt. sinh9.3 gowyosuthde finitonofthecontrole’saci n,whichwe’lmaptoheHTTPPOSTloginrequest.
Nothice wea havenim’t plementdhloe ginloIngic. thne listx weg, thake
request and send a mesage in response acording to a varible repsnti g the
request’ rult. But his varble (in listng 9.3 named
the next lisngs in this ecton, we complet his acton by ad ing a cl to the login
logic. This login logic wil retun the login result based on the crdentials he clint
sentintherqute.s
Listing 9.3
LoginController .This
loggedIn ) is always “fle.” In
The cont roller’s login act ion
@Controller
public class LoginController {
@GetMapping("/")
public String loginGet() {
206
CHAPTER 9
Using the Spring web scopes
return "login.html";
We are mapping the controller’s action to
the HTTP POST request of the login page.
}
@PostMapping("/")
public String loginPost(
@RequestParam String username,
We get the
@RequestParam String password,
credentials
Model model
from the ) {
HTTP request
boolean loggedIn = false;
We declare a Model parameter to
send the message value to the view.
When we later implement the login logic, this
variable will store the login request result.
parameters.
if (loggedIn) {
model.addAttribute("message", "You are now logged in.");
} else {
model.addAttribute("message", "Login failed!");
}
return "login.html";
}
We return the view name,
which is still login.html, so we
remain on the same page.
Depending on
the result of the
login, we send a
specific message
to the view.
}
Figure 9.5 visualy describ the link betwen the controle clas and the view we
implementd.
LoginController class
login.html page
@Controller
public class LoginController {
@GetMapping("/")
public String loginGet() {
return "login.html";
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
The controller’s action is called
when the form is submitted.
@PostMapping("/")
public String loginPost(
@RequestParam String username,
@RequestParam String password,
Model model
){
boolean loggedIn = true;
The controller’s action
gets the credentials from
the request parameters.
if (loggedIn) {
model.addAttribute("message", "You are now logged in.");
} else {
model.addAttribute("message", "Login failed!");
}
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<form action="/" method="post">
Username: <input type="text" name="username" /><br />
Password: <input type="password" name="password" /><br />
<button type="submit">Log in</button>
</form>
<p th:text="${message}"></p>
</body>
</html>
return "login.html";
}
}
The controller’s action sends a message
according to the login request result to
the view. The view displays the message
under the login form.
Figure 9.5 The dispat cher servlet calls t he controller’s action when someone submit s the HTML login form.
The cont roller’s act ion get s t he credentials from t he HTTP request paramet ers. According to t he login result , the
controller sends a message t o the view, and t he view displays this message under the HTML form.
Using the request scope in a Spring web app
Nowwehavecontroleandaview,butwheristherquestcopeinalofthis?The
only clas we wrote is the
default Spring scope. We don’t ned to change the scope for
long as it doesn’t sore any detail n its arbutes. But remember, we ned to implement he login logic. The login logic depnds on the uer’s cdentials, nd we have
toakeintoc nsideratontwothingsabouthescrdntials:
1
2
207
LoginController , and we left it a singleton, which is the
LoginController as
The credntials are sensitve details, and you don’t want to store them in the
ap ’smemoryf longerthantheloginrequest.
Moreuswithdiferntcredntialsmightaemptol ginsimultaneously.
Considerng thes two points, we ned to make sure that if we use a bean for implementing the login logic, eah instance is unique for each HTTP request. We ned to
use a rquest-copedbean.We’l extnd theap as presnted in figure 9.5 We ad a
request-copedbean
validteshem(figure9.6)
LoginProcessor ,whichtakeshecrdentialsontherquestand
The client sends an HTTP request
containing the login credentials.
HTTP Request
POST /?username=natalie&password=password
Tomcat
The controller finds out from the
LoginProcessor if the credentials
are valid and sends a message to
the view according to the login’s result.
Spring app
Handler mapping
Dispatcher servlet
LoginController
LoginProcessor
Message
View resolver
The view displays the message
it receives from the controller.
The LoginProcessor implements
the logic that validates the
credentials. Spring makes sure
to create a new instance for
each HTTP request.
Figure 9.6 The LoginProcessor bean is request -scoped. Spring makes sure to creat e a new inst ance for
each HTTP request . The bean implement s t he login logic. The cont roller calls a method it implement s. The
met hod ret urns true if t he credentials are valid and false otherwise. Based on the value t he LoginProcessor
ret urns, t he LoginController sends t he right message to t he view.
208
CHAPTER 9
Listing 9.4 shows the implementaion of the
scopeoftheban,weusethe
make abenof thiscla type inthe Springcontex byusing the
either a configuraton clas or a steroype an otai n. I chose to an otae he clas
withthe
@Component steroypean otai n.
Listing 9.4
Using the Spring web scopes
LoginProcessor clas. To change the
@RequestScoped an otai n.Ofcourse,wesltinedto
@Bean an otai nin
Request -scoped LoginProcessor bean implement ing t he login logic
We annotate the class with a stereotype
annotation to tell Spring this is a bean.
@Component
@RequestScope
public class LoginProcessor {
private String username;
private String password;
We use the @RequestScope annotation to change the
bean’s scope to request scope. This way, Spring creates
a new instance of the class for every HTTP request.
The bean stores the
credentials as attributes.
public boolean login() {
String username = this.getUsername();
String password = this.getPassword();
The bean defines a method for
implementing the login logic.
if ("natalie".equals(username) && "password".equals(password)) {
return true;
} else {
return false;
}
}
// omitted getters and setters
}
You can run the ap licaton and aces the login page using the locahost:80
ad res in your browser’ ad res bar. Figure 9.7 shows you the ap ’s behavior afte
acesingthepagndforusingvalidndincoretdntials.
The login form
When accessing the web page,
you first see an empty login form.
Using valid credentials
If you use valid credentials, user “ natalie”
with password “ password,” and click the
“ Log in” button, the app displays a
successful login message.
Using incorrect credentials
If you use incorrect credentials, the app
displays the “ Login failed!” message.
Figure 9.7 When accessing t he
page in a browser, t he app shows a
login form. You can use valid
credent ials, and t he app displays a
successful login message. If you
use incorrect credentials, t he app
displays a “ Login failed!” message.
Using the session scope in a Spring web app
9.2
209
Using the session scope in a Spring web app
Inthseictonwe, discueon-scopedbeansWh. enyouenweater bap andloing ,
youexpctothensurf throughthat p ’spages,nd theap stilremembersyou’ve
loged in. A seion-scoped bean is an object managed by Spring, for which Spring
creats n instance and links it o the HTTP seion. Once a lint sends a request o
the srve, the srve resv a place in the memory for this request, for the whole
duration of their seion. Spring creats an instance of a seion-scoped bean when
the HTTP seion is creatd for a specif lnt. That insta ce an be rused for the
samcleinwht hstile ahs HTTP
e seionactiThve. edaytoustoinre thseionscopedbeantribuavilsbte fohar clienrqt’s uthes roughouant HTTPsesion. This ap roach of storing the dat alows you to store information about what
userdowhilethey’rsufingthrought epagsofy urap .
When Richard sends the first request,
he starts a new HTTP session. Spring
creates a new instance of the session-scoped
bean. The app uses this instance throughout
the whole session.
The session-scoped bean is the coffee plant.
Spring keeps track of the object type but creates
and maintains multiple instances of this object.
Spring creates one instance per HTTP session.
Spring context
Richard
HTTP REQUEST 1
LoginUserManagementService@4be2b62e
Next, Richard sends a use request to the session-scoped
bean instance that has already been created.
The app keeps the instance in the memory and reuses
it for all the requests in this HTTP session.
Spring context
Richard
HTTP REQUEST 2
LoginUserManagementService@4be2b62e
When Daniella starts her HTTP session, Spring creates
a bean instance for her as well. Meanwhile, the Spring
context also stores the instances that belong to other
users. Richard’s session bean instance is still here, and
the app still uses it for his requests.
Spring context
Daniella
HTTP REQUEST 1
LoginUserManagementService@a234be1d
LoginUserManagementService@4be2b62e
Figure 9.8 The session-scoped bean is used to keep a bean in t he context throughout the client ’s full
HTTP session. Spring creates an inst ance of a session-scoped bean for each HTTP session a client opens.
The client accesses t he same instance for all the request s sent t hrough t he same HTTP session. Each
user has t heir own session and accesses different instances of the session-scoped bean.
210
CHAPTER 9
Using the Spring web scopes
Take time to c mpare figure 9.8, which presnts he sion-scoped bean, with figure
9.2, which presnt he rquest-coped bean. Figure 9. summarizes the comparison
betwenthetwoap roachesawel.Whileforaequest-copedbeanSpringcreats
Request-scoped beans
Spring context
Richard
HTTP REQUEST 1
LoginProcessor@56b49ef9
For each request, Spring creates
a different bean instance.
Spring context
Richard
HTTP REQUEST 2
LoginProcessor@7aa6eB9
Session-scoped beans
Spring context
Richard
HTTP REQUEST 1
LoginUserManagementService@4be2b62e
Spring context
Richard
During the same HTTP
session, two different
requests of the same
client get the same
bean instance.
HTTP REQUEST 2
LoginUserManagementService@4be2b62e
A different client creates a different
HTTP session, so it gets a different
bean instance.
Spring context
Daniella
HTTP REQUEST 1
LoginUserManagementService@a234be1d
LoginUserManagementService@4be2b62e
Figure 9.9 A comparison bet ween t he request -scoped and session-scoped beans t o help you visualize
the differences between these two web bean scopes. You use request-scoped beans when you want
Spring t o creat e a new inst ance for each request . You use a session-scoped bean when you want to
keep t he bean (t oget her with any det ails it holds) throughout the client ’s HTTP session.
Using the session scope in a Spring web app
211
new instance for evy HTTP request, for a seion-scoped bean, Spring creats only
one instance per HTTP seion. A seion-scoped bean alows us to store dat shared
bymultiperquestofhesameclint.
A couple of featurs you can implement using seion-scoped beans include the
fo l w in g e xa m p le s:
A login —Keeps details of the authenticaed user while they vist difernt parts
ofy urap andsendmultiperquest
An onlie shoping cart —Users vist multipe places in your ap , searching for
products hey ad to the cart. The cart emembers al the products he clint
ad ed.
Key aspect s of session-scoped beans
Like we did for the request-scoped beans, let’s analyze the key characteristics of the
session-scoped beans you need to consider when planning to use them in a production app.
Fact
Consequence
To consider
To avoid
The sessionscoped bean
instances
are kept for
the entire
HTTP
session.
They have a longer
life, and they are
less frequently
garbage-collected
than the requestscoped beans.
The app keeps the data you
store in the session-scoped
beans for a more extended
period.
Avoid keeping too much
data on the session. It can
potentially become a performance problem. Moreover, never store sensitive
details (like passwords,
private keys, or any other
secret detail) in sessionbean attributes.
Multiple
requests can
share the
sessionscoped bean
instance.
If the same client
issues multiple
concurrent
requests that
change the data
on the instance,
you may encounter multithreadingrelated issues like
race conditions.
When you know such a scenario is possible, you might
need to use synchronization
techniques to avoid concurrency. However, I generally recommend you see if this can be
avoided and keep synchronization only as a last resort when
it can’t be avoided.
The sessionscoped
beans are a
way to share
data among
requests by
keeping the
data on the
server side.
The logic you
implement might
imply requests
become dependent one on the
other.
When keeping details stateful in
one app’s memory, you make clients dependent on that specific
app instance. Before deciding to
implement some feature with a
session-scoped bean, consider
alternatives, such as storing the
data you want to share in a database instead of the session.
This way, you can leave the HTTP
requests independent one from
another.
212
CHAPTER 9
Using the Spring web scopes
Weconti utoeusiaoe n-scopedbeantomaoke uapr awthrae ut loser gdin
and recognize them as loged-in user while they acs difernt pages of the ap .
This way, the example teaches you al the relvant details you ned to know when
workingwithproductionap licatons.
Let’s change the ap licaton we implemented in section 9.1 to display page that
only loged-in user can aces. Once a user logs in, the ap redicts them to this
page, which display a welcome mesage contain g the loged-in username and
ofersthusertheoptiontol goutbyclikngalink.
Thesarthestpwenedtoake implementhischange(fiur9.10):
1
2
3
4
Creatsion-scopedbeantokepthelogd-inuser’dtails.
Creathepagusercanonlyacesftrogin.
Mapcanuwiotserhpdui1nacgekot louginfrst. g
Redirectheusrfomlogni tohemainpageftrsucf lauthenticaon.
STEP 1
Create a session-scoped bean
to keep the logged-in user details.
STEP 2
Create a page that the user can access
only after logging in.
resources/templates/main.html
@Service
@SessionScope
public class LoggedUserManagementService {
private String username;
}
STEP 4
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Welcome</title>
</head>
<body>
<h1>Welcome</h1>
</body>
</html>
STEP 3
Redirect the user from login
to the main page after
successful authentication.
Make sure a user cannot access
the page created at step 1
without logging in fi rst.
if (loggedIn) {
return "redirect:/main";
} else {
model.addAttribute("message", "Login failed!");
}
String username =
loggedUserManagementService.getUsername();
if (username == null) {
return "redirect:/";
}
Figure 9.10 We use a session-bean t o implement a sect ion of t he app t hat only a logged-in user can
access. Once the user aut henticates, t he app redirect s them to a page they can only access once
authent icat ed. If the user tries t o access this page before aut hent ication, t he app redirect s t hem t o t he
login form.
Using the session scope in a Spring web app
213
Isepartdhechangesforthisexampleintheproject“sq-he9-x2.”
Fortunately, creating a seion-scoped bean in Spring si as simple as using the
@SessionScope an otai n with the bean clas. Let’s crea new clas,
ManagementService,andmaseitok n-scopedpas, rentedinthfoe l winlstg .
Listing 9.5
LoggedUser-
Defining a session-scoped bean t o keep t he logged user det ails
We add the @Service stereotype annotation to instruct
Spring to manage this class as a bean in its context.
@Service
@SessionScope
public class LoggedUserManagementService {
We use the @SessionScope
annotation to change the
scope of the bean to session.
private String username;
// Omitted getters and setters
}
Every time a user ucesf ly ogs in, we store its name in this bean’s username atribute. We auto-wire the
clas,whichweimplementdinsection9.1toakecroftheauthenticaonlogic,as
showni thefol winglistng.
Listing 9.6
LoggedUserManagementService bean in the
LoginProcessor
Using t he LoggedUserManagementService bean in t he login logic
@Component
@RequestScope
public class LoginProcessor {
private final LoggedUserManagementService loggedUserManagementService;
private String username;
private String password;
We auto-wire the
LoggedUserManagementService bean.
public LoginProcessor(
LoggedUserManagementService loggedUserManagementService) {
this.loggedUserManagementService = loggedUserManagementService;
}
public boolean login() {
String username = this.getUsername();
String password = this.getPassword();
boolean loginResult = false;
if ("natalie".equals(username) && "password".equals(password)) {
loginResult = true;
loggedUserManagementService.setUsername(username);
}
return loginResult;
}
// Omitted getters and setters
}
We store the username on the
LoggedUserManagementService bean.
214
CHAPTER 9
Observ tha the
creathisnstanceforeachlogni request.Weonlynedtheusrnameandpasword
atributes’val duringtherquestoxcuteheauthenticaonlogic.
Becausethe
value wil now be acesibl throughout the entire HTTP seion. You can use this
value to know if someone is loged in, and who. You don’t have to wory about he
caswhe ermultipue sralogedinth; eap licatonframewokr makeus rtolink
eachHTTPrequtoeshcoe srit nF.igure visu9.1 daly escribthloe ginflow.
Using the Spring web scopes
LoginProcessor bean stay request-coped. We stil use Spring to
LoggedUserManagementService beanis eon-scoped,theusername
Login page
Redirects the user
to the login page
and displays a login
failed message
User clicks the login button
and sends its credentials.
No
Are the credentials valid?
Yes
Stores the username
in the session-scoped bean
<<session bean>>
Redirects to the main page
LoggedUserManagementService
Main page
Figure 9.11 The login flow implement ed in t he example. When t he user submits t heir credentials, t he login
process begins. If t he user' s credentials are correct, t he username is st ored in t he session-scoped bean, and
the app redirects t he user t o t he main page. If the credentials are not valid, t he app redirect s t he user back
to t he login page and displays a failed login message.
Nowwecreatnewpagendmakesur auercsnacesitonlyiftheyhavelrdy
loged in. We define a new controle (that we’l cal
page. We’l define an action and map it o the /main path. To make sure a user can
acesthispathonlyiftheylogdin,wechekifthe
beanstoanre uy sernamditIfe. osnwe’t, redthic ue tosrhloe ginpToage. reditahnuorecs thpcoearg,nactironle rtuedonshtri“edgirct:”
fol wedbthy pe tahowhicht aocie nwantosredthic ue Fsr.giuv912e aly
presntshelogicbehindthemainpage.
MainController) for the new
LoggedUserManagementService
Using the session scope in a Spring web app
215
User accesses the main page.
Login page
The app redirects the user
to the login page.
“Is the username already in the
session-scoped bean?” is equivalent
with “Did the user already log in?”
No
Yes
<<session bean>>
LoggedUserManagementService
User remains on the main page.
Main page
Figure 9.12 Someone can access t he main page only after they are aut henticat ed. When t he app
authent icat es t he user, it st ores the username in t he session-scoped bean. This way, t he app knows t he user
had already logged in. When someone accesses the main page, and t he username is not in the session-scoped
bean (t hey did not authent icate), the app redirect s them t o t he login page.
Thefol winglistngshowsthe
MainController clas.
Listing 9.7
The MainController class
@Controller
public class MainController {
We auto-wire the LoggedUserManagementService
bean to find out if the user already logged in.
private final LoggedUserManagementService loggedUserManagementService;
public MainController(
LoggedUserManagementService loggedUserManagementService) {
this.loggedUserManagementService = loggedUserManagementService;
}
@GetMapping("/main")
public String home() {
String username =
We take the username value,
which should be different than
null if someone logged in.
216
CHAPTER 9
Using the Spring web scopes
loggedUserManagementService.getUsername();
if (username == null) {
return "redirect:/";
}
return "main.html";
}
}
If the user is not logged in, we
redirect the user to the login page.
If the user is logged in, we return
the view for the main page.
You ned to ad the main.html that defins the view in the “resources/tmplates”
folder of your Spring Boot project. The fol wing listng shows the content of the
main.htmlpage.
Listing 9.8
The cont ent of t he main.ht ml page
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Welcome</title>
</head>
<body>
<h1>Welcome</h1>
</body>
</html>
To alow the user to log out is also easy. You just ned to set the username in the
LoggedUserManagementService seionbeanasnul.Let’screa log utlinkon the
pange dalsod thloe gd-inusernma ine thwee lcommee Thsage. foe l winlst-g
ingshowsthechangestohemain.htmlpagethadefinesourview.
Listing 9.9
Adding a logout link t o the main.html page
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
We get the username
<meta charset="UTF-8">
from the controller
<title>Login</title>
and display it on the
</head>
page in the welcome
<body>
message.
<h1>Welcome, <span th:text="${username}"></span></h1>
<a href="/main?logout">Log out</a>
</body>
We add a link on the page that sets an HTTP
request parameter named “ logout.” When the
</html>
controller gets this parameter, it will erase the
value of the username from the session.
Thes main.html page changes also asume os me changes in the controle for the
functionality to be complet. The next listng shows how to get the log ut request
Using the session scope in a Spring web app
217
parmetr in the controle’s action and send the username to the view wher it is
displayedonthe page.
Listing 9.10
Logging out t he user based on t he logout request paramet er
We get the logout request parameter if present.
@Controller
public class MainController {
// Omitted code
@GetMapping("/main")
public String home(
@RequestParam(required = false) String logout,
Model model
) {
if (logout != null) {
loggedUserManagementService.setUsername(null);
}
We add a Model
parameter to send the
username to the view.
If the logout parameter is present,
we erase the username from the
LoggedUserManagementService
bean.
String username = loggedUserManagementService.getUsername();
if (username == null) {
return "redirect:/";
}
model.addAttribute("username" , username);
return "main.html";
We send the username
to the view.
}
}
To complet he ap , we’d like to change the
the main page once they authenticae. To achiev this reult, we ned to change the
LoginController ’saction,asprentedinthefol winglistng.
Listing 9.11
LoginController to redict user to
Redirect ing t he user t o t he main page aft er login
@Controller
public class LoginController {
// Omitted code
@PostMapping("/")
public String loginPost(
@RequestParam String username,
@RequestParam String password,
Model model
) {
loginProcessor.setUsername(username);
loginProcessor.setPassword(password);
boolean loggedIn = loginProcessor.login();
218
CHAPTER 9
Using the Spring web scopes
if (loggedIn) {
return "redirect:/main";
}
When the user successfully authenticates,
the app redirects them to the main page.
model.addAttribute("message", "Login failed!");
return "login.html";
}
}
Now you can star the ap licaton and tes the login. When you provide the coret
credntalsi, the ap redicts you to the main page (figure 9.13) Clcik the Logout
link, and the ap redicts you back to the login. If you try o aces the main page
withouta henticang,theap redictsyoutol gin.
Figure 9.13 This flow bet ween t he t wo pages. When t he user logs in, t he app redirect s them to the main page.
The user can click on t he logout link, and t he app redirects t hem back t o the login form.
9.3
Using the application scope in a Spring web app
Inthisecton,wediscuthaep licatonscope.Iwantomentionitsexnce,make
youawareofhowitworks,andemphasizethait’sbernot useitnaproduction
ap .Allcientrequesthraenap cliaton-scopedbean(figure9.14)
Theap licatonscopeisocl t howasingletonworks.Thedifrenceisthatyou
can’t have more instances of the same type in the contex and that we always use the
HTTP request as a refnce point when discung the life cyle of web scopes
(including the ap licaton scope). We face the same concurency problems we discusedinchapter5fohesingleton beansforap licaton-scopedbeans:it’bero
himave mutabrile ufoteshr sine gltonbeanThs. same ade pisvc licabtoen
ap licaton-scoped bean. But if you make the atributes immutable, then you can
directlyusaingletonbeani stead.
Generayl, I recommend devlopers avoid using ap licaton-scoped beans. It’s
betr to directly use a persitnce layer, such as a datbse (which you’l learn in
chapter1).
It’salwabys etosanexmptleounderstandthcase.Lect’hs angethap lication we worked on in this chapter and ad a fetur that counts he login atempts.
Youwilfindthisexampleintheproject“sq-h9ex3.”
Using the application scope in a Spring web app
219
The LoginCountService bean is an application-scoped bean.
There’s only one instance of this type in the Spring context.
Any request from any client uses the same instance.
Richard
HTTP Request
Spring context
Richard
HTTP Request
LoginCountService@4be2b62e
HTTP Request
Daniella
Figure 9.14 Underst anding t he application scope in a
Spring web app. The instance of an applicat ion-scoped
bean is shared by all t he HTTP request s from all clients.
The Spring cont ext provides only one inst ance of t he
bean’s t ype, used by anyone who needs it .
Becausewehavetoc untheloginatemptsfromalueswer, ’lstorehcounti an
ap licaton-scoped bean. Let’s creat
thatsore thecount inanatribute.Thefol winglistngshowsthedefintionofthis
clas.
Listing 9.12
LoginCountService ap lictaon-scoped bean
The LoginCount Service class count s t he login at t empt s
@Service
@ApplicationScope
public class LoginCountService {
private int count;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
The @ApplicationScope
annotation changes the scope of
this bean to the application scope.
220
CHAPTER 9
Using the Spring web scopes
The
LoginProcessor can then auto-wire this bean and cal the
foranynewloginatempt,as rentedinthefol winglistng.
Listing 9.13
increment() method
Increment ing t he login count for every login request
@Component
@RequestScope
public class LoginProcessor {
private final LoggedUserManagementService loggedUserManagementService;
private final LoginCountService loginCountService;
private String username;
private String password;
We inject the LoginCountService bean
through the constructor’s parameters.
public LoginProcessor(
LoggedUserManagementService loggedUserManagementService,
LoginCountService loginCountService) {
this.loggedUserManagementService = loggedUserManagementService;
this.loginCountService = loginCountService;
}
public boolean login() {
loginCountService.increment();
We increment the count
for each login attempt.
String username = this.getUsername();
String password = this.getPassword();
boolean loginResult = false;
if ("natalie".equals(username) && "password".equals(password)) {
loginResult = true;
loggedUserManagementService.setUsername(username);
}
return loginResult;
}
// Omitted code
}
Thelast hingyou nedtodoistodisplaythisvalue.Asyou’vealrdylearnedinthe
examplewes workedonsta,rinwig thc apyo7ter, ucna uase
controleac’si ntosendthecountvaluoe thveiwYo. ucanthenuThse ymeltaof
display the value in the viw. The fol wing listng shows you how to send the value
fromthecontrole theviw.
Listing 9.14
Model parmetinr he
Sending t he count value from cont roller t o be displayed on t he main page
@Controller
public class MainController {
// Omitted code
Using the application scope in a Spring web app
@GetMapping("/main")
public String home(
@RequestParam(required = false) String logout,
Model model
) {
if (logout != null) {
loggedUserManagementService.setUsername(null);
}
String username = loggedUserManagementService.getUsername();
int count = loginCountService.getCount();
if (username == null) {
return "redirect:/";
}
model.addAttribute("username" , username);
model.addAttribute("loginCount", count);
return "main.html";
Gets the count from the
application-scoped bean
Sends the count
value to the view
}
}
Thefol winglistngshowsyouhowtodispylathecountvalueonthepga.
Listing 9.15
Displaying the count value on t he main page
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<h1>Welcome, <span th:text="${username}"></span>!</h1>
<h2>
Your login number is
<span th:text="${loginCount}"></span>
Displays the count
</h2>
on the page
<a href="/main?logout">Log out</a>
</body>
</html>
Whenyour nthape yo, ufindthoe ntal umboer lf ginatempots nthmae inpage,
asprentedinfigure9.15
221
222
CHAPTER 9
Using the Spring web scopes
Figure 9.15 The result of the application
is a web page t hat displays t he t otal
number of logins for all t he users. This
main page displays t he t otal number of
login at t empt s.
Summary
Aside from the singleton and prot ype bean scopes (discued in chapters 2
throughy5o), ucanbenfroeit muins thg more bre anscopines Spa rinweg b
ap . Thes scopes only make sense in web ap s, and that’s why we cal them
webscopes:
– Requscopt —Sprincegatns i stanoce thf be anfoeacrhHTTPrequest.
– Sesioncp —Sprinceagts instanocethf be anpHTTP
er seionothf e
client.Multiperquestfromthesameclintcansharethesameinstance.
– Aplicaton scope —Ther’s only one instance for the whole ap licaton for
thatspecifban.Everyquestfromanyclientcanacesthisnstance.
Springuarnteshat request-copedbeaninstanceisonlyacesib yone
HTTP request. For this reason, you can use the instance’s atributes without
worying about concureny-crelatd problems. Also, you dont’ ned to wory
that hey might fil the ap ’s memory. Being they ar short-lived, the instances
canbegar -coletdoncetheHTTPrequestnds.
Spring creats request-coped bean instances for evry HTTP request. This is
quite often. You prefably shouldn’t make the instance’s ration difcult by
implementingloicntheconstrucor a
Spring links a seion-scoped bean instance to the HTTP seion of the clint.
Thiswa,yaseion-scopedbeaninstanceanbeusdtosharedtamongmultipleHTTPrequestfromthesameclint.
Evenfroi mthsame clienth, clienat sendHTTPrequcoest ncurenIftly.
thes rquest change dat in the sion-scoped instance, they might ge into
race-onditonscenarios.Y unedtoc nsidersuchsituaonsandeitheravoid
themorsynchronizeyourcodetosup ortheconcurency.
recoI mmendavoidnthg ueoaspf licaton-scopedbani stanWices. thap lication-scopedbeani stanbces inshg aredbthly wee bap requanest, wry ite
operationus alynedsynchronizaton,creatingbotlenecksand ramaticly
@PostConstruct method.
Summary
afectinhg pae p’s erfomanMoce. reovth, bes anilevs youapr me’s mlothasnpry eogitscalnf, bry ’teag-coldA. bapetr oach
istodirectlysohedatinadtbase,you’learninchapter1.
Both seion- and ap licaton-scoped beans imply making request les independent. We ays the ap licaton manages the sta he rquest ned (or that
theap is taeful).Astaefulap impliesdiferntarchitecuralproblemstha
are best o avoid. Of course, describng thes problems i beyond the purpose
of this bo k, but i’s a go d to make you aware tha it’s betr to consider an
alternatei.v
223
RESTservic
Implementig
This chapter covers
Understanding REST services
Implementing REST endpoints
Managing the data that the server sends to the
client in the HTTP response
Obtaining data from the client in the HTTP
request body
Managing exceptions at the endpoint level
In chapters 7 through 9, I mentioned repsntaional stae transfer (REST) serfewavics tmcoes ncerni weg bap licatonIs. thcis apweter, xtendthde iscusiononRESTseircv,andyou’learntheyarnotjusrelatdowebap s.
REST servic a one of the most often encounterd ways to implement communicaton betwen two ap s. REST ofers aces to functionality the serv
exposethroughendpointsa clientcancal.
You use REST servic to establih the communicaton betwen a client and a
servinawebap .ButyoucanlsouseRESTservictodevlopthecommunicationbetwmoena apbinle ackdevntwor boacken(f10ig.u) srvcde
224
Implementing REST services
225
An example of an application that may use a
REST endpoint is a mobile app communicating
with its backend solution. The communication
between a mobile app and its backend service
may be implemented with REST endpoints.
A REST endpoint is a way to implement
communication between two apps.
One of the apps exposes a functionality
by making it accessible through HTTP.
REST
REST
A web app may also use REST to communicate to
the backend service. In many cases today, web apps
are implemented as separate JavaScript solutions
executed in the browser. These solutions, usually
developed with frameworks such as Angular,
ReactJS, or Vue.js, call REST endpoints to
communicate with their backend.
REST
REST
You can use REST endpoints to implement the communication
between two backend components. Today, we often use REST
endpoints to implement the communication between multiple
services that compose a backend solution.
Figure 10.1 REST services are a communication met hod between two apps. Today, you can find REST
services in many places. A web client app or mobile app may call its backend solution through REST
endpoint s, but even backend services might communicat e using REST web service calls.
Becauinse manSpy rinapg tos dyoa uhcave ntocesncounater dwoork nREST
servic,Ionsiderthisubjectamust-learnforevySpringdevloper.
We’sltarbdy iscunwhg eatxclRESy Tservic ariensction10.You’elarn
tha Spring sup orts REST servic with the same Spring MVC mechanism we discused in chapters 7 through 9. In section 10.2, we discu the sntial syntaxes you
nedtoknowwhenworkingwithRESTendpoints.We’lworkonsevralxmplesto
elaborate on the crital aspect any Spring devloper neds to know when implementi gcommunicatonbetwentwoap swithRESTservic.
226
CHAPTER 10
Implementing REST services
10.1 Using REST services to exchange data between apps
In this ecton, we discu REST servic and the way Spring sup orts implementi g
them throughSpring MVC. RESTendpointsrae implyawayforimplementi gcommunicaton betwen two ap s. REST endpoints are simple as implementi g a controle action map ed to an HTTP method na d a path. An ap cals this controle
actionthroughHTTPBe. cauihts’e owna p exposetarvhic oughwea bprot col,wecalthisendpointawebservic.
In the end, in Spring a REST endpoint is stil a controel action map ed to an
HTTP method and path. Spring use the same mechanism you learned for web ap s
for exposing REST endpoints. The only difernce is that for REST servic we’l te
theSpringMVCdispatchersvltnot lo kforaevwi .IntheSpringMVCdiagrm
you learned in chapter 7, the viw resolv disap ears. The srv ends back, in the
HTTPresponsetoheclint,direclywhathecontrole’saci nretuns.Figure10.2
presntshechangesintheSpringMVCflow.
1. The client makes
an HTTP request.
Tomcat
2. Tomcat accepts the request
and delivers it to the Spring app.
A component named dispatcher
servlet gets the HTTP request and
manages the flow.
3. The dispatcher servlet first needs
to find out what method of the
controller to call depending on
the path and HTTP method of
the request. To find the controller’s
method, it uses the handler mapping.
Spring app
Handler mapping
Dispatcher servlet
Controller
4. Once it knows what controller
method to call, the dispatcher
servlet calls the method.
After execution, the controller
method retuns the value to be
sent to the client in the HTTP
reponse body.
View resolver
6. The client gets the HTTP response data.
5. Through Tomcat, the HTTP response
is returned to the client.
Figure 10.2 When implementing REST endpoint s, the Spring MVC flow changes. The app no longer needs
a view resolver because t he client needs the dat a ret urned by the cont roller’s act ion direct ly. Once t he
controller’s action completes, the dispatcher servlet returns t he HTTP response wit hout rendering any view.
Implementing a REST endpoint
227
Youfin’l dRESTcoasrevi mfortabole uThse. simer poislctynreasonthey’r
so often used today, and Spring makes their implementaion straightforward. But
befostarinwig thoufiexarmst pI’lde, toik mayoke uawoare sf mcoe mmunicationisuetheRESTendpointmightbring:
If the controle’s action takes a long time to complet, the HTTP cal to the
endpointmightimeoutandbreakthecommunicaton.
Sendingalrequantiyofdatinonecal(throughtheHTTPrequest)might
cause the cal to ime out and break the communicaton. Sending more than a
fewmegabyteshroughaRESTcalus alyin’therightchoice.
Too many concurent cals on an endpoint exposed by a backend component
mightputo muchpresuontheap andcauseitofal.
The network sup orts he HTTP cals, nd the network is nevr 10% reliab.
Thalwer’scha ysnRESa ce Tendpoinmical t ghbfailecutohsfne twork.
When you implement he communicaton betwen two ap s using REST, you always
ned to consider what should hap en if a cl fais nd how it might afec the ap .
Askyourselfithedatcouldbeafctdinanyway.Couldthwae youdesignedyour
ap leadtodat inconsitenciesfanendpointcalfis?Incasetheap nedstodisplay an ero to the user, how would you do tha? Thes are complex isue and
requireachitecuralknowledgoutsidehescopeofthisbo k,butIrecommendJ.
Geewax’s API Design Paterns (Man ing, 201) an exclnt guide discung the best
practiesofdesigni gAPIs.
10.2 Implementing a REST endpoint
Inthsecionyo, ulearn’ toimplemenRESt Tendpoinwits thSprni Thg. goe dnews
isthatSpring use the same Spring MVC mechanism behind REST endpoints, o y u
alredy know a big part of how they work fom chapters 7 and 8. Let’s ar with an
examp(le ro“jseqct -h10-ebxI’”l). uildmyexampole whvr weat alredy iscued
in chapters 7 and 8, and you’l earn how to ransform a simple web controle into a
RESTcontrole implementRESTwebservic.
Liinst g 10. shows you a controle sca tha implemenst a simpel ioact n. As you
learndfromchapter7,wean otaeheoc notr elascwiththe
typane otai nTh. waanis by, ecothanls mf beanithSps riencog xt,e
andSprinMVC
g knconwa throismalea mepits ht ospHTTP
dt ecif phat .s
Alwesou, thed
@GetMappingan otai hspcnoyeif athnHTTP
d method.
Thoe nly we thinyog ufindinthinls htg ue os thf e
The
@ResponseBody an otai n telshedispchat er tsvlhatheconrot le’s aci n
doesntu’r nwavie namebuthedasnt dyinectlr heHTTPresponse.
Listing 10.1
@Controller stero-
@ResponseBody an oati n.
Implement ing a REST endpoint act ion in a cont roller class
@Controller
public class HelloController {
We use the @Controller annotation to
mark the class as a Spring MVC controller.
228
CHAPTER 10
@GetMapping("/hello")
@ResponseBody
public String hello() {
return "Hello!";
}
Implementing REST services
We use the @GetMapping annotation to associate the GET
HTTP method and a path with the controller’s action.
We use the @ResponseBody annotation to inform
the dispatcher servlet that this method doesn’t
return a view name but the HTTP response directly.
}
Bulot whk hat p enweifs ad momere thodtos hcoe ntrolshe, owni thfoe l wni g listng. Repeating the
an oying.
Listing 10.2
@ResponseBody an otai n on evry method becomes
The @ResponseBody annot at ion becomes duplicat ed code
@Controller
public class HelloController {
@GetMapping("/hello")
@ResponseBody
public String hello() {
return "Hello!";
}
@GetMapping("/ciao")
@ResponseBody
public String ciao() {
return "Ciao!";
}
}
avoAidpsbenrtacodg ue pcliatonWe. wasont mehowprevnpteainhge
@ResponseBodyan otai nfoeachr methodTo. helpuwis th aspi Sect, rinog fers
@RestControlleran otai ncoa, mbinationof
the
You se
@RestController toinstrucSpringthalthecontrole’saci nsareREST
endpoints. This way, ou avoid repating the
showwhs yoat unedtochanige thcoe ntroleuse
inclas tedof
@ResponseBodyefaochmer thodTo. alowyoanutes dcompbaore th
ap roaches,Ipratdhiscodeinthexample“sq-ch10ex2.”
Listing 10.3
@ResponseBody .
@ResponseBody an otai n. Listing 10.3
@RestControlleronfoce thr e
Using t he @RestController annot at ion t o avoid code duplication
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello!";
}
@GetMapping("/ciao")
public String ciao() {
return "Ciao!";
}
}
@Controllerand
Instead of repeating the @ResponseBody
annotation for each method, we replace
@Controller with @RestController.
Implementing a REST endpoint
229
It was inde easy to implement a couple of endpoints. But how do we validte hey
wocork Inetly? hsectionyo, ulearn’ toycal uenr dpoinuts intwg ot yols u’l
oftenncounterinreal-worldscenarios:
Postman—OffersaniceGUIandis comfortableouse
cURL—A command-line to l usef l in case wher you don’t have GUI (e.g,
when you con ect to a virtual machine iva SH or when you write a batch
sc rip t)
Boththesto lsaremust-learnforanydevloper.Inchapter15,you’learnathird
ap roach for validtng tha n endpoint behaves expctd by writng an integrationtes.
First, star the ap licaton. You can use either project “sq-ch10-ex” or “sq-ch10ex2.” They have the same behavior. The only difernce is the syntax, s discued in
earli parg hs. As you learned in chapter 7, by default, he Spring Boot ap configuresaTomcatservlontainertobeacsi lonport80.
Ledt’s icuPs ostmanYofirst. unedtointhsal oe ol nyousytemr psa rented
on their ofical website:
instaledwh, enyouopenyoit, ufin’l dhit ans i thelkrfac onpe rsntedinfgure10.3
You create a new tab to
define an HTTP request.
hwtp/ww.s: postman.com/
You select the HTTP method
of the HTTP request you want
to send.
You can use these tabs to define
HTTP request parameters, headers,
or the body of the request.
. Once you have Postman
In the address bar, you write
the URI for the HTTP request.
You click the Send button to
send the HTTP request.
Figure 10.3 Postman offers a friendly int erface t o configure and send an HTTP request . You select the HTTP
met hod, set t he HTTP request URI, and t hen press the Send but ton t o send an HTTP request. You can also define
other configurat ions such as t he request paramet ers, headers, or the request body if needed.
230
CHAPTER 10
Implementing REST services
Once you click the Send button, Postman sends
the HTTP request. When the HTTP request is
completed, Postman displays details of the
HTTP response it received.
Here, you find the HTTP response status
If you send headers in the HTTP
code, the execution time, and the amount
response, Postman displays
of transferred data in bytes.
them in this tab.
Here, you find the HTTP response
body. In our case, the string “ Hello!”
Figure 10.4 Once t he HTTP request complet es, Post man displays t he HTTP response det ails. You find
the response st at us, t he time it t ook the request to complet e, t he amount of transferred data in bytes,
and the response body and t he headers.
OncyeouptreshSndbutonP, ostmanse dths HTTP
e requWhest. enthrequest
complets,PostmandisplaytheHTTPresponsedtails,prentedinfigure10.4
Inyocase udonh’t GUIaev yo, ucanucoasemmand-lintoe anlc e dpoint.
You’l aso find articles and bo ks often use command-line to ls for demonstraions
ratherthanGUIto lsbecausit’hortewaytorepsnthecommand.
Ifyoucho setousecURLascommand-lineto likenthecasofPostman,you
nedfirtos masuke yor uinYost.al uincUstal RLacordintog y uor peratinsygtemasdecribdontheto l’soficawebpage:
Oncyeouhavinte saledndconfiguredyo, ucanutshe
HTTP request. The fol wing snip et shows you the command you can use to send
theHTTPrequestohe/helondpointexposedbyourap :
curl http://localhost:8080/hello
hcutp/rl.se :
curlcommandtosend
Managing the HTTP response
231
Upon completing the HTTP request, the console only display the HTTP response
bodypresntedinthenxtsnip et:
Hello!
If the HTTP method is HTTP GET, you don’t ned to specify t explicty. When the
methodnis oHTTP
t GET,oyifruwantospexicfyolt, ucanuthse
asprentedinthenextsnip et:
-Xflag,
curl -X GET http://localhost:8080/hello
IfyouwantogemoredtailsofheHTTPrequest,youcanad the
command,asprentedinthenextsnip et:
-v optiontohe
curl -v http://localhost:8080/hello
The next snip et presnts the result of this command, which is a bit more complicatedYo. ualsofindthlikeas uths, ame ounotdf ransferdan, dheadrs
th ro u gh t e l n g th yr esp o n se:
Trying ::1:8080...
* Connected to localhost (::1) port 8080 (#0)
> GET /hello HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.73.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200
The HTTP response status
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 6
< Date: Fri, 25 Dec 2020 23:11:02 GMT
<
{ [6 bytes data]
100
6 100
6
0
0
857
0 --:--:-- --:--:-- --:--:-1000
The HTTP response body
Hello!
* Connection #0 to host localhost left intact
10.3 Managing the HTTP response
In this section, we discu managing the HTTP response in the controle’s action.
TheHTTPresponsehi owthebackndap sends atbckotheclintduetoaclient’srequest.TheHTTPresponseholds athefol wing:
Responhadr —Short piecsofdatinthersponse(us alynotmorethana
fewwordslong)
The respon body —A large amount of dat the backend neds to send in the
re sp o ns e
Therspontau —Ashortepsntaionoftherquest’ result
Take a few minutes and reviw ap endix C to remember the details about HTTP
beforg ingfurther.Inseicot n10.3and10.32,wediscutheoptionsyouhavefor
232
CHAPTER 10
Implementing REST services
sendindg inat hersponbse ody.Insection10.3,youl’earnhowtosehHTTP
responsetaundheadrsifned .
10.3.1 Sending objects as a response body
In this section, we discu sending object instances in the response body. The only
thingyounedtodot sendanobjectoheclintinaresponseimakethecontrolleactir’os nretuntha objeInct. hexamp“sqle -ch10-ewex3,” definmoae doel bject
n am e d
Country with the atributes
lation (repsnting the number of milions of people ocated in that country). We
implementacontroleaci ntoreuna instanceoftype
Listinh10.4g owths clae dt efinthes
Countrytomo) dthel rant sferdbtwentwoap wes, namtheoisbject
(suchas
a dt rnsfe objct (DTO). We can say that
retunedbytheRESTendpointweimplementintheHTTPresponsebody.
Listing 10.4
name (repsnti g the country name) and
popuCountry .
Country objWh
ect. enweuanse object
Country is our DTO, whose intsances ar
Model of t he dat a t he server ret urns in t he HTTP response body
public class Country {
private String name;
private int population;
To make a Country instance simpler, we define a
static factory method that receives the name and
the population. This method returns a Country
instance with the provided values set.
public static Country of(
String name,
int population) {
Country country = new Country();
country.setName(name);
country.setPopulation(population);
return country;
}
// Omitted getters and setters
}
Thfoe l winsltg howths ime pelmentaoi nocafntroaciel’s nthreuat nas
instanceoftype
Listing 10.5
Country .
Ret urning an object inst ance from t he cont roller’s act ion
@RestController
public class CountryController {
Marking the class as a REST controller to add a bean
in the Spring context and also inform the dispatcher
servlet not to look for a view when this method returns
@GetMapping("/france")
public Country france() {
Mapping the controller’s action to the
HTTP GET method and /france path
Country c = Country.of("France", 67);
return c;
Returning an instance of type Country
}
}
Managing the HTTP response
What hap ens when you cal this endpoint? How would the object lo k in the HTTP
response body? By default, Spring creats a string repsntaion of the object and
formats it as JSON. JavScript Object Notaion (JSON) is a simple way to format
strinabgs ute-val pThairs. goaer’s dchanyoce use’vnJSONlraedby, uift
you haven’t used it befor, I pre ad a discuion with evrything you ned to know
inap endixD.
When caling the /france ndpoint, he rsponse body lo ks a presnted in the
n ex tsn ip et:
{
"name": "France",
"population": 67
}
Figure10.5mni dsyouwher youfindtheHTTPresponse bodywhenyou sePostmantocalhendpoint.
Here, you find the HTTP response body after you
send the request by clicking the Send button.
Figure 10.5 Once you press the Send butt on, Post man sends t he request. When t he request completes,
Post man displays t he response det ails, including t he response body.
233
234
CHAPTER 10
Implementing REST services
Youcouldasoendobjectoli ninstancesinthersponsebody.Thenextlisng
showsthatwead edamethodthatreunsa
List of
Listing 10.6
Country objects.
Ret urning a collect ion in t he response body
@RestController
public class CountryController {
// Omitted code
@GetMapping("/all")
public List<Country> countries() {
Country c1 = Country.of("France", 67);
Country c2 = Country.of("Spain", 47);
return List.of(c1,c2);
}
Returns a collection in the
HTTP response body
}
Whenyouthcal enis dpointh, responbse odloy paskrentedinthne sxt ip et:
In JSON, the list is defined with brackets.
[
{
"name": "France",
"population": 67
},
{
Each object is between curly
braces, and the objects are
separated with commas.
"name": "Spain",
"population": 47
}
]
Using JSON is the most common way to repsnt objects when working with REST
endpoints. Although you aren’t constrained to use JSON as n object rpesntaion,
you’l proba ly nevr s someone using something els. Spring ofers the posiblty
ofusingotherwaystof rmathersponsebody(likeXMLorYAML)ifyou’dlike,by
plugingcua stomconfvoerty uor bHojects. wthevr, c anyoces un’l edthis
inarel-worldscenarioes malthatwewilskipthisdcusionandgodirectlyo
thenextrlvantopicyounedtolearn.
10.3.2 Setting the response status and headers
In this section, we discu seting the response stau and response headrs. Sometimes it’s more comfortable to send prat of the dat in the response headrs. The
response stau is also an esntial flag in the HTTP response you use to signal the
request’r l.Bydefault,SpringsetomecommonHTTPstaue:
Managing the HTTP response
235
20 OK fi no excption was thrown on the serv side while procesing the
request.
40NotFuondifherquestdrourcedoesn’texis.
40 Bad Requst if a part of the rquest could not be matched with the way the
servxpctdhedat.
50 Ero n serv if an excption was thrown on the srv ide for any reason
whpile rocesinthg requUsest. ufaoly,thr kins doexcpf tionth, clienat ’
do anything, and it’s expctd someone should solve the problem on the
backend.
Howevr, in some cas, the rquirements ak you to c nfigure a custom stau. How
could you do that? The easit and most common way to customize the HTTP
re sp o ns e i u sin g th e
to specify the response body, stau, and headrs on the HTTP response. Example
“sq-ch10-edx4” monstrahe uose thf e
trole aci nretunsa
on the response body directly. The
responsebody’svalueandthersponsetausandheadrs.Wesethreheadrsna d
changethersponseatuo“20Acceptd.”
Listing 10.7
ResponseEntity clas. This cla provide by Spring alows you
ResponseEntity claIsn. it 10ga.7, conResponseEntity instanceinsteadoftheobjectyou wantoest
ResponseEntity clas alows you to set the
Adding custom headers and set t ing a response st at us
@RestController
public class CountryController {
@GetMapping("/france")
public ResponseEntity<Country> france() {
Country c = Country.of("France", 67);
Changes the HTTP response
return ResponseEntity
status to 202 Accepted
.status(HttpStatus.ACCEPTED)
.header("continent", "Europe")
Adds three custom
.header("capital", "Paris")
headers to the response
.header("favorite_food", "cheese and wine")
.body(c);
Sets the response body
}
}
Once you send the rquest using Postman, you can verify the HTTP response taus
changedto“20Acceptd”(figure10.6)
IntheHeaderstaboftheHTTPresponseinPostman,youalso findthethrecustomresponseheadrsyouad ed(figure10.7)
236
CHAPTER 10
Implementing REST services
The response body
still contains the JSONformatted Country object.
Aside from the response body,
you can observe the HTTP response
status changed to 202 Accepted.
Figure 10.6 Once you send t he HTTP request by pressing t he Send but ton and get the HTTP response, you observe
the HTTP response stat us is 202 Accept ed. You can still see t he response body as a JSON formatt ed string.
In the headers tab, you find the custom
headers you added on the HTTP response.
Figure 10.7
To see t he cust omer headers in Post man, you have t o navigat e to t he Headers tab of the HTTP response.
Managing the HTTP response
237
10.3.3 Managing exceptions at the endpoint level
esnIt’oc ialnsidwher hta p thencoif s troaci le’snthrowanexcsptionI .
manwecase,y uexcsptiontosignspal ituecf aonso, moethf relatsdothe
busines logic. Sup ose you creat n endpoint he clint cals o make a payment. If
thuedsr oesnh’t enav oughmoniey thacoeir unth, ape mighrept snthsiuationbythrowni ganexcption.Inthiscae,you’lproba lywantose medtails
ontheHTTPresponsetoinformtheclintofhespciftuaionthatocured.
One of the ways ou can manage xcptions i cathing them in the controle’s
a ctio n a n d u sin g th e
diferntconfiguratonofthersponsewhenthexcptionocurs.
We’lstarbydemonstraingthisap roachwithanexampel.I’thenshowyouan
alternateiv p roach I pref by using a REST controle advice asl: n aspect hat
intercpans e dpoinwhcalt entihrowans excptiona, dyoucanspecifauy stom
logict bexcutdforthatspecifxption.
Let’s creat a new project named “sq-ch10-ex5.” For our scenario, we define an
excption named
when it can ot fuli the payment becaus the clint doesn’t have nough money in
theiracount.Thenxtcodesnip etshowstheclasdefin gthexcption:
ResponseEntity clas,youlearnedinsection10.32,tosenda
NotEnoughMoneyException , and the ap wil throw this excption
public class NotEnoughMoneyException extends RuntimeException {
}
We also implement a servic las that defines the use ca. For our tes, we directly
throw this excption. In a rel-world scenario, the srvic would implement he complex ogic for making the payment. The next code snip et shows the srvic la we
use for urtes:
@Service
public class PaymentService {
public PaymentDetails processPayment() {
throw new NotEnoughMoneyException();
}
}
PaymentDetails ,thertunedtypeofthe
clas describng the response body we expct the controle’s action to retun for a
sucef lpayment.Thenxtcodesnip etprsntshe
processPayment() method,isjustamodel
PaymentDetails clas:
public class PaymentDetails {
private double amount;
// Omitted getters and setters
}
When the ap encounters an excption, it ues another model clas named
Details to inform the clint of the situaon. The
ErrorErrorDetails clas i also simple
238
CHAPTER 10
andondly efinthes ro
ErrorDetails modelcas:
Implementing REST services
messageans tribuThte. ne coxt dsne ip pet rsnths e
public class ErrorDetails {
private String message;
// Omitted getters and setters
}
Howcouldthcoe ntrodle ci whe oat bjectosndbdack epndinog nhowthfelow
excutWhd? enthexrcp’soti n(hapsue cfomly pthlesaymenwet),
wantoreunanHTTPresponsewiththestau“Aceptd”oftype
Sup othapse ncounterdanxcptiondunrithexcug tionfl wInth.case, t
controacile’snrtuna sHTTPresponwise thstBaau“40e dRequanest” dan
ErrorDetails instancoe ntai nmeag thsage describthisue F.iguvs1r0e.8 alypresntsherlationshipbetwenthecompone tsandtheirsponsiblte.
PaymentDetails .
The service class implements
the business logic that might
throw exceptions.
HTTP
PaymentController
PaymentService
The controller manages the exceptions
the service code might throw and sends
an HTTP response according to the
execution result.
Figure 10.8 The PaymentService class implements t he business logic that might t hrow except ions.
The PaymentController class manages t he exception and sends t he client an HTTP response
according t o the execut ion result.
Thenxtlisngshows thislogcmplementedbythecontrole’smethod.
Listing 10.8
Managing the HTTP response for except ions in t he controller’s action
@RestController
public class PaymentController {
private final PaymentService paymentService;
public PaymentController(PaymentService paymentService) {
this.paymentService = paymentService;
}
@PostMapping("/payment")
public ResponseEntity<?> makePayment() {
Managing the HTTP response
try {
PaymentDetails paymentDetails =
paymentService.processPayment();
return ResponseEntity
239
If calling the service method succeeds,
we return an HTTP response with status
Accepted and the PaymentDetails
instance as a response body.
We try calling the
.status(HttpStatus.ACCEPTED)
processPayment()
.body(paymentDetails);
method of the } catch (NotEnoughMoneyException e) {
service.
ErrorDetails errorDetails = new ErrorDetails();
errorDetails.setMessage("Not enough money to make the payment.");
return ResponseEntity
If an exception of type NotEnoughMoneyException is
.badRequest()
thrown, we return an HTTP response with status Bad
.body(errorDetails);
}
Request and an ErrorDetails instance as a body.
}
}
Starheap licatonna dcalthendpointusingPostmanorcURL.Weknowthatwe
madthe mesrvic thodtoalwthays rowthe
to se the rsponse stau mesage is “40 Bad Request,” and the body contains the
ero mesage. Figure 10.9 presnts he rsult of sending a request o the /payment
e nd p o in t in P os tm a n .
The exception description
appears in the HTTP
response body.
NotEnoughMoneyExceptionso,weexpct
The status of the HTTP response
is 400 Bad Request.
Figure 10.9 Calling the / payment endpoint , t he HTTP response st atus is “ 400 Bad Request ” and the
exception message appears in t he response body.
240
CHAPTER 10
Implementing REST services
Thisap roachisgo d,andyou’loftenfind evlopersuingitomanagethexcption cas.eHowevr, ina morecomplexap licaton,you would find it more comfortable to separt the responsiblty of excption mangaement. First, sometimes the
same xception has to be managed for multipe ndpoints, and, as you guesd, we
don’t want o introduce duplicated code. cSond, it’s more comfortba le to know you
findthexcptionlogica noneplace whenyounedtounderstandhowaspecif
case works. For thes raons, I pref using a REST controle advice, an aspect hat
intercps excptions thrown by controles’ actions and ap lies custom logic you
defineacordingtoheintrcepdexcption.
Figure10.persntshechangeswewantomakeinourclasdeign.Takesome
timetoc mparethisnewclasdgnei witht eonei fgure10.8
The controller advice implements the
logic for cases where the service
has thrown an exception.
The service class implements
the business logic that might
throw exceptions.
ExceptionControllerAdvice
ErrorDetails
Exception
HTTP
PaymentController
PaymentService
PaymentDetails
The controller calls the service use case
but only treats the happy flow (where the
service method didn’t throw an exception).
Figure 10.10 Inst ead of managing t he exception cases, t he cont roller now only t akes care of the happy
flow. We added a cont roller advice named ExceptionControllerAdvice t o take care of the logic t hat
will be implement ed if t he cont roller’s action throws an exception.
Inthpe ro“sqject -h10-eyox6,” ufindthcis animge plementedTh. coe ntroacile n
is much simplifed becaus it no longer treas the excption case, as presnted in the
fol winglistng.
Managing the HTTP response
Listing 10.9
241
Cont roller’s act ion t hat no longer t reat s t he except ion case
@RestController
public class PaymentController {
private final PaymentService paymentService;
public PaymentController(PaymentService paymentService) {
this.paymentService = paymentService;
}
@PostMapping("/payment")
public ResponseEntity<PaymentDetails> makePayment() {
PaymentDetails paymentDetails = paymentService.processPayment();
return ResponseEntity
.status(HttpStatus.ACCEPTED)
.body(paymentDetails);
}
}
Instead, we creatd a separt clas named
ExceptionControllerAdvice that implemenwhts hat p thencoif s troaci le’snthrowa s
NotEnoughMoneyExceptionTh. e
ExceptionControllerAdvice clas i a REST controle advice. To mark it as REST
controle advice, we use the
@RestControllerAdvice an otai n. The method the
clasdefinesialocedanexcptionhandler.Youspecifywhatexcpionstrigea
controleadivcemethodusingthe
@ExceptionHandler an otai noverthemethod.
Thfoel winlst ghowthsRESe Tcontroadlces’vifnitona dthexcption handler method tha implements the logic asocited with the
NotEnoughMoneyException excption.
Listing 10.10
Separat ing t he except ion logic wit h a REST cont roller advice
@RestControllerAdvice
public class ExceptionControllerAdvice {
We use the @RestControllerAdvice
annotation to mark the class as a
REST controller advice.
@ExceptionHandler(NotEnoughMoneyException.class)
public ResponseEntity<ErrorDetails> exceptionNotEnoughMoneyHandler() {
ErrorDetails errorDetails = new ErrorDetails();
errorDetails.setMessage("Not enough money to make the payment.");
return ResponseEntity
We use the @ExceptionHandler method to associate
.badRequest()
an exception with the logic the method implements.
.body(errorDetails);
}
}
NOTE In production ap s, you sometimes ned to send information about
thexcptionthoat curedfo, mthcoe ntroaclie’s ntohade Invic. this
case, you can ad a parmetr o the advice’s xption handler method of
the type of thehandle excption.Springismartenough topasthe xcptionrefncefromthecontrole theadvic’sexptionhandlermethod.
Youcanthenuseanydetailsofhexcptioni stanceintheadvic’slog.
242
CHAPTER 10
Implementing REST services
10.4 Using a request body to get data from the client
Inthisecton,wediscugetingdatfromtheclintintheHTTPrequestbody.You
learnedinchapth8er yoa ucanse d inat hHTTP
e request inreqg upest armetrs and path varibles. Because REST endpoints rely on the same Spring MVC
mechanism, nothing from the syntaxes you learned in chapter 8 changes regading
sending dat in request parmetrs and path varibles. You can use the same an otations and implement he REST endpoints identicaly as you were implementi g the
controleaci nsfory urwebpages.
Howevr, we di n’t discu one esntial thing: the HTTP request has a request
body,andyoucanuseitond atfromtheclintohesrv.TheHTTPrequest
bodyisoftenusedwithRESTendpoints.Asalsomentionedinap endixC,whenyou
ned to send a large quantiy of dat (my recommendation is anything that takes
morethan50to1charsc)t,eyou setherquestbody.
Tousetherquestbody,ouj stnedtoan otaeparmetrofhecontrole’s
actionwith
@RequestBody By. defauSltp, ringasumesyou sedJSONtorepsnthe
parmetr you an otaed and wil try o decode the JSON string into an instance of
your parmetr type. In the case Spring can ot decode the JSON-formated string
intohtypa he, ap sendbs reapck onwise th staeu“Ba40 dRequIesnt.” he
proje“cstq-h10-ex7,we” implementasimpelxampleofusinthg erquestbody.The
controle defines an action map ed to the /payment path with HTTP POST na d
expcts to get a request body of
PaymentDetails type. The controle prints the
amount of the
PaymentDetails object in the serv’ console and sends the same
objectinthersponsebodybacktoheclint.
Thne lixtsnghowths de nfi tonofthcoe ntroline thpe roje“sctq-h10-ex7.”
Listing 10.11
Get t ing dat a from t he client in the request body
@RestController
public class PaymentController {
private static Logger logger =
Logger.getLogger(PaymentController.class.getName());
@PostMapping("/payment")
public ResponseEntity<PaymentDetails> makePayment(
@RequestBody PaymentDetails paymentDetails) {
logger.info("Received payment " +
paymentDetails.getAmount());
return ResponseEntity
.status(HttpStatus.ACCEPTED)
.body(paymentDetails);
}}
We get the payment
details from the HTTP
request body.
We log the amount of the payment
in the server’s console.
We send back the payment details object
in the HTTP response body, and we set the
HTTP response status to 202 ACCEPTED.
Using a request body to get data from the client
243
Fgiure 10. shows you how to use Postman to cal the /payment endpoint with a
requestbody.
To set the request body, you select the Body tab
on the HTTP request configuration. You then choose
the option “ raw” by clicking the radio button and
then choose JSON as the formatting style.
In the text area you write the JSON-formatted
request body representing the PaymentDetails
object. Then you click the Send button to send
the HTTP request.
Once the request completes,
Postman shows the response details.
Figure 10.11 Using Post man t o call t he endpoint and specify t he request body. You need t o fill t he JSONformat t ed request body in t he request body text area and select the dat a encoding as JSON. Once the request
completes, Post man displays t he response det ails.
IfyouprefusingcURL, youcanusethecommandpresntedbythenxtsnip et:
curl -v -X POST http://127.0.0.1:8080/payment -d '{"amount": 1000}' -H
➥ "Content-Type: application/json"
244
CHAPTER 10
Implementing REST services
Can an HTTP GET endpoint use a request body?
I often hear this question from students. Why is using HTTP GET with a request body
the subject of confusion? Before 2014, the HTTP protocol specification didn’t allow
a request body for HTTP GET calls. No implementation for the client or server side
allowed you to use a request body with an HTTP GET call.
The HTTP specification changed in 2014, and it now allows the use of the request
body with an HTTP GET call. But sometimes students find old articles on the internet
or read book editions that were not updated, and this seems to create confusion
years later.
You can read more details about the HTTP GET method in section 4.3.1 of the HTTP
specification, RFC 7231: https://tools.ietf.org/ html/ rfc7231#page-24.
Summary
Represntaional ste ransfer (REST) web servic ae simple way to estabilshcommunicatonbetwentwoap licatons.
In a Spring ap , the Spring MVC mechanism sup orts he implementaion of
RESTendpoinY etuhs.nertods
tha method directly retuns the rsponse body or eplac the
an otai nwith
use one of thes, the dispatcher servlt wil asume the controle’s method
retunsaviewnameandtryol okf rthatviewinstead.
You can make the controle’s action directly urn the HTTP response body
andrelyonSpringdefault’sbehaviorf theHTTPstau.
You can manage the HTTP stau and headrs by making your controle’s
a ctio n re tu n a
One way to manage excptions is to trea them directly at the controle’s
actionlev.Thisap roachouplesthelogicusedtoreahexcption tohat
specif controle action. Sometimes using this ap roach can lead to code
duplicaton,whichsbetoav id.
You can manage the xceptions in the controle’s action directly or separt
the logic exutd if the controle’s action throws an excption using a REST
controleadvicls.
AnendpointcangetdafromtheclinthroughtheHTTPrequestinrequest
parmetrs,pahvaribles,ortheHTTPrequestbody.
@ResponseBodyan otai spnoecify
@Controller
@RestController toimplementaRESTendpoint.Ifyou don’t
ResponseEntity instance.
RESTendpoits
This chapter covers
Calling REST endpoints using Spring Cloud
OpenFeign
Calling REST endpoints using RestTemplate
Calling REST endpoints using WebClient
In chapter 10, we discued implementi g REST endpoints. REST servic rae a
common way to implement he communicaton betwen two sytem compone ts.
Theclintofawebap cancalthebacknd,andsocananotherbackndcompone t.Inabckendsolutioncomposedofmultipesrvc(ap endixA),thes
componentsnedto“speak”toxchangedat,sowhenyouimplementsuchaservice using Spnri g, you ned to know how to cal a REST endponi t exposed by
anothersvic(fgure1.)
245
Consuming
246
CHAPTER 11
Consuming REST endpoints
A REST endpoint is a way to implement
communication between two apps.
One of the apps exposes a functionality
by making it accessible through HTTP.
REST
BACKEND
REST
REST
Often, multiple apps compose
the backend. These apps often
communicate via REST services.
One app needs to call endpoints
exposed by another.
REST
Figure 11.1 Oft en, a backend app needs t o act as a client for anot her backend app, and calls exposed
REST endpoint s to work wit h specific dat a.
Inthischapter,you’learnthrewaystocalRESTendpointsfromaSpringap :
1
2
3
OpenFeign —Ato loferdbytheSpringCloudproject.I mmend evlop-
ersuthisfeaturn ewap sforc nsumingRESTendpoints.
RestTemplate —A wel-known to l devlopers have used since Spring 3 to cal
RestTemplate sioftenusedtodayinSpringap s.Howevr,as
RESTendpoints.
we’l discu in this chapter,
OpenFeign is a betr alnative o
soify uworkona ewap ,you’lproba ly avoid
Feign instead.
WebClient —ASprinfeatug pr esntedans lter toaive
featur use a difernt progamming ap roach named reactiv progamming,
whichwe’ldiscuathendofthischapter.
RestTemplate ,
RestTemplate anduse
OpenRestTemplateTh. is
Consuming REST endpoints
247
ThSpfirste ncapg bweilty discun, sectionis1.,
OpenFeignwh, ichps oarthf e
SprinClg oudfamanily dfeaturcoI mmendfonalr ewimplementaiontos dAsay.
yo u ’l lea rn ,
OpenFeign ofers a ismple syntax and makes caling a REST endpoint
fromaSpringap straightforward.
Insectionwe1.2, u’l se
RestTemplateBu. bcareftul!
RestTemplatehbasenput
inmaintena moce dstraine wig thSprina5,g dwiit evnl tubalyde precatdWh. y
RestTemplate to
amIteachingyouabouti,hen?Moost f day’sSpringprojecuts
REScal Tendponi btsecauhrdwhey enthwais thoentohblysr etuionf r
implementisucaphgFboilmty.r thpaofes ,
RestTemplatecapreb’s ilt
enoughandwofinrk soe,placinthg emmankes onSose. metimthes imne de
toreplac
RestTemplatewithna ewsoer lutionmighbtoe c sotly,earnistl g
amustforaSpingdevloper.
RestHere’sanintersingfacthatus alycretsonfusion forstudents.Inthe
Template documentaion (
hmtp/: ng.bz/7lWe
), WebClient si nevg sa ocermmenRestTemplate. In section 1.3, I’l explain why using
doitan of r penical g ht e ues of
WebClient isnotalwaysthebstalrnativeo
RestTemplate .We’ldiscu
WebClient
andclarifywhenit’sbeousethiscapbilty.
Toteachyouthesthrefundamentalways,we’lwriteanexampleforach.We’l
imfrst plemenpa rothjecxpat onse dpoinOut. prurpthocalenis dpoint
ineachp roachwediscunthc is apter:
OpenFeign , RestTemplatean, d
WebClient .
Sup ose you implement an ap tha alows user to make payments. To make a
paymenyot, unedtocanl e dpoinot anf othseytrmF.igu1vs.2re paly resnts
this scenario. Figure 1.3 details the scenario showing the request and response
details.
This is the app we implement differently for each section of this
chapter. We’ll first use OpenFeign, then RestTemplate, and finally,
WebClient, to call the /payment endpoint of the payment service.
The user interacts
with the app’s
frontend in a
web browser.
The app you implement
needs to call the /payment
endpoint exposed by the
payment service.
/payment
POST /payment
/payment
POST /payment
Your app
Assume the app you implement
is the backend of a web app. The user
manages their bills through this app
and can make payments when needed.
Payment service implements a
REST endpoint /payment. For our
scenario, we assume an app needs
to call this endpoint to make
a payment.
Payment service
When making a payment, the frontend
calls the /payment endpoint of this app,
which in turn calls the /payment
endpoint of the payment service.
Figure 11.2 To properly t each you how t o call REST endpoints, we’ll implement several examples. For
each example, we implement t wo project s. One exposes a REST endpoint. The second demonstrates the
implement at ion for calling t hat REST endpoint using OpenFeign , RestTemplate , and WebClient .
248
CHAPTER 11
Consuming REST endpoints
The app further calls the payment service,
sending the same body and adding a request
header named “ requestId” with a random value.
When calling the /payment endpoint,
we provide a request body shaped as
a Payment object.
/payment
POST /payment
{"amount":1000}
POST /payment
requestId: <some random ID>
{"amount":1000}
{"id":"211499...","amount":1000.0}
{"id":"211499...","amount":1000.0}
/payment
Payment service
The app
The payment service responds with the
payment object, to which it assigns an ID.
The app receives this response and sends
it and an HTTP response back.
This is the app we implement
now and that we’ll use throughout
the chapter.
Figure 11.3 The payment service exposes an endpoint t hat requires an HTTP request body. The app uses
OpenFeign , RestTemplate , or WebClient to send request s to t he endpoint t he payment service exposes.
With firstpoject,weimplementhepaymenstrvicape .Weu’l sethisap inal
ournextamples.
Lethcrea’s pro“sqject -h1-paymenwhts,” ichrepsnths pe aymensrvic.t
It’sa webap ,solikeatheprojectswediscuedinchapters7hrough10,wened
toad tohpe om.xmthfile webdepndenpascy,rentedinthne coxt dsne ip et:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Wemo’l dthel paymenwit ht e
Paymentpas recln, tedinhnecoxtdsne ip et:
public class Payment {
private String id;
private double amount;
// Omitted getters and setters
}
Listing1.showsthendpoin’stimplementaioninthecontrolecas.Technicaly,
itdoesn’tdomuch.Themethodrecivsa
the payment befor retuni g it. The endpoint is simple but go d enough for our
Payment instanceandsetarndomIDto
Calling REST endpoints using Spring Cloud OpenFeign
demonstraion. We ues HTTP POST. We ned to specify a request headr and the
requestbody.ThendpointreunsaheadrintheHTTPresponseandthe
objectinthersponsebodywhencaled.
Listing 11.1
249
Payment
The / payment endpoint ’s implement at ion in t he cont roller class
The app exposes the endpoint with
HTTP POST at the path /payment.
@RestController
public class PaymentsController {
We use a logger to prove the right
controller’s method gets the correct
data when the endpoint is called.
private static Logger logger =
Logger.getLogger(PaymentsController.class.getName());
The endpoint needs to get a request
@PostMapping("/payment")
header and the request body from the
public ResponseEntity<Payment> createPayment(
caller. The controller method gets
@RequestHeader String requestId,
these two details as parameters.
@RequestBody Payment payment
) {
logger.info("Received request with ID " + requestId +
" ;Payment Amount: " + payment.getAmount());
payment.setId(UUID.randomUUID().toString());
return ResponseEntity
.status(HttpStatus.OK)
.header("requestId", requestId)
.body(payment);
}
The method sets a random
value for the payment’s ID.
The controller action returns the HTTP
response. The response has a header
and the response body that contains the
payment with the random ID value set.
}
You can now run this ap , and it wil tsar Tomcat on port 80, which is the Spring
Boot default, as we discued in chapter 7. The ndpoint is acebl, and you could
atcwili th cURLorPostmanBu. thpe urpose fthcis aptiserolanhowtoimplementanap thatclshendpoint,sothis exactlywhtawewildoinsections1.,
1.2,and1.3
11.1 Calling REST endpoints using Spring Cloud OpenFeign
In this section, we discu a modern ap roach for caling REST endpoints from a
Sprni g ap . In most ap s, devlopers have used
section 1.2) As mentioned earli n this chapter,
mode staring with Spring 5. Moreov,
pref to begin this chapter by discung the alternative to
mendyou se:
OpenFeign .
With
OpenFeign yoas, u’lfindoutinhexampwele writenhisectonyo, uonly
nedtowriteani terfac,ndtheto lprovidesyouwiththeimplementaion.
RestTemplate (that we’l discu in
RestTemplate is n maintena ce
RestTemplate wil be deprcatd so n, so I
RestTemplate I recom-
250
CHAPTER 11
Consuming REST endpoints
/payment
POST /payment
{"amount":1000}
POST /payment
requestId: <some random ID>
{"amount":1000}
{"id":"211499...","amount":1000.0}
{"id":"211499...","amount":1000.0}
Payment service
The app
Figure 11.4 We now implement t he app t hat
consumes t he / payment endpoint t he payment
service exposes. We use OpenFeign to implement
the funct ionality that consumes the REST endpoint .
This is the app we implement now. This
app uses OpenFeign to call the /payment
endpoint of the payment service.
To teach you how
menat p thuat se
(figure1.4)
/payment
OpenFeign works, we’l creat he project “sq-ch1-ex” and impleOpenFeigntohcal endpoinapt “sq-ch1-paymenxpts” ose
We’l define an interfac wher we declar the methods that consume REST endpoints. The only thing we ned to do is an otae thes methods to defin the path,
the HTTP method, and evntualy parmetrs, headrs, and the body of the rquest.
Theintersingthing isthatwedon’tnedtoimplementhe methodsourselv. You
define with the interfac methods based on the an otai ns, and Spring knows to
implementhem.WerelyaginonthexclntmagicofSpring.
Figure 1.5 shows the clas design for the ap licaton we’l build that consumes a
RESTendpoint.
To implement the REST endpoint call using OpenFeign, we
only need to define an interface and use annotations to
instruct OpenFeign on how to implement this interface.
The app
POST
/payment
Payment service
POST /payment
PaymentsController
@PostMapping(" /payment" )
payment()
Uses
PaymentsProxy
<<interface>>
Calls
createPayment()
Implements
OpenFeign client
implementation
Like any other bean, the OpenFeign
client implementation can be injected
as a dependency where it’s needed.
OpenFeign implements the given
interface and defines a bean of the
implementation in the Spring context.
Figure 11.5 Wit h OpenFeign , you only need t o define an int erface (a cont ract ) and t ell OpenFeign
where to find this cont ract t o implement it . OpenFeign implement s the int erface and provides t he
implement at ion as a bean in t he Spring cont ext based on configurat ions you define wit h annot ations.
You can inject t he bean from t he Spring cont ext anywhere you need it in your app.
Calling REST endpoints using Spring Cloud OpenFeign
251
Youpr om.xmnfile dtos efinthe depndenshacy, ownbthy ne coxtdsne ip et:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Once you have the depndency in place, you can creat he proxy interfac (s presented in figure 1.5) In
OpenFeign terminol gy, we also name this interfac the
OpenFeign client.
OpenFeign implements his nterfac, so you don’t have to bother
writnhg ceodthe aclts endpoinYto. uonly edtoufewas an otai ntos el
OpenFeign how to send the rquest. The fol wing listng shows you how msi ple the
OpenFeign .
defintionoftherquestiwith
Listing 11.2
Declaring an OpenFeign client interface
@FeignClient(name = "payments",
url = "${name.service.url}")
public interface PaymentsProxy {
We use the @FeignClient annotation to configure
the REST client. A minimal configuration defines a
name and the endpoint base URI.
We specify the endpoint’s
@PostMapping("/payment")
path and HTTP method.
Payment createPayment(
@RequestHeader String requestId,
We define the request
@RequestBody Payment payment);
headers and body.
}
The first thing to do is an otae the interfac with the
te l
OpenFeignhit oasprovidane implementaionfothr cois nWetrac. htoavesign
a name to the proxy using the
OpenFeign internaly ues. The name uniquely identifes he clint in your ap . The
@FeignClient an otai n is also wher we specify the base URI of the request. You
candefinethebasURIastringusingthe
NOTE
@FeignClient an otai n to
name atribute of the
@FeignClient an otai n, which
url atributeof
@FeignClient .
Ensure oy u always tore URIs and other details hat might difer om
onenvironmentoanotherinthepropertisflandnevrhardcodethem
intheap .
You can define a property in the project’s “ap licaton.propertis” file and ref it
from the source ode using the fol wing syntax:
tice,youdon’tnedtorec mpilethecodewhenyouwantoruntheap indifernt
environments.
Each method you declar in the interfac repsnts a REST endpoint cal. You
use the same an otai ns you learned in chapter 10 for the controle’s actions to
exposeRESTendpoints:
${property_name} . Using this prac-
252
CHAPTER 11
To specify the path and HTTP method:
Mapping ,andso n
Tospecifyarquestheadr:
Tospecifytherquestbody:
Consuming REST endpoints
@GetMapping , @PostMapping , @Put@RequestHeader
@RequestBody
I find this apect of reusing the an otai n benefical. Here, by “reusing the an otation,” I mean
OpenFeign use the same an otai ns we use when we define the ndpoints. You don’t have to learn something specif to
OpenFeign . Just use the same
an otai nfoas expr osinthg RESe Tendponi ts he SprinMVC
g controclaes.
OpenFeign neds to know wher to find the interfacs defin g the client contracs. We use the
@EnableFeignClients an otai n on a configuraton clas to
OpenFeign functionality nd tel
OpenFeign wher to search for the clint
enable the
contracs. In the fol wing listng, you find the project’s onfiguration clas wher we
enablethe
OpenFeign cleints.
Listing 11.3
Enabling t he OpenFeign client s in t he configurat ion class
@Configuration
@EnableFeignClients(
basePackages = "com.example.proxy")
public class ProjectConfig {
}
oYnacuowthinejc
Onec you ne abel
@FeignClientwedhncIms u,5iSpta.dsenr g ne otra upothgrywidviue th
bnaei antosrf mce oc nwhsti xe enoy aubictwhrsenaylx ,ohdtsiua
dThho.re f ol we shintl oghtwniyc uesjatl or el
Listing 11.4
We enable the OpenFeign clients and
tell the OpenFeign dependency where
to search for the proxy contracts.
OpenFeignthniecl rouynihtgdcefar 2.1instldg
OpenFeign , ti knows to mi peml ent the insfacert an oedta with
FeignClient .
Inject ing and using t he OpenFeign client
@RestController
public class PaymentsController {
private final PaymentsProxy paymentsProxy;
public PaymentsController(PaymentsProxy paymentsProxy) {
this.paymentsProxy = paymentsProxy;
}
@PostMapping("/payment")
public Payment createPayment(
@RequestBody Payment payment
) {
String requestId = UUID.randomUUID().toString();
return paymentsProxy.createPayment(requestId, payment);
}
}
Calling REST endpoints using RestTemplate
253
Now star both projects (the payments servic and this section’s ap ) and cal the
ap ’s /payment endpoint using cURL or Postman. Using cURL, the request commandlo ksthefol wingsnip et:
curl -X POST -H 'content-type:application/json' -d '{"amount":1000}'
➥ http://localhost:9090/payment
Inthcoe nsowhle yeor uexc tdhcUe RLcommandyo, ufin’l d respa onpase, rsentedinthenextsnip et:
{"id":"1c518ead-2477-410f-82f3-54533b4058ff","amount":1000.0}
In the payment servic’ onsole, y u find the log proving tha the ap coretly snt
therquestohepaymentservic:
Received request with ID 1c518ead-2477-410f-82f3-54533b4058ff ;Payment
➥ Amount: 1000.0
11.2 Calling REST endpoints using RestTemplate
In this ecton, we agin implement he ap tha cls the /payment endpoint of the
paymentsrvice,buthistmeweuseadifrentap roach:
I don’t want you to c nclude that
to slep not becaus it’ not working properly or becaus it’ not a go d to l. But as
ap s evold, we straed to ned more capbiltes. Developers wanted to be able to
benfit rom difernt hings that ren’t esya to implement with
asthefol wing:
RestTemplate .
RestTemplate has ny problems. It i beng put
RestTemplate , such
Calingthendpointsbothsynchronouslyandasynchronously
Writnglescodeandtreaingfewerxcptions(eliminateboilerpatcode)
Retrying cal excutions and implementing falbck operations (logic performedwhentheap can’texcuaspecifRESTcalfornyreason)
Inothwoer rds, evlopers tof moge thre inogs uot hf be orathx er animplement hem wherv posible. Remember that reusing code and avoidng boilerpat
code is one of the primary purpose of rameworks, a discued in chpa ter 1. You’l
gethechance toc mparethexampleswe implementinsections1.and1.2na d
observthausing
NOTE Here is a go d leson I learned in my exprince: When something is
caled “deprcatd” or “elgacy,” it doesn’t necsarily mean you shouldn’t
learn it. Sometimes, deprcatd technol gies ar stil used in projects many
years after being declar deprcatd, including
Sprni gSecurityOAuthproject.
Thestpfordefin gthecalrsfo ws(figure1.6):
OpenFeign ismucheasirthanusing
RestTemplate .
RestTemplate
and the
254
CHAPTER 11
1
2
3
Consuming REST endpoints
Define the HTTP heda rs by creating and configurng an
instance.
Creat an
HttpEntity instance that repsnts he rquest dat (headrs and
body).
SendthHTTP
e ucal sinthg e
HttpHeaders
exchange()methodandthge HTTPresponse.
STEP 1
STEP 2
STEP 3
Defi ne the HTTP headers
by creating and confi guring
an HttpHeaders object instance.
Defi ne the HTTP request data
by defi ning an HttpEntity
object instance.
Use the exchange() method to send
the HTTP request.
HttpHeaders headers = new HttpHeaders();
headers.add("requestId", "ID Value");
HttpEntity<Payment> httpEntity =
new HttpEntity<>(payment, headers);
ResponseEntity<Payment> response =
rest.exchange(uri,
HttpMethod.POST,
httpEntity,
Payment.class);
Figure 11.6 To define a more complex HTTP request , you have t o use t he HttpHeaders class t o define t he
headers, t hen t he HttpEntity class t o represent t he full request dat a. Once you defined t he dat a on t he
request, you call t he exchange() method t o send it.
We star implementing this example in the project “sq-ch1-ex2.” In listng 1.5, you
find the definton of the proxy clas. Observ how the
defines the headr by creating an
headr “equestId” to this nstance using the
Entity instance based on the headrs and the body (recivd by the method as a
parmetr). The method then sends the HTTP request using
exchange() method. The
HTTPmethodfo, l wedbthy e
thetypx ectdforthersponsebody.
Listing 11.5
createPayment() method
HttpHeaders instance and ad ing the ned
add() method. It hen creats
HttpRestTemplate ’s
exchange() method’s parmetrs are the URI and the
HttpEntityinstan(hce at oldths requdest an) d
The app’s PaymentsProxy calling t he / payment endpoint
@Component
public class PaymentsProxy {
private final RestTemplate rest;
@Value("${name.service.url}")
private String paymentsServiceUrl;
We take the URL to the payment
service from the properties file.
public PaymentsProxy(RestTemplate rest) {
this.rest = rest;
}
public Payment createPayment(Payment payment) {
We inject the RestTemplate from the
Spring context using constructor DI.
Calling REST endpoints using RestTemplate
255
String uri = paymentsServiceUrl + "/payment";
HttpHeaders headers = new HttpHeaders();
headers.add("requestId",
UUID.randomUUID().toString());
HttpEntity<Payment> httpEntity =
new HttpEntity<>(payment, headers);
ResponseEntity<Payment> response =
rest.exchange(uri,
HttpMethod.POST,
httpEntity,
Payment.class);
return response.getBody();
We build the HttpHeaders object to
define the HTTP request headers.
We build the HttpEntity object
to define the request data.
We send the HTTP request
and retrieve the data on
the HTTP response.
We return the HTTP response body.
}
}
We defin a simple ndpoint o cal this mplementaion, the same as we di for the
smal endpoint we caled in section 1. The next lisng shows you how to define
thecontrolecas.
Listing 11.6
Defining a cont roller class t o t est t he implement at ion
@RestController
public class PaymentsController {
private final PaymentsProxy paymentsProxy;
public PaymentsController(PaymentsProxy paymentsProxy) {
this.paymentsProxy = paymentsProxy;
}
We define a controller action and
map it to the /payment path.
@PostMapping("/payment")
public Payment createPayment(
@RequestBody Payment payment
We get the payment data as a request body.
) {
return paymentsProxy.createPayment(payment);
}
}
We call the proxy method, which in turn calls the endpoint of the payments
service. We get the response body and return the body to the client.
We run both ap s, the payments ervic (“sq-ch1-payments”) and this ecton’s ap
(“sq-ch1-ex2”),ondiferntports validteourimplementaionworksaexpctd.
Forthisexample,Ik thesameconfigurationfromsection1.p: ort80f he
paymentservicandport90f hisecton’sap .
UsingcURL,youcancaltheap ’sendpoint,asprentedinthenxtsnip et:
curl -X POST -H 'content-type:application/json' -d '{"amount":1000}'
➥ http://localhost:9090/payment
256
CHAPTER 11
Consuming REST endpoints
Inthcoe nsowhle yeor uexc tdhcUe RLcommandyo, ufin’l drespa onpase, rsentedinthenextsnip et:
{
"id":"21149959-d93d-41a4-a0a3-426c6fd8f9e9",
"amount":1000.0
}
In the payment servic’ onsole, y u find the log proving tha the ap coretly snt
thepaymentservicquest:
Received request with ID e02b5c7a-c683-4a77-bd0e-38fe76c145cf ;Payment
➥ Amount: 1000.0
11.3 Calling REST endpoints using WebClient
nI thsecionwe, discu sing
used in dfiernt ap s and is built on a methodol gy we cal reactiv proach. The
reactiv methodol gy is an advnced ap roach, na d I recommend studying it once
youknowthebasiwec lA. go dstarinpg oinrtseadincghpa ters12nd1o3Springf
inAction,6hed.,byCraigWa(lsMan ing,201).
Spring’sdocumentaionrecommendsuing
ommendation for reactiv ap s. If you aren’t writng a reactiv ap , use
insteadLi. anke ythinelsg oftwwefitsare, fol sr mbcase, umit ghcot mplicate
things for others. Cho sing
stronglycoupledtomanki gyourap reactiv.
yoIf udeci not implemenarpctiv u, se
ment the REST client capbiltes. If you implement a reactiv ap , you
shoulduseaproperactivo l:
WebClienttoREScal Tendpoints.
WebClient ,but hat’sonlyavidrecOpenFeign
WebClient to implement the REST endpoint cals is
OpenFeigntoimple-
NOTE
Eventhoughreactivp sare bit eyondthebasic,I’dliketomakesuroy uknow
what using
WebClient lo ks like and how this to l difers from others we have discused os that you can compare the ap roaches. Let me tel about reaciv p s and
thenuse
WebClient tocalthe/paymentendpointweusedanexampleinsections
1.and 1.2
In a nonreactiv p , a thread excuts a busines flow. Multipe task compose a
busines flow, but hes tak re not indepndent. The same thread excuts al the
task composing a flow. Let’s ake n example to observ wher this ap roach might
faceisuandhowwecane hanceit.
Sup ose you implement a banking ap laitcon wher a bank’s client has one or
morcedaitountThs. seytmcomponenyot uimplementcalueshtoe aldebt
of a bank’s client. To ues this functionitayl, other sytem compone ts make a REST
cal to send a unique ID to the user. To calute his value, the flow you implement
includesthefol wingstep(fiure1.7):
WebClienttoais l
WebClient .
Calling REST endpoints using WebClient
1
2
3
4
5
257
Theap recivstheusrID.
It cals difernt servic of the sytm to find out if the user has credits with
otherinstiuons.
Itcalsdiferntesrvicofhesytmtogehedbtforinternalcdits.
thIf ue hsr eaxtsndal ebcailtns, exrnseartlvicofndouthexrnal
debt.
Theap sumsthedbtsandretunsthevaluinanHTTPresponse.
The functionality you implement needs to
first call another service in the system
to find the user details. When it does this,
the app waits for the response before
proceeding to step 3. Any request to another
component is an I/O call, so it takes some time.
The thread executing this call is blocked and
cannot do something else in the meantime.
Another app in the system
initiates the call. To find out
the total debt of a user, it
sends the user ID.
User details system
When executing step 3, the app
again makes an I/O call to get
the user’s internal debt. The
thread is again blocked while
the app performs the call.
User ID
User details
User ID
User ID
Total debt
User’s internal debt
User’s external debt
Credit account system
User details
The app calculates the total
debt and returns the result
in the HTTP response.
External debt system
The app performs a call to an
external system to find out the
user’s external debt.
Figure 11.7 A funct ionalit y scenario for demonst rating the usefulness of a reactive approach. A banking
app needs t o call several ot her apps to calculat e t he t ot al debt of a user. Due t o t hese calls, t he t hread
executing t he request is blocked several t imes while wait ing for I/ O operat ions t o finish.
Thjuarestfpicv osuf nctionbality, udIt esignedthemtoprowhve uer sinag
reactiv p could be helpful. Let’s anlyze thes tps depr. Figure 1.8 presnt
the xcution of the scnario from the thread’s point of view. The ap creats new
258
CHAPTER 11
The app receives the request.
A new thread starts executing
the functionality.
The thread is blocked while
waiting to get the user details
from another app in the system.
Consuming REST endpoints
The thread is blocked while waiting
to get the internal debt details from
another app in the system.
The thread is blocked while
waiting to get the external
debt details from another system.
The thread sums the
results and returns
a response.
Figure 11.8 The execut ion of t he scenario funct ionality from t he thread point of view. The arrow represent s
the t imeline of t he t hread. Some of t he st eps cause det ails t o block t he t hread, which needs t o wait for t he
task to finish before proceeding.
threadfochr equanest, dthis readxcuthes pos nbeoy nThe. the radhas
towafoitsepar finshbefopr ocedintog hne oxt nae dbis lockedtimrvy e
itwaitsforheap toperfomanI/Ocal.
Weobservtwosignifcantisueher:
1
2
The thread is dle while an I/O cal blocks it. nI stead of using the thread, we
alow it o stay nd ocupy the ap ’s memory. We conus me rsources without
gaining any benfit. With such an ap roach, you could hvae case wher the
ap gets10rquest imultaneoulys, but alhe threads areidle simultaneously
whilewaitngfordetailsfromothersytms.
Some of the task don’t depnd on one another. For example, the ap could
excut sep 2 and step 3 at he same time. Ther’s no reason for the ap to
wait for step 2 to end befor excuting step 3. The ap just neds, in the nd,
thersultofbothtocalutehetoaldebt.
Reactive ap s change the idea of having one atomic flow in which one thread excutes al i tsk from the bgin ing to he nd.With recativ p s, we thni k of tsak
inas depndenat, dmultiphe radcns olabotrae c mpfloaet wcomposedof
multipeask.
Instead ofimagin g thisfunctionality s epson atimeline,imagineit as backlog of task and a team of devlopers solving them. With this anlogy, I’l help you
imagine how a reactiv ap works: the devlopers are threads, and the task in the
backlogrethestpofaunctionality.
Two devlopers can implement two difernt task simultaneously if they don’t
depnd on one another. If a devloper gets stuck on a task becaus of an extrnal
Calling REST endpoints using WebClient
259
The tasks that need to be performed
Come on folks! We have three
simultaneous requests!
Hey Ginny, I’ll take step 2 of the fi rst request.
Thread 1
Okay George! I’ll take step 3 of the fi rst request.
I see it doesn’t depend on you!
Thread 2
Guys, I’m blocked waiting for the external credit
list on step 4 of the second request. I’ll leave it
for later and start on step 1 of the third request.
Thread 3
Ginny, the task you left earlier because it was
blocked can be solved now. I’ll continue it!
Thread 4
Figure 11.9 An analogy of the way a reactive app works. A t hread doesn’t t ake a request ’s t asks in order
and wait when it’s blocked. Inst ead, all t asks from all request s are on a backlog. Any available t hread can
work on t asks from any request. This way, independent t asks can be solved in parallel, and the t hreads don’t
st ay idle.
depndency, they can leav it temporaily and work on something els. The same
devloper can get back to the task once it’s not blocked anymore, or another devlopercanfinshsolvingit(fure1.9)
Using this ap roach, you don’t ned one thread per ach request. You can solve
multiprequwiest thfewther adbs ecauths e rads onh’t oaveidsty Whl. en
blockedonacertintask,hethreadleavsitndworksonsomeothertaskhatisn’t
blocked.
Technicaly, n a rectiv ap , we implement a flow by defin g the task nd the
depndenbciestwenthemTh. aprectiv specifatonouferstwoc mponents:
theproducerandthesubscri etoimplementhedpendenciesbtwentask.
A task retuns a producer to aol w othre task to subscri e to it, marking the
depndency they have on the task.A taskuse a ubscri e to ach to a producerof
anothertaskndconsumethatsk’reulonceitnds.
Figure 1.0 shows the discued scenioar implementd in a reactiv ap roach.
Takefawminuteos c mparethisvualwithfigure1.8Insteadofbeingstepona
260
CHAPTER 11
Consuming REST endpoints
Tasks use subscribers to
establish the dependencies
on other tasks.
Producer
TASK A
HTTP request
TASK D
TASK B
Subscriber
subscribes to
Subscriber
Producer
subscribes to
calculates the
total debt
Subscriber
subscribes to
gets user’s
external debt
Subscriber
subscribes to
Producer
gets user’s details
TASK C
Producer
gets user’s
internal debt
Tasks use producers to allow other
tasks to subscribe to them.
Figure 11.10 In a react ive app, t he steps become tasks. Each t ask marks its dependencies on other tasks
and allows ot her t asks t o depend on them. Threads are free to execut e any t ask.
timeline, the task are indepndent of any thread and declar their depndencies.
Multipehreadscnexcuthestak,ndnothreadhastowaitforaskwhenan
I/Ocommunicatonblocksit.Thethadre cnbeginexcutinganothertask.
Moreothaskv, nre odt epndenot nonae othcaner bsime ultaneouex-sly
cutedIn. figuC1retask.0, andD,whichweinre tsialeypn2 din3 thne onreactive design, can now be excutd simultaneously, which helps make the ap more
perfomant.
Forthisdemontsraion,weusetheprojects“q-h1-payments”(hepaymentservice) and “sq-ch1-ex3” (the ap ). We used the payment servic n sections 1. na d
1.2, na d it expose the /payment endpoint acesibl usni g the HTTP POST
methodF.othr secionap’s we, use
paymentservicxpose.
Because
WebClient impose a reactiv ap roach, we ned to ad a depndency
n am e d
WebFlux instead of the standar web depndency. The next code snip et
sh o w s the
WebFlux depndency, which you can ad to your pom.xml file or cho se
wheryoubuildtheprojectusingstar.ping.io:
WebClienttosendrequtoes hendpointhe
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
To cal the REST endpoint, you ned to use a
creat sy i to put i n the Spring contex using the
configuraton clas method, as you learned in chapter 2. The fol wing listng shows
yo u th eap ’sco n figu ra t o n clas .
WebClient instance. The best way to
@Bean an otai n with a
Calling REST endpoints using WebClient
Listing 11.7
261
Adding a WebClient bean t o t he Spring cont ext in t he configurat ion class
@Configuration
public class ProjectConfig {
@Bean
public WebClient webClient() {
return WebClient
.builder()
Creates a WebClient bean and
.build();
adds it in the Spring context
}
}
Listing1.8showstheproxyclas’implementaion,whichuse
endponi t the ap expose. The logic is similar to what you’ve leraned for
Template .YoutakehebasURLfromthepropertisfl;pecifytheHTTPmethod,
headrs, and body; and excut he cal.
quiteasyounderstandwhathey’rdoingafterdingtheirnames.
Listing 11.8
WebClient tocalthe
RestWebClient ’s methods’ names difer, but i’s
Implement ing a proxy class wit h WebClient
@Component
public class PaymentsProxy {
private final WebClient webClient;
@Value("${name.service.url}")
private String url;
We take the base URL
from the properties file.
public PaymentsProxy(WebClient webClient) {
this.webClient = webClient;
}
We specify the HTTP method we
use when making the call.
public Mono<Payment> createPayment(
String requestId,
We specify the URI for the call.
Payment payment) {
return webClient.post()
We add the HTTP header value
.uri(url + "/payment")
We provide the
to the request. You can call the
.header("requestId", requestId)
HTTP request body.
.body(Mono.just(payment), Payment.class) header() method multiple times if
you want to add more headers.
.retrieve()
.bodyToMono(Payment.class);
We get the HTTP
}
We send the HTTP request and
response body.
}
obtain the HTTP response.
Inoudr emonstraionwe, unclas e med
ing 1.8, you find this case, wher the method perfoming the cal doesn’t get the
input directly. Instead, we send a
tha provides the rquest body value. The
depndentonit.
MonoTh. dclasi efnpaes roduIncer. li-st
Mono. This way, we can creat n indepndent sak
WebClient subscri ed to this tak becomes
262
CHAPTER 11
Consuming REST endpoints
Thmee thod alsodoens rtu’ nvalude Iinrctly. seadrtui, nas
anothfuer nctiontoaliysubscri toeTh. wais thy, ape buildths floe wn, obtchy aininthg emontha redb, ubtliny k thg de pendenbcies twenthask roughproducersandconsumers(figu1.)
Monoalo, wing
In a reactive app, we define the tasks
and the dependencies between them.
TASK
TASK
HTTP request
subscribes to
Mono
subscribes to
making an HTTP request
with WebClient
Spring Boot subscribes the HTTP request to the Mono
we return from the controller’s action. This is the
Mono the WebClient functionality returns after
getting the HTTP response.
Mono
obtaining an
HTTP request body
To get the request body, WebClient
subscribes to a task that provides the
request body value.
Figure 11.11 The t asks chain in a react ive app. When building a react ive web app, we define t he t asks and
the dependencies bet ween t hem. The WebFlux functionalit y init iat ing t he HTTP request subscribes t o t he
task we create t hrough t he producer t he cont roller’s act ion ret urns. In our case, this producer is t he one we
get by sending the HTTP request wit h WebClient . For WebClient to make t he request , it subscribes to
another t ask t hat provides t he request body.
Listing1.8 lasohowstheproxymethodthaconsumesa
requestbodyandretunsitowhathe
Toprovethecalworkscoetly,awedi nthischapter’s viousexamples,we
implement a controle clas that use the proxy to expose an endpoint we’l ca to
tes our implementaion’s behavior. The fol wing listng shows the implementaion
ofthecontrolecas.
Listing 11.9
Mono producingtheHTTP
WebFlux functionalitysubscri e.
A cont roller class exposing an endpoint and calling t he proxy
@RestController
public class PaymentsController {
private final PaymentsProxy paymentsProxy;
public PaymentsController(PaymentsProxy paymentsProxy) {
this.paymentsProxy = paymentsProxy;
}
@PostMapping("/payment")
public Mono<Payment> createPayment(
@RequestBody Payment payment
) {
String requestId = UUID.randomUUID().toString();
return paymentsProxy.createPayment(requestId, payment);
}
}
Summary
Youcanthes functionoalitybf thap “sq, -ch1-paymen(ths” pe aymensrvict)
and “sq-ch1-ex3,” by caling the /payment endpoint with cURL or Postman. Using
cURL,therquestcommandlo ksliethefol wingsnip et:
curl -X POST -H 'content-type:application/json' -d '{"amount":1000}'
➥ http://localhost:9090/payment
In the console wher you excutd the cURL command, you’l find a response like
thenextsnip et:
{
"id":"e1e63bc1-ce9c-448e-b7b6-268940ea0fcc",
"amount":1000.0
}
In the payment servic onsoel, you find the log proving that his ection’s ap correctlysndstherquestohepaymentservic:
Received request with ID e1e63bc1-ce9c-448e-b7b6-268940ea0fcc ;Payment
➥ Amount: 1000.0
Summary
In a real-world backend solution, you often find case when a backend ap
nedstocalendpointsexposedbyanotherbackndap .
Springofersmultipesolutionsforimpeml entingtheclintsideofaRESTservice.Threofthemostrelvantsolutionsarefol ws:
– OpenFeign —AsolutionoferdbytheSpringCloudprojecthatsucef ly
simplifes the code you ned to write o cal REST endpoint and ad s everalftureslvantohowweimplementservicoday
– RestTemplate —Asimpleto lusedtocalRESTendpointsinSpringap s
– WebClient —AreactivsolutionforcalingRESTendpointsi aSpringap
You shouldn’t use
RestTemplate in new implementaions. You can cho se
betwen
OpenFeign and
WebClient tocalRESTendpoints.
For an ap fol wing a standar (nonreactiv) ap roach, the best choice is
using
OpenFeign .
WebClient isanexclnto lforanap designedonarecvtip roach.But
befor using it, you hs ould deply undrsetand the ractive p roach and how
toimplementarecivp withSpring.
263
Usingdat
sourceinSpga
This chapter covers
What a data source is
Configuring a data source in a Spring app
Using JdbcTemplate to work with a database
Almost evry ap today neds to store dat i works with, and often ap s use datbase to manage the dat they persit. For many years, relational datbse have
provide ap licatons with a simple and elgant way to store dat you can sucefuly ap lyin many scenarios. Spring ap s, like other ap s, often ned to use datbasetopersitda,ndforthisreaon,younedtolearnhowtoimplementsuch
capbiltesfory urSpingap s.
In this chapter, we discu what dat source is and the mots rigahtforward
waytomakeyourSpringap work witha datbse.That srightforwardwayis the
JdbcTemplate to lthaSpringofers.
Figure 12. showsyourproges inprevious chpa terson learni gtouse Spring
to implement various fundamental capbiltes in a sytem. We have made go d
264
What a data source is
265
You can now implement services
to establish communication between
your Spring apps and clients, such as
mobile apps or web apps running in
a browser.
You are here now! You’ll learn
to implement data persistence
capabilities in your Spring apps.
REST
REST
You learned how the Spring context
and aspects work and how they help
the framework to provide capabilities
you directly plug into your apps.
REST
Establishing communication between
components of the backend
Figure 12.1 You already understand t he essent ial parts you implement wit h Spring in a syst em. In chapt ers
1 t hrough 6, you learned t he fundament als and what makes Spring able t o provide t he capabilit ies you use
in your apps. In chapters 7 through 11, you learned to implement web apps and REST endpoint s t o est ablish
communication between t he system’s component s. You now start your journey in learning the valuable
skills of making your Spring app work with persisted dat a.
proges, and you can now use Sprni g to implement capbiltes n various parts of a
sytem.
12.1 What a data source is
In this ecton, we discu an esntial component your Spring ap neds to aces
datbse:hedatsource.Thedatsource(fig 12.c)soa mponenthamanages
con ections to the srve handling the datbse (the datbse management syem,
alsoknownasDBMS).
DBMSsoiftwwhare oresponsibtoal ywyoutoeficnmatly nage persitd dat (ad , change, retiv) while keping it secur. A DBMS
managesthedatindatbse.Adatbseiprstentcolei nofdta.
NOTE
266
CHAPTER 12
Using data sources in Spring apps
The data source manages the connections.
It provides the app with connections when
it’s requested and makes sure to create
new connections only when it’s necessary.
DBMS
App’s logic
Uses
Data source
Uses
JDBC driver
Connects
A data source uses the JDBCdriver
to connect to the DBMS.
Figure 12.2 The dat a source is a component t hat manages connections to t he database management
syst ems (DBMS). The dat a source uses t he JDBC driver t o get the connections it manages. The dat a source
aims t o improve t he app’s performance by allowing it s logic t o reuse connect ions t o the DBMS and request
new connect ions only when it needs them. The dat a source also makes sure t o close the connect ions when
it releases t hem.
Without an object taking the rsponsiblty of a dat os urce, the ap would ned to
requestanewcon ectionforeachoperationwiththedat.Thisap roachisnotrealistcnaproductionscenariobecauscommunicant gthroughthenetworkf establishing a new con ection for each operation would dramaticly slow down the
ap licaton and causeperfomna ce isue.The dat source makes ure your ap only
requestanewcon ectionwhenitrealynedsit,mprovingtheap ’sperfomance.
When working with any to l relatd to dta persitnce in a relational datbse,
Springexpctsyoutodefineadat source.Forthsireaon,it’smportantwefirstdiscuswheradtasourcefitsntheap ’spersitncelayrndthendemonstraehow
toimplementadpersitncelayrinexamples.
In a Jav ap , the languae’s capbiltes to con ect to a relational datbse is
named Jav Databse Con ecvity (JDBC). JDBC ofers you a way to con ect to a
DBMS to work with a datbse. Howevr, the JDK doesnt’ provide a specif implementaionfowor rkinwig thpa rticuhela nol (sugy chMyas SQL,Postgre, Oracle). The JDK only gives ou the abstrcions for bjects an ap neds to work with a
relational datbse. To gain the implementaion of this abstrcion and enable your
ap toc n ectoarni DBMStechnol gy,ouad aruntimedpendencynamed
theJDBCdrive (fgure12.3)Everytchnol gyvendorpovidestheJDBCdrive you
nedtoad toy urap toenableitoc n ectohatspecifthnol gy. TheJDBC
drive s not something that comes ither fom the JDK or fom a frmework such as
Spring.
What a data source is
267
The app uses JDBCabstractions provided
by the JDK. Interfaces such as Connection,
Statement, and ResultSet of the java.sql package
offered by the JDK are common in apps using
plain JDBCto connect to a database.
JDBC abstractions
from the JDK
App
Uses
Needs to persist data in
a relational database
java.sql.Connection
java.sql.ResultSet
java.sql.Statement
...
DBMS
Implements
Connects
JDBC driver
Implementations specific
to a relational database
technology
However, abstractions are not enough. The app needs the implementations
that enable it to connect to a specific database. A JDBCdriver offers the
implementations for a specific DBMS. For example, if you need your app to
connect to a MySQL database server, you need to add the MySQL JDBCdriver,
which implements the JDBCabstractions provided by the JDK and defines a
way to connect to a MySQL server.
Figure 12.3 When connect ing to a dat abase, a Java app uses JDBC. The JDK provides a set of
abst ract ions, but the app needs a certain implement at ion t hat depends on the relat ional dat abase
technology t he app connects to. A runt ime dependency named JDBC driver offers t hese implement ations.
For each specific technology, such a driver exist s, and t he app needs t he exact driver t hat offers t he
implement at ions for t he server technology it needs t o connect t o.
TheJDBCdrivegsyouawayto btainacon ectiontoheDBMS.Afirstoptionis
tousetheJDBCdrive ctlyandmi plementyourap torequireacon ecoti necah
time it neds to excut a new operation on the persitd dat. You’l often find this
ap roachinfuJav ndamentuals oWhrials. enyoulearnJDBCinfuJav ndamentals
268
CHAPTER 12
Using data sources in Spring apps
tuothrial, exmpgenls uraynclse amed
asprentedinthefol wingcodens ip et:
DriverManagertocage n ection,
Connection con = DriverManager.getConnection(url, username, password);
The
getConnection() methoduse theURL provide as vlueforthefrstiparmeter o identify he datbse your ap neds to aces nd the username andpasword
toauthenticaeheacstohedatbse(figure12.4)Butrequestinganewcon ection and ua thenticang each operation agin and agin for each is a waste of
resourcesandtimeforboththeclintandthedatbse rv.Imagineyougointoa
bar nd ask for a ber; you lo k young, so the barman ask for your ID. This fine,
but it would become tedious if the barman asked you for the ID agin when you
orde thescondandthet irdber(hypotheticaly,of urse).
Connection con = DriverManager.getConnection(url, username, password);
DATABASE
App’s logic
Uses
JDBC DriverManager
When your app uses the
DriverManager directly,
it gets a new connection
every time it needs one.
Connects
Getting connections often
results in more traffic over
the network and multiple
unnecessary authentications
to the database server.
Figure 12.4 Your app can reuse connections to t he database server. If it doesn’t
request new connect ions, t he app becomes less performant by executing unnecessary
operat ions. To achieve t his behavior, t he app needs an object responsible for managing
the connect ions—a dat a source.
Adatsourceobjectaneficntlymanagethecon ectionstominimizethenumber
of un ecsary operations. Instead ofusing the JDBC drivemanager directly, we use
adtsourcetoivandmanagethecon ections(figure12.5)
NOTE
A dat source is an object whoes rponsiblty is to manage the con-
nections to a datbse rve for the ap . It makes ure your ap eficntly
request con ections from the datbse, improving the persitnce layer
o p era tio ns ’p erfo m a n ce .
Using JdbcTemplate to work with persisted data
269
Connection con = DriverManager.getConnection(url, username, password);
DATABASE
App’s logic
Uses
Data source
Uses
.
hgit p/us: b.com/bretwo ldri ge/HikarCP
12.2 Using JdbcTemplate to work with persisted data
Inthisecton,weimplementourfistSpngap thatusedatbse,ndwediscu
the advntages Spring provides for implementing the persitnce layr.Yourap can
udase ot urtoce btaincon ectiontos hde atbservficnButly. ht oweasily canyouwrite code to work with the dat? UsingJDBC clase provide by the JDK
hasnotproventobeacomfortablewaytoworkwithpersitd at.Youhavetowrite
verbose blocks of code vn for the simplest operations. In Jav fundamentals exmples,youmight avesncodelikthapresntedinthenextsnip et:
String sql = "INSERT INTO purchase VALUES (?,?)";
try (PreparedStatement stmt = con.prepareStatement(sql)) {
stmt.setString(1, name);
stmt.setDouble(2, price);
stmt.executeUpdate();
} catch (SQLException e) {
// do something when an exception occurs
}
Suchlena gthby ol ck fodfoe siamr pole perationoadf inag ewrecodtoable!
Andconids therkpIa edthloeingc the
Connects
Figure 12.5 Adding a dat a source t o t he
class design helps t he app spare t he time
for unnecessary operations. The dat a source
manages the connect ions, provides t he app
wit h connect ions when requested, and creat es
new connect ions only when needed.
The data source manages the connections.
It provides the app with connections when
it’s requested and makes sure to create
new connections only when necessary.
For Jav ap s, you have multipe choices for dat source implementaions, but the
most commonly used today is the HikariCP (Hikar con ection po l) dat source.
Thcoe nventionconfiguratonoSpf rinBog oalstc nsidHier kariCPthde faudlt a
source implementaion to , and this what we’l use in the xamples. You can find
oumot abreouthdisoatuhrce :
HikariCPisopensource,andyoucanhelpcontributeoisdevlopment.
JDBC DriverManager
catchbloBuck. Spt rinhg elpusminimize
270
CHAPTER 12
Using data sources in Spring apps
thcoedwewrfosuiterchoperationWis. thSprinapg wes, canuvriose altrnatives
toimplementhpe rsitnlayerc, dthmoe imst portansut chalternatiweves d’l iscus in this chapter and in chapters 13 and 14. In this ecton, wel’ use a to l named
JdbcTemplate thalowt yowotus wirkdthawibse thJDBCsimna plifedashion.
JdbcTemplate is the simplest of the to ls Spring ofers or using a reltional datbase, uanit’s exclncht oicfe smr apl ditas oesnfo’t yrce utouasne oy ther
specifpersitnceframework.
JdbcTemplate isthebstSpringchoicet implement
pa ersitnwhlayerc enyoudonwa’t nyot uapr tohanve oy thder pendenalsoIcy.
consider it an exclnt way to star leni g how to implement he persitnce layr
ofSpringap s.
Todemonsthrae ow
JdbcTemplateuis edwe, im’l plemenat exmpWele. fo’l lowthestp:
1
2
3
Creatcon ectiontoheDBMS.
Codetherposit rylogic.
Cal the reposit ry methods in methods that implement REST endpoints’
a ctio n s.
Youcanfi dthisexampleintheproject“sq-h12-ex.”
For this ap , we have a table “purchase” in a datbse. This table store details
about he products bought from an onli e shop and the price of the purchase. The
columnsof thistablersfo ws(figure12.6):
id —Anauto-incrementi guniquealvuethatlsotakehersponsibltyofthe
primarykeofthetabl
product —Thenameofthepurchasedproduct
price —Thepurchasepric
The purchase table
We use a generated numeric
value for the primary key.
For each purchase we store the
product and the purchase price.
Each row is a purchase record.
Figure 12.6 The purchase t able. Each purchase is stored as a row in t he table. The att ribut es we store for a
purchase are the purchased product and the purchase price. The primary key of t he t able (ID) is a numeric
generated value.
Using JdbcTemplate to work with persisted data
Thbiso examk’s pdles ond’t epndonthrelaiondal tbechas nol yg ucho se.
Youcanuthse amcoe dwie theca nol gyof uchr oHoice. whIevr, adtocho se
certain technol gy for the examples. In this bo k, we’l use H2 (an in-memory
datbse, xclnt for examples, and, as youl’ find in chapter 15, for implementi g
integraiontesa)ndMySQLfr(ane dlightec nol ygoucaneisly toal cy
to prove the xamples work with something other than an in-memory datbse). You
canhotimse plementhxame pwiles thsomoethrlaioendaltbechs nol gy
you pref, like Postgre, Oracle, or MS SQL. In such a case, you wil have to use a
properJDBCdrivefoy ur ntime(asmentionedarlinthischapterndasyou
knowfromfuJav ndamenAltals). soth, SQe Lsynmitaxes ghbtde ifrnbt ewentwo
difernlatonal-dtbechas nolY gies.uh’l toadve pthemtohec nol gy
ofy urchoicefy ucho setouseomethingels.
Your ap use a JDBC drive for the H2 datbse a wel. But for H2,
you don’t have to ad it separtly becaus it comes with the H2 datbse
depndencyouad edinthepom.xmlfie.
NOTE
For this bo k’s examples, I aume you alredy know SQL basic nd you understand
simpleSQLquerysntaxes.IloasumeyouhaveworkedwithJDBCinatlesheoreticalxmpeslbcauseyoulearnthisnJavfundamentals—amandatoryprequisite for learni g Spring. But you might want to refsh your knowledg in this are
befor g ing further. I commend chapter 21 of OCP Oracle Certifd Posnal Jv
SE 1 Developr Complet Study Guide by Jean e Boyarsk and Scot Selikof (Sybex,
20f)otrhJeDBCpartF. oefarsheor nSQL,rIecommendLearniSgQL3r,de .,
byAlanBeaulie (O’ReilyMedia,20).
The rquirements for the ap we implement are simple. We’l devlop a bckend
servic that expose two endpoints. Clients cal one ndpoint o ad a new recod in
the purchase table and a second endpoint to get al the recods from the purchase
table.
When working with a datbse, we implement al the capbiltes relatd to the
persitncelayinr clasewe(byconvention) amerposit.Fgure12.7showsyou
theclasdignoftheap licaton wewantoimplement.
NOTE
Areposit ryaclesponsiblewithworkingwithadtbase.
271
272
CHAPTER 12
Using data sources in Spring apps
PurchaseController is a REST controller. It exposes
two endpoints. The client calls the POST /purchase
endpoint to add a new purchase record and the
GET /purchase endpoint to get all the existing
purchase records from the database.
DATABASE
PurchaseController
PurchaseRepository
Uses
Connects
GET /purchase
POST /purchase
PurchaseRepository uses the JdbcTemplate tool provided
by Spring. JdbcTemplate uses a data source and connects
to the database server through JDBC.
Figure 12.7 A REST controller implement s t wo endpoints. When a client calls t he endpoint s, t he cont roller
delegat es t o a reposit ory object t o use t he database.
We star the implementaion as us al, by ad ing the necsary depndencies. The
nextcodesnip etshowsyouthedepndenciesyounedtoad astheyap earinthe
p ro jec t’sp om .x m lfi e :
<dependency>
We use the same web dependency
<groupId>org.springframework.boot</groupId>
as we did in previous chapters to
<artifactId>spring-boot-starter-web</artifactId>
implement the REST endpoints.
</dependency>
<dependency>
We add the JDBCstarter to get
<groupId>org.springframework.boot</groupId>
all the needed capabilities to
<artifactId>spring-boot-starter-jdbc</artifactId>
work with databases using JDBC.
</dependency>
<dependency>
We add the H2 dependency to get both
<groupId>com.h2database</groupId> an in-memory database for this example
<artifactId>h2</artifactId>
and a JDBCdriver to work with it.
<scope>runtime</scope>
The app only needs the database and the JDBCdriver at
</dependency>
runtime. The app doesn’t need them for compilation. To
instruct Maven we only want these dependencies at runtime,
we add the scope tag with the value “ runtime.”
Even if you don’t have datbse rv for this example, the H2 depndency simulates he datbse. H2 is an exclnt o l we use both for examples and ap licaton
tewhs enwewantoanes p fu’s nctionablity uexclt ditse pendenocy nda tb ase ( w ed isc u a p lica to n t es in c h a p t e r1 5 ) .
Using JdbcTemplate to work with persisted data
273
This is where you should add the
“ schema.sql” file in your Maven project.
Figure 12.8 In the Maven project , you create t he
“ schema.sql” file in the resources folder, where you
can write t he queries t hat define your dat abase
structure. Spring executes t hese queries when t he
app starts.
We ned to ad a tbel hat sore the purchase rcods. In theortical exmples, it’
easy to creat datbse truc re by ad ing a file named “schema.sql” to he Maven
project’s urcesfolder(figu12.8)
In this flie, you can write al the struc ral SQL queris you ned to defni the
datbseruct rYeo. ualsofind evlopenrs amthe sequeris“dat escriptonla guae” (DDL). We’l aso ad such a file n our project and ad the query to creat
thepurchasetbl,presntedinthenextcodesnip et:
CREATE TABLE IF NOT EXISTS purchase (
id INT AUTO_INCREMENT PRIMARY KEY,
product varchar(50) NOT NULL,
price double NOT NULL
);
Using a “schema.qs l” file to define the datbse struc re only works
fothr eoxamrticl pThles. apis roachbesyi caunfsit’e dalowyos u
to focus on the things you learn rather than the definton of the datbse
struc re in a tuorial. But in a real-world example, you wil ned to use a
depndency that also alows you to veiros n your datbse script. I recommend you lo k at Flyway (
www.liquibase.org/
datbse chema versioni g. They ar beyond Spring basic, o we wont’ use
them ni examples in this bo k. But i’s one of the thni gs I recommend you
learnrightaferhefundamentals.
NOTE
hflywtp/ayds: b.org/
). Thes are two highly ap reciatd depndencies for
) and Liquibase (
htp/s:
274
CHAPTER 12
Using data sources in Spring apps
We ned a model clas to define the purchase dat in our ap . nI stances of this cla
maptherowsofthepurchasetblinthedatbse,oachinsta cenedsanID,the
produanct, dthpe atribsc uThtes. ne coxt dsne ip shet owths e
clas:
Purchasemodel
public class Purchase {
private int id;
private String product;
private BigDecimal price;
// Omitted getters and setters
}
You might find it intersing tha the
Decimal . Couldn’t we have defined it as
you to be aware of: in theortical exmples, you often find
values,but inmany real-world examples,using
isn’t he right hing to do. When operating with
lose precison for evn simple arithmetic operations uch as d iton or subtracion.
This efct is cauesd by the way Jav store such values in memory. When you work
withsensitvenformationsuchasprice,youshouldusethe
Don’t wory about he conversion. All the sntial cpabiltes Spring provides know
howtouse
BigDecimal .
NOTE
BigDecimal andnot
To easily gt
also make this object a bean in the Spring contex. The simplest ap roach is to use a
steroypaen otai n(suchas
But ni stead of using
rieswecanuse:
clase, for reposit re, you should use the
instrucSpringtoad abentoisc ntex.Thefol winglistngshowsyoutherpositoryclasdefinton.
double used for decmi al
double or
float fordecimal numbers
double and
float value,s you might
BigDecimal typeinstead.
double or
float .
PurchaseRepository insta ce when we ned it n the controle, we’l
@Component or
@Component , Spnri g provides a focused an otai n for eposit @Repository .Asyoulearnedinchapter3ouse
@Service a)s,youlearnedinchapt3er.
@Service forseicv
@Repository steroype an otai n to
Listing 12.1
Defining t he PurchaseRepository bean
@Repository
public class PurchaseRepository {
Now that
instanceof
thinkng! “Wher is this
Big-
When you want to store a floating-poni t value acurtely and make
suyreoudonlo’t dse cimpal recisonwhenxecutinvargouos perationwis th
thevalus, e
}
Purchase clas price atribute’s type is
double ? Here’s an important hing I want
We use the @Repository stereotype
annotation to add a bean of this class
type to the Spring context.
PurchaseRepository is a bean in the ap licaton contex, we can inject an
JdbcTemplate thatwe’lusetoworkwiththedatbse.Iknowwhatyou’re
JdbcTemplate instance coming from? Who creatd this
Using JdbcTemplate to work with persisted data
275
instance so that we can alredy inject i nto our eposit ry?” In this example, ik n
manyproductionscenarios,we’lbenfitoncemorefomSpringBoot’smagic.When
Spring Boot saw you ad ed the H2 depndency in pom.xml, it automaticly onfigured a dat source and a
JdbcTemplate instance. In this example, we’l use them
directly.
If you use Spring but not Spring Boot, you ned to defni e the
a nd th e
JdbcTemplate bean(youcand themintheSprincgontexusingthe
an otai ni thcoe nfiguratonyocals, ulearnedinchapI2n)t.er scion1I’2l.3,
showyouhowtocustomthize mandfowhr ichsenarioys unedto efinyoe uor wn
dsoat uanrce d
JdbcTemplateinstanThces. foe l winlstg howyos uhowtoinject
the
JdbcTemplate instanceSpringBootc nfiguredfory urap .
Listing 12.2
DataSource bean
@Bean
Inject ing a JdbcTemplate bean t o work wit h persist ed dat a
@Repository
public class PurchaseRepository {
private final JdbcTemplate jdbc;
public PurchaseRepository(
JdbcTemplate jdbc) {
this.jdbc = jdbc;
We use constructor injection to get
the JdbcTemplate instance from the
application context.
}
}
Fni aly, ou have
JdbcTemplate instance, so you can implement he ap ’s requireJdbcTemplate has n
update() method you can use to excut any query for
ments.
dat mutaion:
INSERT , UPDATE or
DELETE . Pas the SQL and the parmetrs i neds,
andtha’sit;le
JdbcTemplate takecr oftherst(obtain gacon ection,creating
SQLException , and so on). The fol wing listng ad s a
a staement, treaing the
storePurchase() method to the
PurchaseRepository clas. The
methoduse
JdbcTemplate toad anewrecodinthepurchasetbl.
Listing 12.3
storePurchase()
Using JdbcTemplate t o add a new record t o a table
@Repository
public class PurchaseRepository {
The method takes a parameter that
represents the data to be stored.
private final JdbcTemplate jdbc;
public PurchaseRepository(JdbcTemplate jdbc) {
this.jdbc = jdbc;
}
public void storePurchase(Purchase purchase) {
String sql =
The query is written as a string,
and question marks (?) replace
the queries’ parameter values.
For the ID, we use NULL because
we configured the DBMSto
generate the value for this
column.
276
CHAPTER 12
Using data sources in Spring apps
"INSERT INTO purchase VALUES (NULL, ?, ?)";
jdbc.update(sql,
purchase.getProduct(),
purchase.getPrice());
}
}
With a couple of lines of code, you can insert, update, or delt recods in tables.
Retrievng dat is no more difcult han this. As for the insert, you write and send a
quToery. dretihv a,mis yoe,uwr’l a ite
howtoransformthedatinto
RowMapper : an object rsponsible for tansforming a row from the
specifobject.Foerxample,ifyouwantogehedatfromthedatbsemodel as
Purchaseoybnujectsi,mod plemena t
toa
Purchase instance(figure12.9)
The JdbcTemplate update() method sends the query to the
database server. The first parameter the method gets is
the query, and the next parameters are the values for the
parameters. These values replace, in the same order, each
question mark in the query.
SELECTquAnery. dtoel
JdbcTemplate
Purchase objects(yourmodelcas),youimplementa
ResultSet into a
RowMapperdtromaefinhwawas e y p ed
DATABASE
JdbcTemplate
RowMapper
DataSource
Requests a connection to send SQL queries to the DBMS
Only requests a new
connection when needed
Gets a connection to send SQL queries to the DBMS
Sends the SELECT query to the DBMS to retrieve data
Gets the data in a ResultSet
For each row in the ResultSet,
calls the RowMapper to map the
row to a Purchase instance
Gets a Purchase instance
for each row
Figure 12.9 JdbcTemplate uses the RowMapper t o change t he ResultSet t o a list of Purchase
inst ances. For each row in the ResultSet , JdbcTemplate calls t he RowMapper t o map t he row t o a
Purchase instance. The diagram presents all t hree steps JdbcTemplate follows to send the SELECT
query: (1) get a DBMS connect ion, (2) send t he query and ret rieve t he result , and (3) map t he result t o
Purchase instances.
Using JdbcTemplate to work with persisted data
277
The fol wing listng shows you how to implement a reposit ry method to get al the
recodsinthepurchasetbl.
Listing 12.4
Using JdbcTemplate t o select records from a dat abase
The method returns the records it retrieves from
the database in a list of Purchase objects.
@Repository
public class PurchaseRepository {
// Omitted code
public List<Purchase> findAllPurchases() {
String sql = "SELECT * FROM purchase";
We implement a RowMapper object
that tells JdbcTemplate how to map a
row in the result set into a Purchase
object. In the lambda expression,
parameter “ r” is the ResultSet (the
data you get from the database),
while parameter “ i” is an int
representing the row number.
RowMapper<Purchase> purchaseRowMapper = (r, i) -> {
We define the Purchase rowObject = new Purchase();
SELECT query rowObject.setId(r.getInt("id"));
to get all the rowObject.setProduct(r.getString("product"));
records from rowObject.setPrice(r.getBigDecimal("price"));
the purchase return rowObject;
table.
};
return jdbc.query(sql, purchaseRowMapper);
}
}
We set the data into a Purchase
instance. JdbcTemplate will use
this logic for each row in the
result set.
We send the SELECT query using the
query method, and we provide the
row mapper object for JdbcTemplate
to know how to transform the data
it gets in Purchase objects.
Once you have the rposit ry methods and you can store na d retiv cords in the
datbse, it’ me to expose thes methods through endpoints. The fol wing listng
showsyouthecontroleimplementaion.
Listing 12.5
Using t he reposit ory object in t he cont roller class
We use constructor dependency injection to get
the repository object from the Spring context.
@RestController
@RequestMapping("/purchase")
public class PurchaseController {
private final PurchaseRepository purchaseRepository;
public PurchaseController(
PurchaseRepository purchaseRepository) {
this.purchaseRepository = purchaseRepository;
}
We implement an
endpoint a client calls
to store a purchase
record in the database.
We use the repository
storePurchase()
method to persist the
data the controller’s
action gets from the
HTTP request body.
@PostMapping
public void storePurchase(@RequestBody Purchase purchase) {
purchaseRepository.storePurchase(purchase);
}
278
CHAPTER 12
Using data sources in Spring apps
@GetMapping
public List<Purchase> findPurchases() {
return purchaseRepository.findAllPurchases();
}
}
We implement an endpoint the
client calls to get all the records
from the purchase table. The
controller’s action uses the
repository’s method to get the
data from the database and
returns the data to the client
in the HTTP response body.
If you run the ap licaton now, you can tes the two endpoints using Postman or
cURL.
To da a new recod in the purchase table, cal the /purchase path with HTTP
POST,asprentedinthenxtsnip et:
curl -XPOST 'http://localhost:8080/purchase' \
-H 'Content-Type: application/json' \
-d '{
"product" : "Spring Security in Action",
"price" : 25.2
}'
You can then cal the HTTP GET /purchase endpoint to prove the ap stored the
purchase recod coretly. The next snip et shows the cURL command for the
request:
curl 'http://localhost:8080/purchase'
The HTTP response body of the request is a list of al the purchase recods in the
datbse,prntedinthenxtsnip et:
[
{
"id": 1,
"product": "Spring Security in Action",
"price": 25.2
}
]
12.3 Customizing the configuration of the data source
In this ecton, you’l earn how to customize the dat source tha
to work with the datbse. The H2 datbse we used in section 12. is exclnt for
examples andtuorialsnd to gestard withimplementi g thepersitncelayrfo
an ap . In produocti n ap s, howevr, you ned more than an in-memory datbse,
andoftenyounedtoc nfiguethr edatsourceaswel.
Todiscu sinDBMS
ag inworeal rld–typscenariowes, ch’l anthge xampwele
implementd in section 12. to use a MySQL serv. You’l observ the logic in the
example doesn’t change, and changin the dat os urce to point o a difernt datbasein’tricky.Thesarthestpwe’lfo w:
JdbcTemplate use
Customizing the configuration of the data source
1
2
In section 12.3, we’l ad a MySQL JDBC drive and configure a dat source
using the “ap licaton.propertis” fl to point o a MySQL datbse. We’l sti
letSpringBootdefinethe
propertiswedefine.
Insection12.3,we’lchangetheproject defineacustom
and iscuwhenos methinglikethisned inreal-worldscenarios.
279
DataSource beani theSpringcontexbasdonthe
DataSource bean
12.3.1 Defining the data source in the application properties file
In this section, we’l con ect our ap licaton to a MySQL DBMS. Production-reda y
ap licatonsuextrnaldtbaserv,ohavingthisklwilhelpyou.
Thpe rofjecthr sectiond’s emonstraion“sqi -chyoIf12-ex.”uwantorunthe
exampyleourse(lfwhichrIecommendy)oun’l edtoinstalMySQLservandcreate datbseyou’lcon ecto.Y ucanalsodapthexampletouseanalternative
datbsechnol gyaswel(suchasPostgre Oracle)ifyouwish.
Wefol wtwosimplest forpeformingthistransformation:
Change the project depndencies to exclude H2 and ad the adequate JDBC
d rive .
Adochtndepa“nhtoicewafdlnrbtpes.aior p”seit
1
2
.elif
For step 1, in the pom.xml fie, xcul de the H2 depndency. If you use MySQL you
ned to ad the MySQL JDBC drive. The project now neds to have the depndencies,aprentdinthenxtsnip et:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
We add the MySQL JDBC
driver as a runtime
dependency.
For step 2, the “ap ilcaton.propertis” fl should lo k lie the fol wing code snippet. We ad the
spring.datasource.url property to define the datbse locati n,
a nd th e
spring.datasource.username and
spring.datasource.password propertis
todefni ethecrdentialsheap nedstoauthenticae ndgetcon ectionsfromthe
DBMS. Additonaly, we ned to use the
spring.datasource.initialization-mode
property with the value “always” to instruc Spring Boot to use the “schema.sql” file
and creat he purchase tble. You don’t need to use this property with H2. For H2,
Sprni gBootrunsbydefautlhequerisnthe“schema.sql”fie,thisflext:
280
CHAPTER 12
Using data sources in Spring apps
We configure the URL that defines
the location to the database.
spring.datasource.url=jdbc:mysql://localhost/spring_quickly?
useLegacyDatetimeCode=false&serverTimezone=UTC
We configure the credentials
spring.datasource.username=<dbms username>
spring.datasource.password=<dbms password>
spring.datasource.initialization-mode=always
NOTE
to authenticate and get
connections from the DBMS.
We set the initialization mode to
“ always” to instruct Spring Boot to run
the queries in the “ schema.sql” file.
Storing secrt (uchas paswords) inthepropertisfl not ago d
practie in production-ready ap licatons. Such private details are stored in
secrvaut lWe. wond’t iscuervta inls thbis o bk ecauths ui bjeisct
way beond fundamentals. But I want you to be aware that defin g the paswordsinthiswayisonlyforexamples andtuorials.
With thes couple of changes, the ap licaton now use the MySQL datbse. Sprni g
Boot knows to creat he
you provide in the “ap licaton.propertis” file. You can star the ap and tes the
endpointslikeyoudi nsection12.
To da a new recod in the purchase table, cal the /purchase path with HTTP
POST,asprentedinthenxtsnip et:
DataSource bean using the
curl -XPOST 'http://localhost:8080/purchase' \
-H 'Content-Type: application/json' \
-d '{
"product" : "Spring Security in Action",
"price" : 25.2
}'
Youcanthenthcal HTTP
e GET/purchenas dpointoprothev ap storedthpe urchasercodcoretly.Thenxtsnip etshowsthecURLcommandforthequest:
curl 'http://localhost:8080/purchase'
The HTTP response body of the request is a list of al the purchase recods in the
datbse,prntedinthenxtsnip et:
[
{
"id": 1,
"product": "Spring Security in Action",
"price": 25.2
}
]
12.3.2 Using a custom DataSource bean
Spring Boot knows how to use a
details n the “ap licaton.propertis” fle. Sometimes this enough, and as us al, I
recommendyougowiththesimplestoutionthatsolvey urpoblems.Butinother
DataSource bean if you provide the con ection
spring.datasource propertis
Customizing the configuration of the data source
case, you can’t rely on Spring Boot o creat your
younedtodefinethebanyourself.Somescnariosnwhichyounedtodefinthe
b ea n yo u rse lf a o w s :
281
DataSource bean. In such a sce,
You ned to use a specif
youcanonlygetaruntime.
Your ap con ects o more than one datbse, o you have to creat multipe
datsourcesand istnguisht emuins gqualifers.
You hvea to congfiure spifec parmetrs of the
conditons your ap has only at runtime. For example, depnding on the nvironment wher you star he ap , you want o have more o fewer con ections
inthecon ectionpo lforpeformanceoptimizatons.
Yourap useSpringframeworkbutnotSprni gBoot.
DataSource implementaion based on a conditon
DataSource object in certain
Don’t wory! The
DataSource is just a bean you ad to the Spring contex like any
other bean. Instead of leting Spring Boot cho se the implementaion for you and
configuthre
DataSource objecty,oudefinmeae thodan otaedwith
figuraton clas ( you learned in chapter 3) and ad the object o the contex yourself.Thisway,ouhavefulcontrol vertheobject’sraion.
Wech’l anexmg p“sqle -cht12o-ex”definbaenfothr de soat uinrce stadof
leting Spring Boot creat it from the propertis file. You find thes changes in the
pro“sqject -hWe12-ex3.” coaret’nl figuratonafile d efinmeae thodan otaed
with
@Bean ,whichretunsthe
DataSource instancewead toheSpringcontex.The
next listngshowstheconfiguratonclasndthedfintionofthemethodan otaed
with
@Bean .
Listing 12.6
@Bean incoa n-
Defining a DataSource bean for your project
We annotate the method with @Bean to instruct
Spring to add the returned value to its context.
@Configuration
public class ProjectConfig {
@Value("${custom.datasource.url}")
private String datasourceUrl;
@Value("${custom.datasource.username}")
private String datasourceUsername;
The connection details are configurable,
so it’s a good idea to continue defining
them outside of the source code. In this
example, we keep them in the
“ application.properties” file.
@Value("${custom.datasource.password}")
private String datasourcePassword;
@Bean
public DataSource dataSource() {
HikariDataSource dataSource =
new HikariDataSource();
The method returns a DataSource object. If
Spring Boot finds a DataSource already exists in
the Spring context it doesn’t configure one.
We’ll use HikariCP as the data source implementation
for this example. However, when you define the bean
yourself, you can choose other implementations if
your project requires something else.
282
CHAPTER 12
Using data sources in Spring apps
dataSource.setJdbcUrl(datasourceUrl);
dataSource.setUsername(datasourceUsername);
dataSource.setPassword(datasourcePassword);
dataSource.setConnectionTimeout(1000);
return dataSource;
}
}
We return the
DataSource instance,
and Spring adds it to
its context.
We set the connection
parameters on the data source.
You can configure other properties as
well (eventually in certain conditions). In
this case, I use the connection timeout
(how much time the data source waits
for a connection before considering it
can’t get one) as an example.
Donfo’t rgec nfiguvalre fosthr pe ropeyrotis uinuject sinthg e
tion. In the “ap licaton.propertis” file thes propertis should lo k like the next
codesnip et.Ihaveintenionalyusedtheword“custom”intheirnametosre that
we chose thes names, and they’r not Spring Boot propertis. You can give thes
propertisanyname:
custom.datasource.url=jdbc:mysql://localhost/spring_quickly?
useLegacyDatetimeCode=false&serverTimezone=UTC
custom.datasource.username=root
custom.datasource.password=
Youcan owasntr dptes ro“sjqect -h12Th-ex3.” resuhlt ouldbthe samfoase r
theprvioustwoprojectsinthisc apter.
To da a new recod in the purchase table, cal the /purchase path with HTTP
POST,asprentedinthenxtsnip et:
curl -XPOST 'http://localhost:8080/purchase' \
-H 'Content-Type: application/json' \
-d '{
"product" : "Spring Security in Action",
"price" : 25.2
}'
You can then cal the HTTP GET /purchase endpoint to prove the ap stored the
purchase recod coretly. The next snip et shows the cURL command for the
request:
curl 'http://localhost:8080/purchase'
The HTTP response body of the request is a list of al the purchase recods in the
datbse,prntedinthenxtsnip et:
[
{
"id": 1,
"product": "Spring Security in Action",
"price": 25.2
}
]
@Valuean ota-
Summary
NOTE
283
Ifyoudi n’tcleanupthepurchtsaeblndusethseamde atbse
fortheproject“sq-h12-ex,”thersultwouldcontianthercodsyouad ed
previously.
Summary
ForavJp licaton,theJavDevelopmentKit(JDK)providesabtrcionsof
the objects he ap neds to con ect o a reltional datbse. The ap always
nedtos ad rua ntimde pendenthcy pa rovidthes implementaionos thf es
abstrcions.WenamethisdepndencytheJDBCdrive.
Adatsourceisanobjectmanagi thecon ectionstoadtbaserv.Without a dat source, the ap would request con ections to often, afecting its
perfomance.
By default, Spring Boot configures a dat source implementaion named
HikariCP, which use a con ection po l to optimize the way our ap use the
con ection to the datbse. You can use a difernt dat source implementationifthelpsyourap .
JdbcTemplate isaSprngto lthatsimplifesthecodeyouwriteoacsr-l
JdbcTemplate object depnds on a dat
tional datbse using JDBC. The
sourceto n ectohedatbserv.
Tosendaquerythatmutaesdinatble,you sethe
JdbcTemplate object’s
update() method. To send
SELECT queris to retiv dat, you use one of the
JdbcTemplate ’s query() methods. You’l most ofnte ned to use such operationsforchanginoretivngpersitd at.
TocustomizethedatsourceyourSpringBootap licatonuse,youconfigure
java.sql.DataSource . fI you declar bean of this
a custom bean of the type
typeinSpring’scontex,Sprni gBootwiluseitnsteadofc nfigurngadefult
onYoe. u thse amape roachyoif unedcua stom
JdbcTemplateobjecWet.
generaly use the Spring Boot–provide defaults, but specif case ometimes
nedcustomconfiguratonsorimpeml entaionsforvai usoptimizatons.
Youcancreatmultipedatsourceobjects,ahwiththeirown
JdbcTemplate
objectasoidfyouwantyouapr toc n ectomultipedatbse.Insuch
a scenario, you’d ned to use the
@Qualifier an otai n to distnguish
betwen objects of the same tpy e in the ap lciaton contex (as you learned in
ch a p ter s 4 an d 5 ).
Usingtrasco
inSprgas
This chapter covers
What a transaction is
How Spring manages transactions
Using transactions in a Spring app
One ofthe mostimportanthingswetake intoc nsideratonwhenmanagingdat
istokepacurteda.Wedon’twantspecifxutionscenariost endupwith
wrong or inconsitent dat. Let me give you an example. Sup ose you implement
an ap licaton used to share money—an elctronic walet. In thsi ap lictaon, a
user has counts wher they store their money. You implement a functionality o
alowausetor ansfermonefryomoneacountoanotheCor. nsiderngsaimplisticmplementaionfor urexample,thismpliestwostep(figure13.):
1
2
Withdrawmoneyfromthesourceaount.
Depositmoneyintohedstinatonacount.
Both thes step are operations tha change dat (mutable dat operations), and
bothoperationsnedtobesucef ltoexcut hemoneytransfercotly.But
what if the scond step encounters a problem and can’t complet? If the first nished,butsep2couldn’tcomplet,hedatbecomesinconsiten.
284
Using transactions in Spring apps
285
Before the money transfer operation
John
Jane
John wants to transfer $100 to Jane.
Before transferring the money, John
owns $1,000 and Jane owns $500.
Owns $1,000
Owns $500
Step 1: Withdraw $100 from John’s account.
$100
Jane
John
Owns $900
The money transfer operation has two steps.
In the first step, the money is withdrawn from
John’s account. After the execution of the first
step, John owns $900. Jane didn’t get the
money yet, so she still owns $500.
Owns $500
Step 2: Deposit $100 into Jane’s account.
$100
John
Owns $900
In the second step, the $100 is added
to Jane’s account. John has $900, and
Jane has $600.
Jane
Owns $600
Figure 13.1 An example of a use case. When t ransferring money from one account t o another
account, the app execut es two operations: it subt ract s t he t ransferred money from t he first account
and adds it t o t he second account. We’ll implement this use case, and we need t o make sure it s
execution won’t generate inconsistencies in dat a.
Say John sends $10 to Jane. John had $1,0 in his acounts prio to making the
transfer, while Jane had $50. After the transfer complets, we expct that John’s
acount wil hold $10 les (that is $1,0 – $10 = $90), while Jane wil get the $10.
Janeshouldhave$50+1=6.
286
CHAPTER 13
Using transactions in Spring apps
If the scond step fails, we end up in a situaon wher the money has ben taken
from John’s acount, but Jane nevr got it. John wil have $90 while Jane stli has
$50.Wherdi the$10go?Figure13.2ilustraehisbehavior.
Before the money transfer operation
John
Jane
John wants to transfer $100 to Jane.
Before transferring the money, John
owns $1,000 and Jane owns $500.
Owns $1,000
Owns $500
Step 1: Withdraw $100 from John’s account.
$100
Jane
John
Owns $900
The money transfer operation has two steps.
In the first step, the money is withdrawn from
John’s account. After the execution of the first
step, John owns $900. Jane didn’t get the
money yet, so she still owns $500.
Owns $500
Step 2: Deposit $100 into Jane’s account fails.
$100
John
Owns $900
The app withdraws $100 from John’s
account but didn’t add it to Jane’s
account. The $100 is now lost.
Jane
Owns $600
Figure 13.2 If one of t he steps of a use case fails, dat a becomes inconsistent . For the money t ransfer
example, if t he operat ion t hat subt racts t he money from t he first account s succeeds, but t he operation
that adds it to t he dest ination account fails, money is lost.
Transactions
To avoid such scenarios in which dat becomes inconsitent, we ned to make sure
either both step coretly excut or neithr of them do. Transacoti ns ofer us the
posibltyoimplementmultipeoperationsthateihercotlyxuealornone.
13.1 Transactions
Inthisecton,wediscu transcio.Atransctionisadefinedstofmutableoperations(operationsthatchangedat)hatcneithercotlyexcuthemaltogehr
or not a l. We ref to this a atomicty. Transactions are sential n ap s becaus
they nsure the dat remains consitent if any step of the use ca fils when the ap
alredcyhanged atLe. t’asginconsid(earmplifedt)ransfmoer nefyunctionality
consitngoftwotsep:
1
2
Withdrawmoneyfromthesourceaount.
Depositmoneyintohedstinatonacount.
We can tsar tansction befor step 1 and close the transction after sp 2 (figure
13.) In such a case, if both step sucef ly excut, when the transaction ends
(after step 2), the ap persit the changes made by both step. We also say, in this
case, that the transction “commits.” The “commit” operation hap ens when the
transction ends and al the step are sucef ly excutd, so the ap persit the
datchanges.
COMMIT
The sucef l end of a transction when the ap store al the
changesmadebythetransaction'smutableoperation.s
If step 1 excuts without a problem, but sep 2 fails or any reason, the ap revts
thechangestp1made.Thisoperationisnma edrolback.
ROLLBACK
dat to the way it lo ked at the begin ing of the transction to avoid dat
inconsitencies.
The transction ends with rolback when the ap resto the
287
288
CHAPTER 13
Using transactions in Spring apps
Before the money transfer operation
John
Jane
John wants to transfer $100 to Jane.
Before transferring the money, John
owns $1,000 and Jane owns $500.
Owns $1,000
Owns $500
The transaction star ts here.
Step 1: Withdraw $100 from John’s account.
$100
Jane
John
Before executing this step, the app starts
a transaction. Using the transaction, the app
makes sure that if any problem occurs during
the step’s execution, the data is restored to
how it was when the transaction began.
Owns $900
Owns $500
Step 2: Deposit $100 into Jane’s account fails.
John
Owns $1,000
$100
Jane
If one of the steps fail, the app reverts
the data to how it looked like at the
beginning of the transaction. The money
transfer doesn’t work, but at least John
doesn’t lose his money.
Owns $500
The transaction rolls back here.
Figure 13.3 A t ransaction solves possible inconsist encies t hat could appear if any of t he steps of a use case
fail. With a t ransaction, if any of t he st eps fail, the dat a is revert ed t o how it was at t he transact ion st art .
How transactions work in Spring
289
13.2 How transactions work in Spring
Befoshre owinyog uhowtouranse ctionis youSpr inapg dlet’s, icuhs owtransactions work in Spring and the capbiltes he framework ofers you for implementing transctionla code. In fact, a Spring AOP aspect lies behind the scens of a
transaction.(Wediscuedhowaspectworkinchapter6.)
An aspect is a peic of code that intercps pecif methods’ excution in a way
tha you define. In most cae today, we use an otia ns to mark the methods whose
excution anaspect shouldintercp and alter.For Spring transctions, things aren’t
difernt.Tomarmeka thodwewantSpringtowrapintra saction,weusean notaion named
@Transactional . Behind the scnes, Spring configures an aspect (you
don’t implement his apect yourself; Spring provides it) and ap lies the transaction
logicf rtheoperationsexcutdbythamethod(figure13.4)
Something (e.g., a controller action) calls
the service method. Because the method
is annotated with @Transactional, Spring
configures an aspect that intercepts the call.
Controller
The @Transactional annotation is what
tells the Spring transaction aspect to
intercept this method.
Spring transaction aspect
Service
try {
// start transaction
@PostMapping
public void transferMoney() {
service.transferMoney();
}
// call intercepted method
// commit transaction
} catch (RuntimeException e) {
// rollback transaction
}
This is a simplistic representation of the
Spring transaction aspect logic. By default,
if the intercepted method throws any runtime
exception, the aspect rolls back the transaction.
If the intercepted method didn’t throw a
runtime exception, the transaction is committed.
@Transactional
public void transferMoney() {
// 1. withdraw money from the source account
// 2. deposit money in the destination account
}
Because the whole method call is wrapped in
the transaction, both steps are now in the
transaction. If step 1 succeeds but step 2 throws
a runtime exception, then the Spring transaction
aspect will revert the changes made by step 1 with
the transaction rollback operation.
Figure 13.4 When you use t he @Transactional annot ation wit h a method, an aspect configured by Spring
int ercept s the met hod call and applies t he transact ion logic for that call. The app doesn’t persist t he changes
the method makes if t he met hod t hrows a runtime except ion.
Springknowstor lbacktrnsactionifthemethodthrowsaruntimexcption.But
I’d lkie to emphsiaze the word “throws.” When I teach Spring in clas, tudents often
understandtheni’sa ought soat moe perationi sdthe
throwarsuntimexcption.Buthisnotenough!Thetransctionalmethodshould
throwthexcptionfurthsoer that spe knct owshit ouldrolbtahck e angIfes.
transferMoney()method
290
CHAPTER 13
Controller
@PostMapping
public void transferMoney() {
service.transferMoney();
}
Using transactions in Spring apps
Spring transaction aspect
Service
try {
// start transaction
@Transactional
public void transferMoney() {
try {
// 1. withdraw money from the source account
// 2. deposit money in the destination account
} catch (RuntimeException e) {
// do something when the exception occurs
}
}
// call intercepted method
// commit transaction
} catch (RuntimeException e) {
// rollback transaction
}
If one of the operations in the method throws a runtime
exception, but the method uses a try-catch block to treat
it, the exception never gets to the aspect. The aspect can’t
know such an exception occured, so it will commit the transaction.
Figure 13.5 If a runtime exception is thrown inside the met hod, but the met hod treat s t he exception and doesn’t
throw it back t o t he caller, t he aspect won’t get t his exception and will commit t he t ransact ion. When you t reat
an exception in a transact ional met hod, such as in t his case, you need t o be aware the transact ion won’t be rolled
back, as the aspect managing t he t ransact ion cannot see the except ion.
the method treas he xcption in its logic and doesn’t hrow the xcption further,
theaspctn’tknowthexcptionocured(figure13.5)
What about checked except ions in t ransactions?
Thus far, I’ve only discussed runtime exceptions. But what about the checked exceptions? Checked exceptions in Java are those exceptions you have to treat or throw;
otherwise, your app won’t compile. Do they also cause a transaction rollback if a
method throws them? By default, no! Spring’s default behavior is only to roll back a
transaction when it encounters a runtime exception. This is how you’ll find transactions used in almost all real-world scenarios.
When you work with a checked exception, you have to add the “ throws” clause in the
method signature; otherwise, your code won’t compile, so you always know when
your logic could throw such an exception. For this reason, a situation represented
with a checked exception is not an issue that could cause data inconsistency, but is
instead a controlled scenario that should be managed by the logic the developer
implements.
If, however, you’d like Spring to also roll back transactions for checked exceptions,
you can alter Spring’s default behavior. The @Transactional annotation, which
you’ll learn to use in section 13.3, has attributes for defining which exceptions you
want Spring to roll back the transactions for.
However, I recommend you always keep your application simple and, unless needed,
rely on the framework’s default behavior.
Using transactions in Spring apps
291
13.3 Using transactions in Spring apps
Let’s ar with an emxa ple tha teches you how to use transctions ni a Spring ap .
Declaring a trnsaction in a Spring ap is a esy a using an an otai n:
tional . You use
transction. You don’t ned to do na ything els. Spring configures an aspect tha
intercps the methods you an otae with
action and either commits he method’s changes if vrything went fine or ls back
thechangesifanyrunimt excptionocured.
Wel’ wrtie an ap that sore acount deitlas n a datbse table. Imagine this
the backndof anelctronicwaletap youimplement.We’l creathecapbilty o
transfer money from one acount to another. For this use case, we’l ned to use a
transctiontoensurethedatsyconsitentifanexcptionocurs.
The clas design of the ap we implement is traghtforward. We use a tble in a
datbose t hre acoundt ea(ilns cludinthg moe naemy ount)We. implemenat
reposit ry to work with the dat in this table, and we implement the busines logic
(the money transfer use ca) in a servic la. The srvic method tha implements
thebusineslogicswherwe’lnedtouseatrnsaction.Weexposethisusecaby
implementing an endpoint in the controle clas. To transfer money from one
acount o another, someone neds to cal this endpoint. Figure 13.6 ilustrae the
a p ’sc la d e ig n .
@Transac@Transactional to mark a method you want Spring to wrap in a
@Transactional . This apect sar tns-
The AccountController is a REST controller
that exposes the POST /transfer endpoint.
This endpoint offers a way to call the
transfer money use case.
The TransferService implements the
transfer money use case with the
transferMoney() method. We need to
execute this method in a transaction to
make sure we avoid data inconsistencies.
POST /transfer
AccountController
TransferService
AccountRepository
transferMoney()
DATABASE
(holds the
account table)
The transferMoney() method logic implements the
steps “ withdraw the money from the source account”
and “ deposit the money in the destination account.”
These are mutable operations, so we wrap them in a
transaction to make sure that, if either fail, the data is
rolled back to the way it was before the use case started.
The repository class implements all the
operations with the account table in
the database.
Figure 13.6 We implement the t ransfer money use case in a service class and expose t his service method
through a REST endpoint . The service met hod uses a reposit ory to access t he dat a in the dat abase and change
it . The service method (which implements the business logic) must be wrapped in a transact ion t o avoid dat a
inconsist encies if problems occur during the method execut ion.
292
CHAPTER 13
Using transactions in Spring apps
You find the xample in the project“sq-h13-ex.” We’l creat SpringBoot project
andthepndpenitsomce .xmprasenfil, tedhncoesdxt ip et. We
continue sinSpg rinJDg BCwe(as di nchpa n12)ter danH2in-memodry atbse:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
Theap workswithonlyonetablinadtbase.Wenamethistable“count,”andit
hasthefol wingfields:
id —Theprimaryke.WedefinethisfeldanINTvaluethaselfincrements.
name —Thenameoftheacount’sowner.
amount —Theamountofmoneytheownerhasintheacount.
We use a “chema.sql” fie n the project’s rources folderto creat he tabl. In this
file,wewritehSQLquerytocahetabl,sprentedni thenextcodesnip et:
create table account (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
amount DOUBLE NOT NULL
);
Wealsod “da t.sqnfile” thar “sce ma.sqinl” thresouforces ldtoerwca o
recods we’l use later to tes. The “dat.sql” file contai s SQL queris to ad two
acountrecodstohedatbse.Youfindthesquerisnthefol wingcodesnip et:
INSERT INTO account VALUES (NULL, 'Helen Down', 1000);
INSERT INTO account VALUES (NULL, 'Peter Read', 1000);
Wenedaclsthamodelstheacountableohawave ytoref thedatinour
ap so,wenclasret med
ashowni thefol winglsting.
Listing 13.1
Accounttomodthel acounrecot dins thde atbse,
The Account class that models t he account t able
public class Account {
private long id;
private String name;
Using transactions in Spring apps
293
private BigDecimal amount;
// Omitted getters and setters
}
Toimplementh“reansfemor neyu” sca,wenedthfeol wincagpbiltnes he
reposit rylae:
1
2
FindthedtailsfornacountusingtheacountID.
Updateheamountforagivenacount.
We’l implement thes capbiltes as discued in chapter 10, using
JdbcTemplate .
For step 1, we implement the method
findAccountById(long id) , which gets the
JdbcTemplate to get he acount details for the
a c o u n t ID in a p a r m e t r a nd us e
acount with tha ID from the datbse. For step 2, we implement a method named
changeAmount(long id, BigDecimal amount) . This method set he amount i ges a
the scond parmetr to the acount with the ID it gets in the first parmetr. The
nextlisngshowsyoutheimplementaionofthestwomethods.
Listing 13.2
Implement ing t he persist ence capabilit ies in t he reposit ory
We add a bean of this class in the Spring context
using the @Repository annotation to later inject
this bean where we use it in the service class.
We use constructor dependency
injection to get a JdbcTemplate
object to work with the database.
@Repository
public class AccountRepository {
private final JdbcTemplate jdbc;
public AccountRepository(JdbcTemplate jdbc) {
this.jdbc = jdbc;
}
We get the details of an
account by sending the SELECT
query to the DBMS using the
JdbcTemplate queryForObject()
method. We also need to provide
a RowMapper to tell JdbcTemplate
how to map a row in the result to
our model object.
public Account findAccountById(long id) {
String sql = "SELECT * FROM account WHERE id = ?";
return jdbc.queryForObject(sql, new AccountRowMapper(), id);
}
public void changeAmount(long id, BigDecimal amount) {
String sql = "UPDATE account SET amount = ? WHERE id = ?";
jdbc.update(sql, amount, id);
We change the amount of an account by
}
}
Asyolearuniedchwhap12, ter nyouse
buase inSEag LECTquyoer, unedtoprovidae
Template howtomapeachrowofthersultfomthedatbseoy urspecifmodel
obInject. ouwecase,r nedtoel
Account object.Thenxtlisngshowsyouhowtoimplementhe
sending an UPDATE query to the DBMS using
the JdbcTemplate update() method.
JdbcTemplatefrdometiav thda-e
RowMapperobwhject, ichtels
Jdbc-
JdbcTemplatehowtomaproa winthresutol he
RowMapper object.
294
CHAPTER 13
Listing 13.3
Using transactions in Spring apps
Mapping t he row t o a model object inst ance wit h a RowMapper
We implement the RowMapper contract and provide the
model class we map the result row into as a generic type.
We implement the mapRow()
method, which gets the query
result as a parameter (shaped
as a ResultSet object) and
returns the Account instance
we map the current row to.
public class AccountRowMapper
implements RowMapper<Account> {
@Override
public Account mapRow(ResultSet resultSet, int i)
throws SQLException {
Account a = new Account();
a.setId(resultSet.getInt("id"));
a.setName(resultSet.getString("name"));
a.setAmount(resultSet.getBigDecimal("amount"));
return a;
We return the account instance
}
We map the values on the
current result row to the
Account’s attributes.
after mapping the result values.
}
To tes he ap more asily, et’ also ad the capbilty o get al the acount details
fromthde atbshe, owni thfoe l winlgst Weg. u’l sthe capi bilwhty envrifyngthatheap worksaweexpct.
Listing 13.4
Get t ing all the account records from t he database
@Repository
public class AccountRepository {
// Omitted code
public List<Account> findAllAccounts() {
String sql = "SELECT * FROM account";
return jdbc.query(sql, new AccountRowMapper());
}
}
In the servic clas, we implement the logic for the “transfer money” use case. The
TransferService clas use the
acountable.Thelogicthemethodimplementsiafol ws:
1
2
3
AccountRepository clas to manage the dat in the
Get he source and destination acount details o find out he amount in both
acounts.
Withdrawthetransferdamountfromthefirstacountbyseinganewvalue,
whichst eacountminusthe amountobewithdrawn.
Deposit he transferd amount into the destination acount by seting a new
value,thecurntamountofheacountplusthetransferdamount.
Listing 13.5 shows you how the
ments his logic. Observ that points 2 and 3 define mutable operations. Both thes
transferMoney() method of the srvice clas imple-
Using transactions in Spring apps
operations change the persitd dat (i.e, they updtae some acount’s amounts). If
wedonwrt’ apthemintra csationwe, caniget howhcase ther dbat ecomes
in co n si te nt be ca u s o ne o fth e st p fails.
Fortunately, we only ned to use the
methodastrnsactionalndtelSpringitnedstointercphismethod’sexcutions
andwrapthemintra sctionThs. foe l wni ltsg howyos uthime plementaionof
themoneytransferucaloginthesrvicla.
Listing 13.5
295
@Transactional an otai n to mark the
Implement ing t he money t ransfer use case in t he service class
@Service
public class TransferService {
private final AccountRepository accountRepository;
public TransferService(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
We use the @Transactional
}
annotation to instruct Spring to wrap
the method’s calls in transactions.
@Transactional
public void transferMoney(long idSender,
long idReceiver,
BigDecimal amount) {
Account sender =
We get the accounts’ details
accountRepository.findAccountById(idSender);
to find the current amount
Account receiver =
in each account.
accountRepository.findAccountById(idReceiver);
BigDecimal senderNewAmount =
sender.getAmount().subtract(amount);
BigDecimal receiverNewAmount =
We calculate the new amount
receiver.getAmount().add(amount);
for the destination account.
We
calculate
the new
amount for accountRepository
the sender .changeAmount(idSender, senderNewAmount);
account.
We set the new amount value
for the sender account.
accountRepository
.changeAmount(idReceiver, receiverNewAmount);
We set the new amount value
for the destination account.
}
}
Figu1re3.7vs alpy resntshtreansactioncsopeandthsepthe
methodexcuts.
Let’s also implement a method tha retivs al the acounts. We’l expose this
method with an endpoint in the controle casl we’l define later. We wil use it to
checkthedatwascoretlyhangedwhentesingthetransfermoneyuscae.
transferMoney()
296
CHAPTER 13
Using transactions in Spring apps
DATABASE
AccountController
The transaction starts here.
Right after Account Controller
calls the service method,
the Spring transaction aspect
intercepts the call and starts
the transaction.
TransferService
Transaction scope
AccountRepository
Gets details for the sender
account
SELECT
Gets details for the destination
account
SELECT
Calculates the new
amounts
Updates the source account
Updates the destination
account
UPDATE
UPDATE
If the method didn’t throw a
runtime exception, the Spring
transaction aspect commits
the transaction here, after
the method execution ends.
Figure 13.7 The transact ion starts just before t he service met hod execut ion and ends just after t he method
successfully ended. If t he met hod doesn’t throw any runt ime exception, t he app commit s the t ransaction. If
any st ep causes a runt ime except ion, the app rest ores t he dat a t o how it was before t he transact ion st art ed.
Using @Transactional
The @Transactional annotation can also be applied directly to the class. If used on
the class (as presented in the next code snippet), the annotation applies to all the class
methods. Often in real-world apps you will find the @Transactional annotation used
on the class, because the methods of a service class define use cases and, in general,
all the use cases need to be transactional. To avoid repeating the annotation on each
method, it’s easier just to mark the class once. When using @Transactional on both
the class and the method, the method level’s configuration overrides the one on the class:
@Service
@Transactional
public class TransferService {
// Omitted code
We often use the @Transactional annotation
directly with the class. If the class has multiple
methods, @Transactional applies to all of them.
public void transferMoney(long idSender,
long idReceiver,
BigDecimal amount) {
// Omitted code
}
}
Using transactions in Spring apps
The next listng shows you the implementaion of the
whichretunsalitofhedatbse’countrecods.
Listing 13.6
297
getAllAccounts() method,
Implement ing a service met hod t hat ret urns all t he exist ing account s
@Service
public class TransferService {
// Omitted code
public List<Account> getAllAccounts() {
return accountRepository.findAllAccounts();
}
}
In the fol wing listng, you find the
definesthendpointshatexposethesrvicmethod.s
Listing 13.7
AccountController clas’ implementaion that
Exposing t he use cases t hrough REST endpoint s in t he cont roller class
@RestController
public class AccountController {
private final TransferService transferService;
public AccountController(TransferService transferService) {
this.transferService = transferService;
We use the HTTP POST method for the
}
/transfer endpoint because it operates
changes in the database's data.
@PostMapping("/transfer")
public void transferMoney(
@RequestBody TransferRequest request
We use a request body to get the
) {
needed values (source account ID,
transferService.transferMoney(
destination account ID, and amount
request.getSenderAccountId(),
to be transferred).
request.getReceiverAccountId(),
request.getAmount());
We call the service transferMoney()
}
method, the transactional method that
implements the transfer money use case.
@GetMapping("/accounts")
public List<Account> getAllAccounts() {
return transferService.getAllAccounts();
}
}
Weuseanobjectofype
parmetThr. e
objects, whose responsiblty is to model the dat transferd betwen two ap s, are
DTOs.Thefol winglistngshowsthedfintionofthe
TransferRequest asthe
TransferRequest objectsimpmoly dethls HTTPrequebst odSuy. ch
transferMoney() controleaci n
TransferRequest DTO.
298
CHAPTER 13
Listing 13.8
Using transactions in Spring apps
The TransferRequest data transfer object modeling the HTTP request body
public class TransferRequest {
private long senderAccountId;
private long receiverAccountId;
private BigDecimal amount;
// Omitted code
}
Star he ap licaton, and let’s how the transaction works. We use cURL or Postman to cal the ndpoint the ap expose. First, le’ cal the /acounts endpoint o
check how the dat lo ks befor excuting any transfer money operation. The next
snip eths owsyouthecURLcommandtousetocalhe/acountsendpoint:
curl http://localhost:8080/accounts
Once you run this command, you should find an output in the console imilar to he
oneprsntedinthenextsnip et:
[
{"id":1,"name":"Helen Down","amount":1000.0},
{"id":2,"name":"Peter Read","amount":1000.0}
]
We have two acounts in the datbse (we insertd them earli n this ecton when
wedefinedthe“dat.sql”fie)BothHelenandPetrown$1,0each.Let’snowexcute the transfer money use case to transfer $10 from Helen to Petr. In the next
codesnip et,youfindthecURLcommandyounedtoruntocalhe/transferndpointo send$10fromHelentoPetr:
curl -XPOST -H "content-type:application/json" -d '{"senderAccountId":1,
➥ "receiverAccountId":2, "amount":100}' http://localhost:8080/transfer
Ifyoucalthe/acountsendponi tgain,youshouldobrvesthedifrence.Afterhe
moneytransferoperation,Helenhas$90,whilePtrnowhas$1,0:
curl http://localhost:8080/accounts
The result of caling the /acounts endpoint after the money atnr sfer operation is
presntedinthenextsnip et:
[
{"id":1,"name":"Helen Down","amount":900.0},
{"id":2,"name":"Peter Read","amount":1100.0}
]
Using transactions in Spring apps
Thaep wois rkinag, dthue scgaivthexpctdresultBu. wht der oweprove
thetransactoi nrealyworks?Theap coretlyprsithedatwhenevrythingoes
wel, but how do we know the ap inde resto the dat if something in the
methodthrowsaruntimexcption?Shouldwejustr idoes?Ofcoursenot!
NOTE
One of the most important things I learned about ap s is that you
shouldnevrtusomethingworksunlesyoutesdiproperly!
I like to say tha until you tes any featur of your ap , it s in a Schrödinger sta. I
bothworksand oesn’tworkuntilyouproevitsa.Ofcourse,thisjustapersonal
anlogyImakewithanesntialconceptfromquantummechanics.
Let’s tes the transaction rols back as expctd when some runtime excption
ocurs. I duplicated the project “sq-ch13-ex” in the project “sq-ch13-ex2.” In this
copoy thf pe roajedcIt, onoly nlie ocf dthe at rowruas ntimexcptiontha e
endofthe
transferMoney() servicmethod,asprentedinthefol winglistng.
Listing 13.9
Simulat ing a problem occurs during t he use case execut ion
@Service
public class TransferService {
// Omitted code
@Transactional
public void transferMoney(
long idSender,
long idReceiver,
BigDecimal amount) {
Account sender = accountRepository.findAccountById(idSender);
Account receiver = accountRepository.findAccountById(idReceiver);
BigDecimal senderNewAmount = sender.getAmount().subtract(amount);
BigDecimal receiverNewAmount = receiver.getAmount().add(amount);
accountRepository.changeAmount(idSender, senderNewAmount);
accountRepository.changeAmount(idReceiver, receiverNewAmount);
throw new RuntimeException("Oh no! Something went wrong!");
}
}
We throw a runtime exception at the end of the service method
to simulate a problem that occurred in the transaction.
Figure13.8ilustraehechangewemadeinthe
We star he ap licaton and chek the acount recods by caling the /acounts
endpoint,whichretunsaltheacountsinthedatbse:
curl http://localhost:8080/accounts
transferMoney() servicmethod.
299
300
CHAPTER 13
Using transactions in Spring apps
DATABASE
AccountController
When the transaction rolls
back, the app restores the
data to how it was at the
beginning of the
transaction, here.
TransferService
Transaction scope
Both these steps successfully
execute. But because the
method throws a runtime
exception, the app rolls back
the transaction and restores
the data, so the changes
these two steps made won’t
be persisted.
AccountRepository
Gets details for the sender
account
SELECT
Gets details for the destination
account
SELECT
Calculates the new
amounts
Updates the source account
Updates the destination
account
Throws a runtime exception
UPDATE
UPDATE
After updating the two accounts, the method
throws a runtime exception. The transaction
hasn’t ended. The Spring transaction aspects
gets the runtime exception and rolls back
the transaction. The app restores the data
to how it was at the beginning of the transaction.
Figure 13.8 When t he method throws a runt ime except ion, Spring rolls back the transact ion. All t he successful
changes made on t he dat a are not persisted. The app rest ores t he dat a to how it was when the t ransaction
st art ed.
Once you run this command, you should find an output in the console imilar to he
oneprsntedinthenextsnip et:
[
{"id":1,"name":"Helen Down","amount":1000.0},
{"id":2,"name":"Peter Read","amount":1000.0}
]
As in the previous te, we cal the /transfer ndpoint o transfer $10 om Helen to
PetrusingthecURLcommand,showni thenextsnip et:
curl -XPOST -H "content-type:application/json" -d '{"senderAccountId":1,
➥ "receiverAccountId":2, "amount":100}' http://localhost:8080/transfer
Now,the
transferMoney() methodofthesircvlathrowsna excption,resulting
in an ero 50 in the rsponse nt o the clint. You should find this excption in
the ap ’s console. The xcption’s tack re is milar to the one presnted in the
n ex tc o de sn ip et:
Summary
301
java.lang.RuntimeException: Oh no! Something went wrong!
at
com.example.services.TransferService.transferMoney(TransferService.java:30)
➥ ~[classes/:na]
at
com.example.services.TransferService$$FastClassBySpringCGLIB$$338bad6b.invoke
➥ (<generated>) ~[classes/:na]
at
org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
➥ ~[spring-core-5.3.3.jar:5.3.3]
Let’scalhe/acountsendpointaginandesiftheap changedtheacounts:
curl http://localhost:8080/accounts
Once you run this command, you should find an output in the console imilar to he
oneprsntedinthenextsnip et:
[
{"id":1,"name":"Helen Down","amount":1000.0},
{"id":2,"name":"Peter Read","amount":1000.0}
]
Youobthserv dat idnch’t anevg thif excptionhap enthafrs we o perationths ca nthge amounits hacoe unHets. lenshoudl have dan$90 dPetr
$1,0 but both of them stil have the same amounts in their acounts. This reult is
the consequence of the transaction being roled back by the ap , which cause the
dat to be restod to how it was at the begin ing of the transction. Even if both
mutable step were excutd, when the Spring transction aspect got the runtime
excption,itroledbacktheransction.
Summary
A transaction is a set of operations tha change dat, which either excut
togeher or not a l. In a rel-world scenario, almost any use case hould be
thesubjectofarnsactiontoav id atinconsitencis.
aIfnoy thf eoperationfails,thape restohedatohowitwaaths be ginnthiraonfegsctionWh. enthatp etnhwera syt,eaciobnr ack.ls
If al the operations uced, we say the transction commits, which means the
ap persitalhechangestheuscaxe tiondi .
ToimplementransctionalcodeinSpring,you esthe
taion. You use the
Spring to wrap in a trnsaction. You can also an otae clas with
tional toelSpringthatnyclasmethodsnedtobetransactional.
AtexcutionSpa, rinaspg inect rpths mee thodans otaedwith
tional .Theaspctsarhetransction,andifanexcptionocurstheaspct
rolsbackthetransaction.Ifthemethod oesn’throwanexcption,thetransactioncommits,andtheap persithemethod’schanges.
@Transactional an o@Transactional an otai n to mark a method you expct
@Transac@Transac-
withSprngData
datpersinc
This chapter covers
How Spring Data works
Defining Spring Data repositories
Using Spring Data JDBC to implement a Spring
app’s persistence layer
In this chapter, you’l learn to use Spring Data, a Spring ecosytm project tha
givesyoutheposibltyofimplementingaSpringap ’speritncelayrwithminimumefort.Asyoualredyknow,na ap licatonframework’sentialroeisprovidng out-ofhe-box capbiltes hat you can driectly plug into ap s. Frameworks
helpusavetimeandalsomakeap s’deigneasirtounderstna d.
Youlearn’ tohcrea p rep’s osit bredy claring tYerofacs. uthle’
framework provide implementaions for thes interfacs. You’l literay enable
302
Implementig
What Spring Data is
303
your ap to work with a datbse without implementi g the rposit ry ourself and
withminimumefort.
We’l star the chapter by discung how Sprni g Data works, and in section 14.2
you’l earn how Spring Data integras into Spring ap s. We’l then continue in section 14.3 with a practil example wher you’l learn to use Spring Data JDBC to
implementanap licaton’speritncelayr.
14.1 What Spring Data is
In this ecton, we discu what Spring Data is and why we hs ould use this project o
implement a Spring ap ’s persitnce apbiltes. Spring Data is a Spring ecosytm
project hat simplifes the persitnce layr’s devlopment by providng implementationacos rdintoghpe rsitnechnol wegy uThse. wais wey, only edtowraite
few lines of code to defni the reposit re of our Sprni g ap . Figure 14. ofers a
visualrepsntaionofSpringData’splcefromanp ’sper ctive.
Spring App Logic
Spring Data
Persistence
technology
Persistence
technology
Persistence
technology
Persistence
technology
Spring Data is a high-level
layer that simplifies the
persistence implementation
by unifying the various persistence
technologies under the same
abstractions.
Figure 14.1 The Java ecosyst em offers a large number of various persist ence t echnologies. You use
each technology in a specific way. Each t echnology has it s own abst ract ions and class design. Spring
Data offers a common abst ract ion layer over all t hese persist ence t echnologies to simplify the use of
multiple persistence t echnologies.
Letse’wherSpingDatfiasnSpinr gap .Ina p ,youhaverioutecshnol gies you can use to work with persitd dta. nI chapters 12 and 13, we used JDBC,
which directly con ects to a relational DBMS through a drive manager. But JDBC
isn’theonylap roachyoucanusetoc n ctoe arli naldtbase.Anothercommon way to implement dat persitnce is using an ORM framework, such as Hibernate.Andrelationaldtbasernt’hoe nlykindopf ersitndg atechnol gieAns.
ap mightuseoneofthevariousNoSQLtechnol giesouthertopersitda.
304
CHAPTER 14
Implementing data persistence with Spring Data
Figush14.2re owyos uomoeSpf rinaltge’s aotivespdersit Eaa. chalternative
ohwits a nwaimofy plementinhapg er ’soitS rmes. etimyoues,vnhmoave re
options to implement he ap ’s persitnce layr fo ne tchnol gy (such as JDBC).
Foerxample,withJDBC,youcna use
you could work directly with the JDK interfacs (
ResultSetan, dso nHa). vinsogmanway toysimplementhape p’s eritncape biltesad scomplexity.
JdbcTemplate yo,as ulearndinchapter12,but
Statement , PreparedStatement ,
You have various choices for implementing
the persistence layer. Your app might directly
connect to a relational DBMS through JDBC,
or it can choose other libraries to connect
to a NoSQL implementation such as MongoDB,
Neo4J, or another persistence technology.
Spring App Logic
JDBC
MongoDB
Neo4J
Some other
persistence
technology
Figure 14.2 Using JDBC t o connect t o a relational DBMS is not t he only choice for implement ing an
app’s persistence layer. In real-world scenarios, you’ll use other choices as well, and each way t o persist
data has it s own library and set of APIs you need t o learn to use. This variety adds a lot of complexit y.
The diagrm gets more complitcead if we include ORM frameworks such as Hibernate. Figure 14.3 shows Hibernate’s place in the scen. Your ap could ues JDBC
dinrectly vaouwas bys, ucoit uldasorely nframewoimrk plementdoJDver BC.
The Spring app can
use JDBCdirectly or
an ORM framework
such as Hibernate.
Spring App Logic
JDBC
Hibernate
MongoDB
Neo4J
Some other
persistence
technology
Hibernate is an ORM persistence framework
that relies on JDBCand simplifies some aspects
of working with persisted data.
Figure 14.3 Sometimes apps use frameworks built on t op of JDBC, such as Hibernate. The variet y in choices
makes implement ing a persistence layer complex. We want t o eliminate t his complexit y from our apps, and,
as you’ll learn, Spring Data helps us do t his.
What Spring Data is
305
Don’t be woried! You don’t ned to learn al thes at once, and you don’t ned to
knowoalthf emtolearnSprinDag Fta.orunkately, owinwhg weat lredy iscued
in chapters 12 and 13 on JDBC is enough for a foundation to star learning Sprni g
DaThta. reasonmaI dyoe uawoarethlf oisedemonwhstrae Spy rinDag soita
valuble.Youmight avlredsky ours“elIthf, waear wey canimplementhe
persitnce for al thes tchnol gies nstdea of havni g to know difernt ap roaches
foreach?”Theanswerisy,andSpringDatahelpsuachievthisgoal.
Spring Data simplifes the implementaion of the persitnce layer by doing the
fol wing:
Providng a common set of abstrcions (interfacs) for various persitnce
technol gies. This way, ou use a similar p roach for implementing the persitencfordifentechnol gies.
Allowing the user to implement the persitnce operations using only the
abstrcions, for which Spring Data por vides the implementaions. This way,
youwrite lescode,soy umorequicklymplementheap ’scapbiltes.With
leswritencode,theap alsobecomesairtounderstandandmaintain.
Figure14.showsSpringData’sposit ninaSpringap .Asyouobserv,SpingData
isahigh-levayrovethevariouswaystoimplementheprsitenc.So,whichevr
yois uchr oticemplemenyot uapr p’s eritnyofce, u Spse rinDag yota, uwr’l ite
theprsitnceoperationsimlaryi.
Spring Data is a high-level
layer that simplifies the
persistence implementation
by unifying the various
technologies under the same
abstractions.
Spring App Logic
Spring Data
JDBC
Hibernate
MongoDB
Neo4J
Some other
persistence
technology
Figure 14.4 Spring Data simplifies t he persist ence layer implement ation by offering a common set of
abst ract ions for various technologies.
306
CHAPTER 14
Implementing data persistence with Spring Data
14.2 How Spring Data works
Inthseictonwe, discuhowSprinDag wota rksandhowyou’l se foti rmplementingyourSpingap ’speritnceaylr.Whendevlopersuethetrm“SpringData,”
theyrf in genralto al the capbiltes hisprojectprovidesto y urSpringap to
con ecto neprsitencethnol gyoranother.Inanap ,generalyou seapeciftehnol gy:JDBC,Hibernate,MongoDB,oranothertchnol gy.
The Spring Data project ofers difernt modules for one tchnol gy or another.
Thmoes duinare lsdepndenotfna e othaner, dyoucand themtoy upr oject
using difernt Maven depndenc.ies So, when you implement an ap , you don’t use
the Spring Data depndency. Ther is no such thing as one Spring Data depndency.
ThSpe rinDag pta ropject rovidoesnMae vendepndenfocyeahr persitnfahce ion
situp ortsF. oerxample,youcanustehSpringDataJDBCmoduletoc n tecohe
DMBS directly hroughJDBC,or usethe SpringDataMongo module toc n ect oa
MongoDBdatbse.Figure14.5showswhatSpringDatalo kslieungJDBC.
An app will use one persistence technology or another.
The app only needs the Spring Data module according to
the technology it uses. If the app needs to use JDBC, it
needs to add a dependency to the Spring Data JDBCmodule.
Spring App Logic
Spring Data JDBC
JDBC
Figure 14.5 If t he app uses JDBC, it only needs the part of t he Spring Dat a project that manages persist ence
through JDBC. The Spring Dat a module t hat manages t he persistence t hrough JDBC is called Spring Data JDBC.
You add t his Spring Data module t o your app through its own dependency.
You can find the ful list of Spring Data modules on Spring Data’s ofical page:
hps t/rins:g.o/projects/pring-dat
Whichevrpersitncethnol gyourap use,SpringDataprovidesacommon
set of interfacs (contracs) you extnd to define the ap ’s persitnce capbiltes.
Figure14.6psnthefol winginterfacs:
.
How Spring Data works
307
Repository is the most abstrc ontrac. If you extnd this contrac, your ap
recognthi zespyoturwrfaciSpslrnDaite g reptaoy Ssuil, ry.
woni ’t hanperit ydefinedoperation(suadchs ni a ewg rcodetivn, g
thalrecodgetins,rcoadgpbits yrmThkey).ar e
doesn’tdeclarnymethod(itsamarkeinterfac).
CrudRepository is the simplest Spring Data contrac that also provides some
persitnce capbiltes. If you extnd this contrac to define your ap ’s persitence capbiltes, you get the simplest operations for creating, retivng,
updating,and eltingrecods.
PagingAndSortingRepository extnds
reatldos rtinhg recodos retinv thg eminchunoks paf enci umber
(pages).
Repositoryinterfac
CrudRepository and ad s operations
Repository is a marker interface. It contains
no methods, and its purpose is to represent
the top of the contract hierarchy in Spring
Data. Most likely, you won’t extend this
interface directly.
Repository
<<interface>>
Extends
CrudRepository
<<interface>>
Extends
CrudRepository defines the contract for
simple create, read, update, and delete
operations. This is one of the interfaces
you’ll extend most frequently when
defining Spring Data repositories.
PagingAndSortingRepository enhances the
CrudRepository contract by adding operations
for data read with pagination and sorting.
You extend this interface if you need to
use pagination and sorting operations when
retrieving data from the database.
PagingAndSortingRepository
<<interface>>
Figure 14.6 To implement your app’s repositories using Spring Dat a, you ext end specific int erfaces.
The main int erfaces t hat represent Spring Data cont ract s are Repository , CrudRepository , and
PagingAndSortingRepository . You extend one of t hese cont ract s t o implement your app’s
persist ence capabilit ies.
308
CHAPTER 14
NOTE Don’t confuse the
with the Spring Data
the steroype an otai n you use with clase to instruc Spring to ad an
instance of the an otaed clas to the ap licaton contex. This
interfac we discu in this chapter is specif to Spring Data and, as you’l
learn, you extnd it or another interfac that extnds from it to define a
Sprni gDatareposit ry.
Implementing data persistence with Spring Data
@Repository an otai n we discued in chapter 4
Repository interfac. The
@Repository an otai n is
Repository
Maybe you wonder why Spring Data provides multipe interfacs that extnd one
another. Why not only one interfac with al the operations in it? By implementi g
multipe contracshatexndecah other insteadofprovidng you one “fat”contrac
with al the operations, Spring Data gsive your pa the posiblty o implement only
theoperationsitneds.Thisap roachisaknownprincplecadinterfacsgo.
For example, if your ap only neds to use CRUD operations, it extnds the
Repository contrac.Yourap won’tgeheoperationsrelatdos rtingandpaging
recods,makingyourap simpler(figue14.7)
Crud-
Spring Data
Repository
<<interface>>
If your app needs simple CRUD operations,
but it doesn’t need sorting or pagination,
then your app’s repository can directly
extends Spring Data’s CrudRepository.
Extends
CrudRepository
<<interface>>
App’s logic
Extends
TransferService
Uses
AccountRepository
<<interface>>
Extends
PagingAndSortingRepository
<<interface>>
Because AccountRepository extends a Spring Data contract,
the framework provides an implementation of this interface
as a bean in the application context. Other classes in the
app can use DI to get the needed implementation of
AccountRepository.
Figure 14.7 To creat e a Spring Dat a reposit ory, you define an int erface t hat ext ends one of t he Spring Data
contracts. For example, if your app only needs CRUD operat ions, t he int erface you define as a reposit ory should
extend t he CrudRepository interface. The app adds a bean that implements t he contract you define to t he
Spring cont ext, so any other app component s that need to use it can simply inject it from the cont ext.
How Spring Data works
yoIf uapr alsonedps aging dsortinpcag boiltes mvr pCRUD
le operationits,
should extnd a more particul contrac, the
face(igur14.8)
309
PagingAndSortingRepository inter-
Spring Data
Repository
<<interface>>
If the app also needed sorting and pagination
capabilities when retrieving the data from
the database, it would have extended the
PagingAndSortingRepository.
Extends
CrudRepository
<<interface>>
App’s logic
TransferService
Extends
Uses
AccountRepository
<<interface>>
Extends
PagingAndSortingRepository
<<interface>>
Figure 14.8 If t he app needs sort ing and paging capabilit ies, it should ext end a more part icular cont ract. The
app provides a bean t hat implements t he contract , which can then be inject ed from any other component that
needs t o use it .
Some Spring Data modules might provide specif contracs to the technol gy they
JpaReposirepsnt. For example, using Spring Data JPA, you also can extnd the
tory interfacdi(lysprentedinfgure14.9)The
JpaRepository interfacis
contrac more particul than
PagingAndSortingRepository . This contrac ad s
operations ap licabe only when using specif technol gies like Hibernate tha
implementheJakrtPsienceAPI(JPA)specifaton.
Another xample is using a NoSQL technol gy such as MongoDB. To use Spring
Data with MongoDB,you would ned to ad the Spring Data Mongo module to y ur
ap , which also provides a particul contrac named
MongoRepository that ad s
operationspeciftohispertncethnol gy.
When anap usecrtain technol gies,t xndsSpring Data contracs hat provide operations particul to that technol gy. The ap could stil implement
CrudRepository if it doesn’t ned more than the CRUD operations, but thes specif
contracs us aly provide solutions tha re more comfortable to use with the specif
technol gy they’r made for. In figure 14.0, the
AccountRepository clas (of the
ap )extndsfrom
JpaRepository (speciftoheSpringDataJPAmoduel).
310
CHAPTER 14
Implementing data persistence with Spring Data
Repository
<<interface>>
Extends
CrudRepository
<<interface>>
Extends
PagingAndSortingRepository
<<interface>>
JpaRepository
<<interface>>
MongoRepository
<<interface>>
Some specific Spring Data modules extend the contract
chain even further, adding operations that are particular
to their technology. For example, if your app uses MongoDB,
you could define your Spring Data repositories extending the
MongoRepository interface, which is particular for Spring
Data Mongo.
If you use Hibernate (which implements the JPA specifications),
you could extend the JpaRepository contract, which adds
operations that are specific for using the JPA approach.
Figure 14.9 Spring Data modules that are specific to certain technologies might provide part icular
contracts that define operations you can apply only wit h t hose t echnologies. When using such
technologies, your app most likely will use these specific contract s.
Using Spring Data JDBC
311
Spring Data
Repository
<<interface>>
Extends
CrudRepository
<<interface>>
In some cases, specific Spring Data modules
provide even more particular interfaces.
For example, if your app would use an
ORM framework such as Hibernate, you
would use the Spring Data JPA module.
This module provides the JpaRepository
interface, which is a contract that defines
particular operations that can be used only
with a framework such as Hibernate.
Extends
PagingAndSortingRepository
<<interface>>
Extends
JpaRepository
<<interface>>
App’s logic
Extends
TransferService
Uses
AccountRepository
<<interface>>
Figure 14.10 Different Spring Dat a modules might provide other, more part icular cont ract s. For example, if you
use an ORM framework such as Hibernat e (which implement s the JPA) wit h Spring Dat a, you can ext end t he
JpaRepository int erface, which is a more part icular cont ract t hat provides operations applicable only when
using a JPA implement at ion, such as Hibernat e.
14.3 Using Spring Data JDBC
In this section, we use Spring Data JDBC to implement the persitnce layer of a
Springap .Wediscuedthaytol unedtodoexistndSapinr Dag otac ntacr,but
let’s it n action. In ad iton to implementing a plain reposit ry, ou’l aso learn
howtocreandusec tomreposit ryoperations.
Weco’l nsidcenar iosmtoilarhoe nwee workedoni chapTh13.ter ape lication we build is an elctronci walet managin its user’ acounts. A user can transfer money from their acount o another acount. In this tuorial, we implement he
montraey usfr tocael wthue tosrndmonfroey monacoe untoanother.
Themoneytransferoperationhastwostep(figure14.):
1
2
Withdrawagivenamountofr mthesnder’sacount.
Depositheamountinthedstinationacount.
312
CHAPTER 14
Implementing data persistence with Spring Data
Before the money transfer operation
John
Jane
John wants to transfer $100 to Jane.
Before transferring the money, John
owns $1,000 and Jane owns $500.
Owns $1,000
Owns $500
Step 1: Withdraw $100 from John’s account.
$100
Jane
John
Owns $900
The money transfer operation has two steps.
In the first step, the money is withdrawn from
John’s account. After the execution of the first
step, John owns $900. Jane didn’t get the
money yet, so she still owns $500.
Owns $500
Step 2: Deposit $100 into Jane’s account.
$100
John
Owns $900
In the second step, the $100 is added
to Jane’s account. John has $900, and
Jane has $600.
Jane
Owns $600
Figure 14.11 The money t ransfer use case implies two steps. First , t he app withdraws the t ransferred
amount from t he sender’s (John’s) account. Second, t he app deposits t he t ransferred amount into t he
receiver’s (Jane’s) account .
Using Spring Data JDBC
313
We’l store the acount details n a tble in the datbse. To kep the xample short
andsimpanle dalowyoutof cuos nthsiectonsu’ bweject, u’l asne H2in-memory
d at b se ( d i c us ed in ch ap te r1 2 ).
Theacountablehasthefol wingfields:
id —Theprimaryke.WedefinethisfeldanINTvaluethaslfincrements.
name —Thenameoftheacount’sowner
amount —Theamountofmoneytheownerhasintheacount
Youcanfindthisexampleintheproject“sq-h14-ex.”Thedpendencieswenedto
ad toheproject(inthepom.xmlfie)arpesntedinthenextcodesnip et:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
We use the Spring
Data JDBCmodule to
implement this app’s
persistence layer.
We ad a “schema.sql” file in the Maven project’s resources folder to creat the
acount table in the ap ’s H2 in-memory datbse. This file store the DDL query
ned tocreaheacountable,sprntedinthenxtcodesnip et:
create table account (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
amount DOUBLE NOT NULL
);
Wealsonedtoad acoupole frc dstoheacountable.Weusethesrcodsto
tesheap licatonlaterwhenwefinshimplementingt.Toinstrucheap toad a
coupolercf dwes, “dacret .sqinfle” thMae venproejsct’ uforce ldToer.
ad tworec dsintheacountable,we’lwriteacoupleof
“dat.sql”fie,prsntedinthenxtcodesnip et:
INSERT staementsinthe
INSERT INTO account VALUES (NULL, 'Jane Down', 1000);
INSERT INTO account VALUES (NULL, 'John Read', 1000);
At the nd of the sction, we’l demonstrae he ap works by transfering $10 from
Jane to John. Let’s model the acount able rcods with a cls named
useafildtomapeacholumni thetablwithheproperty .
Account . We
314
Implementing data persistence with Spring Data
CHAPTER 14
Remember tha, for decimals, I recommend using
or float toav idpotentialsuewithheprcisoni arithmeticoperations.
For sevral operations it provides, such as retivng dat from the datbse,
Spring Data neds to know which field maps the table’s primary ke. You use the
an otai n, as shown in listng 14., to mark the primary key. The fol wing listng
Account modelcas.
showsthe
Listing 14.1
BigDecimal instead of
double
@Id
The Account class that models t he account t able records
public class Account {
@Id
private long id;
We annotate the attribute that models the
primary key with the @Id annotation.
private String name;
private BigDecimal amount;
// Omitted getters and setters
}
Now that you have a model cas, we can implement he Spring Data reposit ry (listing14.2)WeonlynedCRUDoperationsforthisap licaton,sowe’lwriteaninterface tha extnds the
twogenrictypesounedtoprovide:
1
2
CrudRepository interfac. All the Spring Data interfacs have
Themodelcas(ometimesnamedntiy)forwhichyouwriteherposit ry
Theprimarykefildtype
Listing 14.2
Defining t he Spring Dat a reposit ory
public interface AccountRepository
extends CrudRepository<Account, Long> {
The first generic type value is the type of
the model class representing the table. The
second is the type of the primary key field.
}
When you extnd the
tions like geting a value by its primary key, geting al the recods from the table,
deltingrecods,andso n.Butican’tgiveoy ualtheposibleoperationsyoucould
implementwithSQLqueris.Inarel-worldap ,younedcustomoperations,which
nedawritenSQLquerytobeimplementd.Howdoy uimplementacusomoperationi aSpringDatareposit ry?
SpringDatamakesthisapectsoayhtyousometimesdon’tevnnedtowrite
SQa LquSpery. inDag knta owtosinterphmee thodn’s ambes adonsomne aming definiton rules and creats he SQL query behind the scnes for you. For example, say you want to write an operation to get al the acounts for a given name. In
SpringData,youcanwriteamethodwithhefol wingname:
CrudRepository interfac, Spring Data provides imple opera-
findAccountsByName .
Using Spring Data JDBC
315
When the method name star with “find,” Spring Data knows you want o
something. Next, the word “Acounts” tels Spring Data what you want to
Spring Data is so smart that I could hvae evn named the method
would stil know what o selct just becaus the method is n the
interInfac. hexaismpwaIle, ntedobmoe spre caifndmathke operation ame
. After he “By” in the method’s name, Spring Data expcts o get he query’s
clear
co n d it on ( th e
WHERE clause).Inourcase,wewantosel“cByName,”soSpringData
translatehisto
WHERE name = ? .
Fgiure 14.2 visualy repsnts he rlationship betwen the method’s name na d
thequerySpingDatacresbhindthescnes.
The query results should be
mapped to a list. When using a
collection, you tell Spring Data
you expect zero or more fetched
records as a result of executing
this operation.
SELECT
SELECT .
findByName . It
AccountRepository
The method’s parameter becomes the
query’s parameter’s value.
List<Account> findAccountsByName(String name)
SELECT * FROM account WHERE name = ?
The “ find” in the name translates
to a “ SELECT” for Spring Data.
The “ ByName” part of the method’s name
tells Spring Data which is the retrieve
condition. In an SQL query, it translates
to a “ WHERE” clause.
The “ Accounts” tells Spring Data where
to fetch the records from. It translates to
an SQL query into a “ FROM” clause.
Figure 14.12 The relat ionship bet ween the repository’s met hod name and the query Spring Data creates
behind t he scenes
The fol wing listng shows the definton of the method in the
interfac.
Listing 14.3
AccountRepository
Adding a reposit ory operation t o get all t he account s with a specified name
public interface AccountRepository
extends CrudRepository<Account, Long> {
316
CHAPTER 14
Implementing data persistence with Spring Data
List<Account> findAccountsByName(String name);
}
Thismagicoftranslatinga method’sname intoaquerylo ksincredibleatfirs ght.
Howewivr, thexprinyoce urenital’sz osbilverat ulheIt. faws disa vntages,
so I always recommend devlopers explicty specify the query instead of relnyi g on
SprinDag toarnthslae methodn’s amThe. mae indisa vnotagesrlyifnog nthe
methods’namearsfol ws:
If the operation requires a more complex query, the method’s name would be
to largend ifcultoread.
If a devloper refactos the method’s name by mistake, they might afect the
ap ’s behavior without realizng it (unfortunately, not al ap s are roughly
tesd,andwenedtoc nsiderthis).
Unles you have n IDE that ofers you hni ts while writng the method’s name,
younedtolearnthSeprinDag ta’ns ma inrgulesS.inyceoualredkynowSQL,
learni gasetofrulesap licabeonlyforSpingDataisnotadvntageous.
Perfomance is faectd becaus Spring Data lso has to translate he method
name into a query, so the ap wil intliaze slower (the pa translate the
methodnamesintoqueriswhentheap bo ts).
Thsime pwalest oyav idthpes roblemuis nthg e
SQL query that he ap wil run when you cal that method. When you an otae he
method
@Query , it’s no longer lvant how you name that method. Spring Data wil
usethequeryouproidv ensteadoftranslaitngthemethod’snameintoaquery.The
behavior also becomes more perfomant. The fol wing listng shows you how to use
the
@Query an otai n.
Listing 14.4
@Queryan otai ntospthecify
Using t he @Query annot at ion t o specify the SQL query for an operat ion
public interface AccountRepository
extends CrudRepository<Account, Long> {
@Query("SELECT * FROM account WHERE name = :name")
List<Account> findAccountsByName(String name);
Remember that the
parameter’s name in the
query should be the same as
the method parameter’s
name. There shouldn’t be any
spaces between the colon (:)
and the parameter’s name.
}
You use the
@Query an otai n in the same way to define any query. Howevr, when
your query changes dat, you also ned to an otae he method with the
a n o ta i n . I f yo u u se
UPDATE , INSERT , or
@Modifying Th. foe l winlstginhg owyos uhowtouse
methodwith
an UPDATE queryfoaposti rymethod.
@Modifying
DELETE , you also ned to an otae the
@Querytodefine
Using Spring Data JDBC
Listing 14.5
317
Defining a modifying operat ion in t he repository
public interface AccountRepository
extends CrudRepository<Account, Long> {
@Query("SELECT * FROM account WHERE name = :name")
List<Account> findAccountsByName(String name);
@Modifying
@Query("UPDATE account SET amount = :amount WHERE id = :id")
void changeAmount(long id, BigDecimal amount);
We annotate the
methods that define
operations that
change data with
the @Modifying
annotation.
}
UseDItogeabnthatimplementshe
nedit ntheap .Don’twory tha you onlywrote heinterfac. SpringDatacres
a dynamic mplementaion and ad s a ben to y ur ap ’s contex. Listing 14.6 shows
h o w th e
TransferService compone t of the ap use construcor injection to get a
bean of type
AccountRepository . In chapter 5 you learned tha Spring is mart nd
knows that if you requestd a DI for a field with an interfac ype, it neds to find a
beanthatimplementshatinerfac.
Listing 14.6
AccountRepository interfacwhervyou
Inject ing t he reposit ory in t he service class to implement t he use case
@Service
public class TransferService {
private final AccountRepository accountRepository;
public TransferService(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}
}
Listing 14.7 shows the implementaion of the money transfer use case. We use the
AccountRepository togeheacountdeailsndchangetheacounts’amounts.We
conti utoe thse
@Transactionalan otia nyoas, ulearnedinchapto13,erwrap
thloe ingc tra sctiona dmasuke wer donme’t wis th deanift oyhf oe perationsfail.
Listing 14.7
Implement ing t he t ransfer money use case
@Service
public class TransferService {
private final AccountRepository accountRepository;
public TransferService(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
318
CHAPTER 14
Implementing data persistence with Spring Data
}
@Transactional
public void transferMoney(
long idSender,
long idReceiver,
BigDecimal amount) {
We wrap the use case logic in a transaction to
avoid data inconsistencies if any instruction fails.
Account sender =
accountRepository.findById(idSender)
.orElseThrow(() -> new AccountNotFoundException());
Account receiver =
accountRepository.findById(idReceiver)
.orElseThrow(() -> new AccountNotFoundException());
BigDecimal senderNewAmount =
sender.getAmount().subtract(amount);
BigDecimal receiverNewAmount =
receiver.getAmount().add(amount);
We get the sender
and receiver’s
account details.
We calculate the new account amounts
by subtracting the transferred value
from the sender account and adding it
to the destination account.
accountRepository
.changeAmount(idSender, senderNewAmount);
accountRepository
.changeAmount(idReceiver, receiverNewAmount);
We change the
accounts’ amounts
in the database.
}
}
In the transfer money use case, we used a simple runtime excption clas named
AccountNotFoundException . The next code snip et presnts the definton of this
clas:
public class AccountNotFoundException extends RuntimeException {
}
Let’s ad a servic method to retiv al the rcods from the datbse and get he
acoundt ebails thy oe wner’s amWee. u’l thse oe perationwhs entsinog uapr .
To get al recods, we di n’t write the method oursevl. Our
inherits the
fol winglistng.
AccountRepository
findAll() method from the
Listing 14.8
CrudRepository contrac, as shown in the
Adding service met hods t o ret rieve account det ails
@Service
public class TransferService {
// Omitted code
public Iterable<Account> getAllAccounts() {
return accountRepository.findAll();
AccountRepository inherits this
method from the Spring Data
CrudRepository interface.
Using Spring Data JDBC
319
}
public List<Account> findAccountsByName(String name) {
return accountRepository.findAccountsByName(name);
}
}
Thefol winglistngshowsyouhowthe
transferucathroughaRESTendpoint.
Listing 14.9
AccountController clasexposethemoney
Exposing t he t ransfer money use case wit h a REST endpoint
@RestController
public class AccountController {
private final TransferService transferService;
public AccountController(TransferService transferService) {
this.transferService = transferService;
}
We get the sender and destination
account IDs and the transferred
@PostMapping("/transfer")
amount
in the HTTP request body.
public void transferMoney(
@RequestBody TransferRequest request
) {
transferService.transferMoney(
We call the service to execute
request.getSenderAccountId(),
the money transfer use case.
request.getReceiverAccountId(),
request.getAmount());
}
}
The next code snip et presnts the
/transferndponi tuseomaptheHTTPrequestbody:
TransferRequest DTO implementaion the
public class TransferRequest {
private long senderAccountId;
private long receiverAccountId;
private BigDecimal amount;
// Omitted getters and setters
}
Inthne lixstnweg, implemenat endpointofecht recodfros mthde atbse.
Listing 14.10
Implementing an endpoint t o retrieve account det ails
@RestController
public class AccountController {
320
CHAPTER 14
Implementing data persistence with Spring Data
// Omitted code
We use an optional request parameter
to get the name for which we want to
return the account details.
@GetMapping("/accounts")
public Iterable<Account> getAllAccounts(
@RequestParam(required = false) String name
If no name is provided in the
) {
optional request parameter, we
if (name == null) {
return all the account details.
return transferService.getAllAccounts();
} else {
If a name is provided in the
return transferService.findAccountsByName(name);
request parameter, we only
}
return the account details
}
for the given name.
}
Westar heap licatonandcheckthecaountrecodsbycalingthe/acountsendpoint,whichretunsalcountsi hedatbse:
curl http://localhost:8080/accounts
Once you run this command, you should find an output in the console imilar to he
oneprsntedinthenextsnip et:
[
{"id":1,"name":"Jane Down","amount":1000.0},
{"id":2,"name":"John Read","amount":1000.0}
]
We cal the /transfer endpoint to transfer $10 from Jane to John using the cURL
commandshowni thenxtsnip et:
curl -XPOST -H "content-type:application/json" -d '{"senderAccountId":1,
➥ "receiverAccountId":2, "amount":100}' http://localhost:8080/transfer
Ifyoucalthe/acountsendponi tgain,youshouldobrvesthedifrence.Afterhe
moneytransferoperation,Janehasonly$90,whileJohn owhas$1,0:
curl http://localhost:8080/accounts
The result of caling the /acounts endpoint after the money atnr sfer operation is
presntedinthenextsnip et:
[
{"id":1,"name":"Jane Down","amount":900.0},
{"id":2,"name":"John Read","amount":1100.0}
]
Youcanalsorequestose onlyJane’sacountsifyou sethenamequeryparmetr
withthe/acountsendpoint,asprentedinthenxtsnip et:
curl http://localhost:8080/accounts?name=Jane+Down
Summary
321
Aspresntedinthne sxt ip inet, hresponbse odfoy thr cUis RLcommandyo, u’l
onlygetJane’sacounts:
[
{
"id": 1,
"name": "Jane Down",
"amount": 900.0
}
]
Summary
SprinDag Spaits rnecog ystmprothjec at elpus moearsilymplemenat
Spring ap ’s peristnce layer. Spring Data provides an abstrcion layer over
multipe rsitencethnol giesandfaciltesheimplementaionbyprovidingacommonsetofc ntracs.
With Spring Data, we implement reposit re through interfacs that extnd
standar SpringDatacontracs:
– Repository , whichdoesn’tprodvi eanypersitnceoperation
– CrudRepository , which provides simple
(CRUD)operations
– PagingAndSortingRepository , which extnds
operationsforthepaginationandsortingoftheftchedrcods
When using Spring Data, you cho se a certain module acording to the persitence technol gy your ap use. For exampel, if your pa con ects to the
DBMS through JDBC, your ap neds the Spring Data JDBC moduel, while f
yourap useaNoSQLimpelmentaionsuchasMongoDB,itnedstheSpring
DataMongomodule.
When extnding a Spring Data contrac, your ap inherits and can use the
operations defined by that contrac. Howevr, your ap can define custom
operationswithmethodsintherposit rynterfacs.
You use the
@Query an otai n with the Spring Data reposit ry method to
definetheSQLqueryourap excutsforhatspecifoperation.
If you declar a method and don’t explicty specify a query with the
an otai n, Spring Data wil translate the method’s name into a SQL query.
The method name neds to be defined based on Spring Data rules to understand and translate it into the coret query. If Spring Data can ot solve the
methodname,theap licatonfailstorndthrowsanexcption.
It is prefabl to use the
@Query an otai n and avoid relying on Spring Data
to translate the method name into the query. Using the name translation
ap roachouldcomewithdifcultes:
– It creaslong and difcult-oread method namesformore complex operations,whichafectheap ’smaintainabilty.
CREATE , READ , UPDATE , DELETE
CrudRepository and ad s
@Query
322
CHAPTER 14
– sloIt wds ownthape ins’ tialzonbcaeuths ape nedns owtoals rnslatehemethodnames.
– YounedtolearntheSpringDatamethodnameconvention.
– Itrunstheriskofactngtheap ’sbehaviorbyanincoretfa rofthe
methodname.
Any operation that changes dat (e.g, excuts
queris) must be an otaed with the
Datahatheoperationchangesdatrecods.
Implementing data persistence with Spring Data
INSERT , UPDATE , or
@Modifying an otai n to instruc Sprni g
DELETE
TestingyourSpa
This chapter covers
Why testing apps is important
How tests work
Implementing unit tests for Spring apps
Implementing Spring integration tests
Inthcis apyoter, ulean’ toimplemenfotsyr uSpr inapg As. maiste al
piecofl gicwhosepurposeit valdtehatps ecifapbiltyourap implementsworksaexpctd.We’lcasfiythe tesintowocateg ris:
Unites —Focusonlyona isolatedpiecofl gic
Integraio tes —Focus on validtng tha multipe compone ts coretly
interacwitheachother
ButwhenIonlyusethetrm“tes,”Irfoboththescatgori.
Test are sntial for any ap licaton. They nsure that he changes we make
durni g the ap ’s devlopment proces don’t break xistng capbiltes (or at les
they make eros les likey) and also serv as documentaion. Many devlopers
(unfortunately) disrega tes bcause theyar notdirectly part ofthe ap ’s busines logic, and, of course, it akes ome time to write hem. Because of th,is tes
323
324
CHAPTER 15
semtonothavesignifcantimpact.Inde ,theirmpactisnotus alyvibenthe
short em, but rust me, tes ar invaluble in the long term. I can’t sre nough
howimportantisomakesuryouproperlytsourap ’slogic.
Whyshouldyouwriteasnsteadof relyingonmanualytesingacpbilty?
Because you can run that es over and over agin to validte hings are working as expctd with minimum efort (validtes the ap behaves coretly
continuously)
Because by reading the tes step you can easily understand the ues-ca purpose(rvadocumentaion)
Because tes provide early fedback about new ap licaton isue during the
devlopmentproces
Whywouldn’theap ’scapbiltesworkasecondtimeiftheyintialyworked?
Because we conti uously change the ap ’s ource ode to fix bugs or ad new
featurs.Whenyouchangethesourceode,youmightbreakpreviouslyimplementedcapbiltes.
yoIf uwritesfohr osecapbiltes,youcanrunthemantmyi eyouchantgehap
tovalidtehingsaretilworkingasexpdct .Ifyouafectdsomexistngfunctionalityo, u’dfindoutwhathp endbefodr elivnyog urcodetoproduction.Regrssionteg heap roachofc ntasntlyesingexistngfunctionalityovdateisl
workscoetly.
Ago dap roachismakingsureyoutes al herlvantscenariosf ranyspecif
capbitlyouimplement.Youcanthenrunthetsanytimeyouchangesomething
tovalidthe previouimsly plementedcapbweiltes nre oafectdbyouchr anges.
Today, we don’t rely only on devlopers un ing the ts manualy, but we make
their excution part of the ap ’s build por ces. Generaly, devlopment teams use
what we cal contius integrao (CI) ap roach: they configure a to l such as JenkinsoTer amCityorunba uildprocesvytimdea vlopermakcehs anges.Acontinuous integraion to l is oftware we use to excut he stp ned to build and
sometimes instal the ap s we implement during the devlopment proces. This CI
to lasorunsthetsandnotifeshedevlopersifomethinghasben broken(figure15.)
In section 15., we star by drawing a big picture of what unit es i and how it
works. In section 15,.2 we discu the two most encounterd types of tes you’l find
used with Spring pa s: unit and integraion tes. We’l take xmples of capbiltes
weimplementdhroughouthisbo kandimplementesforhem.
Before dinv g dep into this chapter, I’d like to make you aware tha tesing is a
complex subject, and we’l focus only on the esntial knowledg you ned to have
whentsi Spg rinapg Bus. tesinuag bjethc dat oesirv wnbo kshrecI-lf.
ommend you alsored thebo k JUnitAction(M˘ linTuan d˘ intaosge,20) byCa
whichrevalsmoretsingjamths atyou’lfindvaluble.
Testing your Spring app
Writing correctly implemented tests
2. A continuous integration tool
like Jenkins runs the tests.
1. The developer uploads code
to the GIT repository.
GIT
TEST 1 passed
TEST 2 passed
TEST 3 failed
Jenkins
3. If a test is failing, Jenkins
notifies the developer.
Figure 15.1 A CI tool, such as Jenkins or TeamCit y, runs t he test s every t ime a
developer changes t he app. If any of the t ests fail, the CI tool not ifies t he developers
to check which capability doesn’t work as expect ed and correct the problem.
15.1 Writing correctly implemented tests
In this section, we discu how tes work and what a coretly implementd tes is.
Youlearn’ howtowryoite uapr co’s dtoematoaensyi,k dyouo’l bthserv at
ther’satongcon ectionbtwe enmakingtheap tesablndmakingitmainta able (i., easy to change to implement new featurs and coret eros). Testabily
and maintainabilty are software qualites tha help one another. By designi g your
ap tobetsa l,youalsohelptomakeitmaintainable.
Wewrtoesivaldthe loimgc plementedbspaymeecif thodinthpe roject
works in the desir way. When you tes a givn method, us aly ou ned to validte
multipe scenarios (ways in which the ap behaves depnding on difernt inputs).
For each scenario, y u write a s method in a tes cl. In a Maven project (such as
thexamplesweimplementdthroughouthebo k),youwritehetscla inthe
project’sf lder(figu15.2)
A tes clas hould focus only on a particul method whose logic you tes. Even
simple ogic enerats vious cenarios. For each scenario, you’l write a method in
thetsclahatvlideshatspecifas.
Let’s take an example. Remember the money transfer use case we discued in
chapters 13 and 14? This was our simple implementaoi n of transfering a given
amountbewentwodiferntacounts.Theuscahadonlyfourstep:
1
2
3
4
Fni dthesourceaountdeailsnthedatbse.
Findthedstinationacountdeailsnthedatbse.
Calcuatehenwamountsforhetwoac untsaferhetransfer.
Updateheacounts’amountvaluesinthedatbse.
325
326
CHAPTER 15
Testing your Spring app
In your Maven project
main folder, you write
the app’s source code.
In your Maven project
test folder, you write
the test classes.
Figure 15.2 In a Maven project , you writ e
the t est classes in t he project ’s test folder.
Evenwithonlythestp,wecanstilfndmultipescnarioselvntforesing:
Testwhathap ensiftheap cantf’i dthesourceaountdeilsa.
2 Testwhathap ensiftheap canf’it dthedstinaonacountdeails.
3 Testwhathap ensifthesourceaountdoesn’thavenoughmoney.
4 Testwhathap ensiftheamountsupdatefi.ls
5 Testwhathap ensifltha estpworkfine.
Foreachtescnario, y u nedtounderstandhow the ap should behave nd write
ates methodto validtei works a desir .For example,if or tes ca 3, you don’t
wantoal watrnsfertohap enifthesourceaountdoesn’thavenoughmoney,
you’l tes hat he ap throws a specif xception and the tarnsfer doesn’t hap en.
But depnding on the ap ’s requirements, you could alow a defined credit lmit for
thsoe uarceounIt. suchyoase, utenrs edtos akehlims int oc nsideraton
aswel.
The ts cenario implementaion is trongly reatd to how the ap should work,
but technicaly, the idea is the same in any ap : you identify the tes scenarios, and you
writeasmethodforeach(figure15.3)
Acritalhingto bservithatwecanfindmultiperlvantescnarios,evn
for a smal method—another reason to kep the methods in your ap licaton smal! If
you write larg methods with many code lines and parmetrs hat focus on multipe
things imultaneously, identifyng the rlvant es cnario becomes xtrmely difcult. We say tha the ap ’s tesabily decras when oy u fail to separt the difernt
responsibltentosmalndeasy-tordmethods.
1
Implementing tests in Spring apps
327
In a Maven project, the app source
code belongs to the main folder.
project/main
TransferController
TransferService
AccountRepository
transferMoney()
project/test
TransferMoneyTests
We write the tests in the
Maven project’s test folder.
testCase1()
testCase2()
testCase3()
...
For a method we test, we
write various test scenarios.
For each test scenario, we
implement a test method
in a test class.
Figure 15.3 For any piece of logic you t est, you need t o find t he relevant test scenarios. For each
test scenario, you write a test method in a t est class. You add t he test classes in t he app’s Maven
project test folder. In t his figure, t he TransferMoneyTests class is a t est class t hat contains t he
test scenarios for t he transferMoney() met hod. TransferMoneyTests defines mult iple t est
case met hods to t est each relevant scenario in t he transferMoney() ’s method logic.
15.2 Implementing tests in Spring apps
In this ecton, we ues two tesing techniques for Spring ap s you often encounter in
real-world projects. We’l demonstrae each technique by considerng a use case we
implementdintheprevious chapters and write hets forit.Thes tchniquesar
(inmypers ctiv)amust-knowforanydevloper:
Writng unit es to validte a method’s .lgic The unit es ar short, fas to excute, and focus on only one flow. Thes t are way to focus on validtng a
smalpiecofl gicbyelminatingalthedpendencies.
Writng Spr integao s validte method’slgican tsiegraon with specif apbltes h framework pvides. Thes t help you make sure your ap ’s
capbiltesworkwhenyou pgrade pendencies.
328
CHAPTER 15
Testing your Spring app
In section 15.2, you’l earn about unit es. We’l discu why unit es ar important dthsepyouconsidwher enwritnuag nates,i dwewr’l coaiteupoleuf nit
tes as examples for use case we implemented in the previous chapters. In section
15.2, you’l earn to implement integraion tes, how thes ar difernt from unit
tes,andhowtheycomplementheunitesnaSpringap .
15.2.1 Implementing unit tests
Inthisecton,wediscu nites.Unitesarmethodsthatcl erinuseca
in specif conditons to validte behaovi r. The unit tes method defines the conditions in which the use ca exuts and validtes he behavior defined by the ap ’s
requirements. They liminate l the depndencies of the capbilty hey ts, coveringonlyaspecif,solatdpiecofl gic.
Unvaltuesri ble cauwhse enonfayiolse, uknowsomethinwrsg onwig tha
particupl oiec f dane, dyoush’re ownwhexactly yoer unedtoc Air.et unit
t e s i l k e o n e o f y o u r c a r ’ s d a s h b or a d i n d i c a t o r s . I f y o u t r y s t a i n g y o u r c a r n d i t
failstor,mightbe causeyouranoutofgas ryourbateyisn’tworkingproperly.Acarisomplexsytm(sameasnp ),na dyouhavenocluewhatheproblemisunleosy uhaveni dicatohIfr. eca’sindicatorshowyos uo’re uot gafs,hen
youimmediately ntifedheproblem!
Unit es’ purpose i to validte a single unit of logic’s behavior, and like a cr’s
indicators,heyhelpyouidentify problemsinaspecifompone t.
IMPLEMENTING A FIRST UNIT TEST
Let’slo katoneoftheuscawewroteinchapter14:hemoneytransferuscae.
Thestpinthispecofl gicaresol ws:
1
2
3
4
5
Findthesnder’sacountdeails.
Fni dthedstinationacountdeails.
Calcuatehenwamountsforeachacount.
Updatehesnder’sacountamount.
Updatehedstinaionacountamount.
The fol wing listng shows you the use case implementaion as we worked it in the
p ro jec t“sq - h 1 4-e x .”
Listing 15.1
The implement at ion of t he money t ransfer use case
@Transactional
public void transferMoney(
long idSender,
long idReceiver,
BigDecimal amount) {
We find the details of
the sender’s account.
Account sender = accountRepository.findById(idSender)
.orElseThrow(() -> new AccountNotFoundException());
Account receiver = accountRepository.findById(idReceiver)
.orElseThrow(() -> new AccountNotFoundException());
We find the
details of the
destination
account.
Implementing tests in Spring apps
329
BigDecimal senderNewAmount = sender.getAmount().subtract(amount);
BigDecimal receiverNewAmount = receiver.getAmount().add(amount);
We calculate the accounts’ amounts.
accountRepository
.changeAmount(idSender, senderNewAmount);
accountRepository
We update the new amount
in the sender account.
.changeAmount(idReceiver, receiverNewAmount);
}
We update the new amount in
the destination account.
Usualy, the most obvious cenarios and the first we write s for ae thehapy flows:
an excution tha encounterd no excptions or eros. Figure 15.4 visualy represntshe ap yflowof urmoneytransferuca.
One of the scenarios (usually the first one for which we write tests),
is the “ happy flow” : the scenario in which no exception or error occurs.
@Transactional
public void transferMoney(
long idSender,
long idReceiver,
BigDecimal amount) {
Account sender = accountRepository.findById(idSender)
.orElseThrow(() -> new AccountNotFoundException());
Account receiver = accountRepository.findById(idReceiver)
.orElseThrow(() -> new AccountNotFoundException());
BigDecimal senderNewAmount = sender.getAmount().subtract(amount);
BigDecimal receiverNewAmount = receiver.getAmount().add(amount);
accountRepository.changeAmount(idSender, senderNewAmount);
accountRepository.changeAmount(idReceiver, receiverNewAmount);
}
Figure 15.4 The happy flow: an execut ion for which no errors or except ions are encountered.
Usually, the happy flows are t he first to writ e t est s because t hey are the most obvious scenarios.
Let’s write a unit es for thsi hap y flow of the money transfer use ca. Any tes has
thremainparts(figue15.):
1
2
3
Asumptions —Wenedto efina einy puant dfindandy epndenothcyfl egic
we ned to control to achiev the desir flow scenario. For this point, we’l
answtehr foe l winqg uestionwhs: atinputshouldweproivdaen, d howshould
depndencisbehavforthetsdlogict anthespcifwaywewant?
Cal/Execution —Wenedtocalhelogicwetesovalidtesbhavior.
Validtons —We ned to define al the validtons that ned to be done for the
given piec of l gic. We’l answer this question: what should hap en when this
piecofl gicsaedinthegivnconditon?s
330
CHAPTER 15
STEP 1
Defi ne the assumptions.
Before calling the tested method,
decide the input values the method
depends on.
Testing your Spring app
STEP 2
Call the tested method.
STEP 3
Validations
Call the method you test with the
given inputs decided in the
assumptions step.
Write all the checks the tests
need to perform to validate the
tested method executed as
expected, with the inputs given
in the assumptions.
Figure 15.5 The steps for writing a unit test . Write t he assumpt ions by defining the met hod input s. Call t he
met hod with t he defined assumptions and writ e the checks t he t est s need t o perform to validat e t he met hod’s
behavior is correct .
NOTE
Sometimes,you’lfindthesthrestp(asumptions,calndvali -
tions)namedabitdiferntly:“arnge,act ndasert”o“given,when,na d
then.”Regardlesofhowyoupreftonamethem,theidaofhowyouwrite
thetsayhesame.
Inthasue’mtipowens, identhify de pendenfocisthrweae wrthie s
for.Wecho setheinputsandhowthedpendenciesbhavetomakethetsdlogci
actinacertinway.
Which are the depndencies for the money transfer use case? Dependencies are
anythingthemethodusebutdoesn’tcreaislf:
Themethod’sparmetrs
Objectinstancesthemethodusebuthatrenotcreadbyit
Infigure15.6,weidentifyhesdpendencisfor urexample.
Parameters are execution dependencies.
Based on their value, the method
might behave one way or another.
@Transactional
public void transferMoney(
long idSender,
long idReceiver,
BigDecimal amount) {
Other objects external to the method,
but that the method uses to implement
its logic are also execution dependencies.
Based on their behavior, the method
might behave one way or another.
accountRepository.
Account sender = accountRepository.findById(idSender)
.orElseThrow(() -> new AccountNotFoundException());
accountRepository.
Account receiver = accountRepository.findById(idReceiver)
.orElseThrow(() -> new AccountNotFoundException());
BigDecimal senderNewAmount = sender.getAmount().subtract(amount);
BigDecimal receiverNewAmount = receiver.getAmount().add(amount);
accountRepository.
accountRepository.changeAmount(idSender,
senderNewAmount);
accountRepository.
accountRepository.changeAmount(idReceiver,
receiverNewAmount);
}
Figure 15.6 A unit test
validates a use case logic
in isolat ion from any
dependency. To writ e the t est ,
we need t o make sure we
know the dependencies and
how t o control t hem. For our
scenario, t he paramet ers and
the AccountRepository
object are dependencies we
need t o control for the t est .
Implementing tests in Spring apps
331
Whenwecalthemethodtoesi,wecanprovideanyvaluesforithreparmetrs
toc ntrolhexcutionflow.Buthe
AccountRepository instanceisabtmorecomtransferMoney() method excution depnds on how the
findById()
plicated. The
methodofthe
AccountRepository instancebhaevs.
But remember, a unit es focuse on only one piec of l gic, so it should not cal
the
findById() method. The unit tes should asume
findById() works in a given
way and asert hat he tsd method’s excution does what’s expctd for the givn
situaon.
Buthetsdmethodcals
findById() .Howcouldwecontroli?Tocontrolsuch
adepndency,weusemocks:afeobjectwhosebhaviorwecancontrol.Inthiscea,
instead of using the real
AccountRepository object, we’l make sure the tesd
methodusethisfakeobject.We’l take dvantageofc ntrolinghowthisfakeobject
behaves to induce al the difernt excutions of the
transferMoney() method that
wewantoes.
Figure 15.7 shows you what we want to do. We replac the
AccountRepository
objectwithamocktoeliminatehetsdobject’sdpendency.
A unit test only focuses on
testing a certain piece of logic.
To have the test validate only
one component’s logic, we need
to remove all the dependencies.
TransferController
TransferService
transferMoney()
TransferMoneyTests
testCase1()
testCase2()
testCase3()
...
AccountRepository
The logic we test depends
on the AccountRepository.
We eliminate this dependency
by replacing the “ real”
AccountRepository bean
with a “ fake” one whose
behavior we control.
Figure 15.7 To allow t he unit test t o focus only on t he transferMoney() met hod' s logic, we
eliminat e t he dependency to t he AccountRepository object . We use a mock object t o replace
the real AccountRepository inst ance, and we control t his fake inst ance t o t est how t he
transferMoney() method behaves in different sit uations.
332
CHAPTER 15
In listng 15.2, we star implementing the unit est. After cating a new clas in the
Maven’s project s folder, we star implementi g the first e scnario by writng a
newmethodwean otaewithhe
Testing your Spring app
@Test an otai n.
For the xamples in this bo k, we use JUnit 5 Jupiter, he lats JUnit
version, to implement he unit and integraion tes. Howevr, in real-world
ap yos, umighalsotfindJUnu4it sedoftenTh. osi nmoe reasonrecoI mmend you also read bo ks that focus on tesing. Chapter 4 of JUnit Action
(Man ing, ˘20)lin by Tu˘ ta doCase focuse on the difernces betwen
JUnit4andJUnit5.
NOTE
We creat
TransferService instance to cal the
want to tes. Instead of using a real
object that we can control. To creat such a mock object, we use a method named
mock()Th. is
mock()methodpis rovide bday epndency amedMockito( ftenused
withJUnitomplementes).
Listing 15.2
transferMoney() method that we
AccountRepository instance, we creat a mock
Creat ing t he object whose met hod we want t o unit t est
We use the Mockito mock() method to create a
mock instance for the AccountRepository object.
public class TransferServiceUnitTests {
@Test
public void moneyTransferHappyFlow() {
AccountRepository accountRepository =
mock(AccountRepository.class);
TransferService transferService =
new TransferService(accountRepository);
We create an instance of the
TransferService object whose
method we want to test. Instead of
a real AccountRepository instance,
we create the object using a mock
AccountRepository. This way, we
replace the dependency with
something we can control.
}
}
We can now specify how the mock object should behaev, then cal the tsd method
andproveitworksaexpctdinthegivnconditons.Youcontrolhemock’sbehavior using the
given() method, as hown in listng 15.3 Using the
you tel he mock how to behav when one of its methods i caled. nI our case, we
want the
AccountRepository ’s
instanceforagivnparmetrvalu.
.
NOTE Inarel-worldap ,ago dpractiesungthe
tiontodescribthetscnario(sy useinthenextlisng).Inourexamples, I to k out the
focuos nthloes gHoic. wuevr, sintg real-worldap canhelpyoub, ut
also other devlopers on the team, betr understand the implemented tes
scenario.
given() method,
findById() method to retun a specif
Account
@DisplayName an ota-
@DisplayName an otai n to save space and alow you
Implementing tests in Spring apps
Listing 15.3
333
A unit t est validat ing the happy flow
We control the mock’s findById() method to return the sender account instance when
it gets the sender account ID. You can read this line as “ If one calls the findById()
method with the sender ID parameter, then return the sender account instance.”
public class TransferServiceUnitTests {
@Test
@DisplayName("Test the amount is transferred " +
"from one account to another if no exception occurs.")
public void moneyTransferHappyFlow() {
AccountRepository accountRepository =
mock(AccountRepository.class);
TransferService transferService =
new TransferService(accountRepository);
Account sender = new Account();
sender.setId(1);
sender.setAmount(new BigDecimal(1000));
We create the sender and the destination
Account instances, which hold the Account
details, which we assume the app would
find in the database.
Account destination = new Account();
destination.setId(2);
destination.setAmount(new BigDecimal(1000));
given(accountRepository.findById(sender.getId()))
.willReturn(Optional.of(sender));
given(accountRepository.findById(destination.getId()))
.willReturn(Optional.of(destination));
transferService.transferMoney(
sender.getId(),
We call the method we want
destination.getId(),
to test with the sender ID,
new BigDecimal(100)
destination ID, and the value );
to be transferred.
}
We control the mock’s findById()
method to return the destination
account instance when it gets the
destination account ID. You can read
this line as “ If one calls the findById()
method with the destination ID
parameter, then return the
destination account instance.”
}
Theonlythingwestilnedtodoistelhe tswhatshouldhap enwhenthetsd
method excuts. What do we expct? We know this method’s purpose i to transfer
the money from one givn acount o another. So, we expct hat i cals the rpository instance to change the amounts with the right values. In listng 15.4, we ad the
itens ructionths vearithfy mee thodcorealtydhreposit rny stancmee’s thodstochangetheamounts.
Tovemoiafyr cok’s bjet’scmethodhabs encaled,you seth
asprentedinthefol winglistng.
verify()method,
334
CHAPTER 15
Listing 15.4
Testing your Spring app
A unit t est validat ing the happy flow
public class TransferServiceUnitTests {
@Test
public void moneyTransferHappyFlow() {
AccountRepository accountRepository =
mock(AccountRepository.class);
TransferService transferService =
new TransferService(accountRepository);
Account sender = new Account();
sender.setId(1);
sender.setAmount(new BigDecimal(1000));
Account destination = new Account();
destination.setId(2);
destination.setAmount(new BigDecimal(1000));
given(accountRepository.findById(sender.getId()))
.willReturn(Optional.of(sender));
given(accountRepository.findById(destination.getId()))
.willReturn(Optional.of(destination));
transferService.transferMoney(
sender.getId(),
destination.getId(),
new BigDecimal(100)
);
verify(accountRepository)
.changeAmount(1, new BigDecimal(900));
verify(accountRepository)
.changeAmount(2, new BigDecimal(1100));
}
}
Ifyour nthetsnow(us layinna DI Ebyright-clikngonthetsclandselcting the “Run tes” option), you should observ the tes suced. When a tes succeds, the IDE display them in gren, and the console doesn’t show any excption
mesage. If a tes fails, it’s us aly displayed in either red or yelow in an IDE (figure 15.8)
Even if you find, in many case, the
method, as presnted in slitngs 15.2 through 15.4, I us aly pref a difernt
ap roachtocrhea moock bjenItc’s. ont ecsabrily tomor ore ftnusedb, ut
coI nsidcleantr wae toyuanse otai ntoscreha moanck dthesdobject,
asprentedinltins g15.
mock() method being declar insde the
Verify that the changeAmount()
method in the AccountRepository was
called with the expected parameters.
Implementing tests in Spring apps
335
In any IDE, a simple way to
run a test suite is to right-click
on the test class and select “ Run.”
The IDE displays the results
as shown in this image. A green
check means the test passed.
If the IDE displayed a red or
yellow X, it means the tests
failed. When a test fails, you
can check the app’s console to
find out more about the reason
it failed.
Figure 15.8 Running a t est. An IDE usually offers several ways you can run a test . One of t hem is t o
right -click on t he test class and select “ Run.” You can also run all the project t ests by right-clicking on
the project name and select “ Run t est s.” Different IDEs might have slightly different graphical interfaces,
but they all look similar to what you see in t his figure. After running t he t est s, t he IDE shows t he stat us
for each test .
336
CHAPTER 15
Listing 15.5
Testing your Spring app
Using annotat ions for mock dependencies
Use the @Mock annotation to create a
mock object and inject it into the test
class’s annotated field.
Enable the use of @Mock and
@InjectMocks annotations.
@ExtendWith(MockitoExtension.class)
public class TransferServiceWithAnnotationsUnitTests {
@Mock
private AccountRepository accountRepository;
@InjectMocks
private TransferService transferService;
@Test
public void moneyTransferHappyFlow() {
Account sender = new Account();
sender.setId(1);
sender.setAmount(new BigDecimal(1000));
Use the @InjectMocks to create
the tested object and inject it into
the class’s annotated field.
Account destination = new Account();
destination.setId(2);
destination.setAmount(new BigDecimal(1000));
given(accountRepository.findById(sender.getId()))
.willReturn(Optional.of(sender));
given(accountRepository.findById(destination.getId()))
.willReturn(Optional.of(destination));
transferService.transferMoney(1, 2, new BigDecimal(100));
verify(accountRepository)
.changeAmount(1, new BigDecimal(900));
verify(accountRepository)
.changeAmount(2, new BigDecimal(1100));
}
}
Observ how, instead of declaring thes objects inside the ts method, I to k them
outasheclasprmetrsandan otaedthemwith
@Mock and
@InjectMocks .When
yo u se th e
@Mock an otai n,theframeworkceatsndinjectsamockobjectinthe
@InjectMocks an otai n,youcreat heobject otes and
an otaed atribute.With
instrucheframeworkt injectalhemocks(reatdwith
@Mock )intsparmetrs.
For the
@Mock and
@InjectMocks an otai ns to work, you also ned to an otae
@ExtendWith(MockitoExtension.class) an otai n. When
the tes clas with the
an otani g the clas this way, you enable an extnios n that laows the framework to
readthe
@Mock and
@InjectMocks an otai nsa dcontrolhean otaedfil s.
Implementing tests in Spring apps
337
Figure1s5.9 mmarizesthetswebuilt.Inhisvual,youfindthespandcode
wewrote solveachofthestpweenumeratdwhenwestaredwritngthets:
1
2
3
Asumptions —Enumeratndcontrolhedpendencies.
Cal —Executhetsdmethod.
Validtons —Verifythexcutdmethodhadthexpctdbehavior.
@ExtendWith(MockitoExtension.class)
public class TransferServiceWithAnnotationsUnitTests {
@Mock
private AccountRepository accountRepository;
@InjectMocks
private TransferService transferService;
@Test
public void moneyTransferHappyFlow() {
Account sender = new Account();
sender.setId(1);
sender.setAmount(new BigDecimal(1000));
Account destination = new Account();
destination.setId(2);
destination.setAmount(new BigDecimal(1000));
given(accountRepository.findById(sender.getId()))
.willReturn(Optional.of(sender));
given(accountRepository.findById(destination.getId()))
.willReturn(Optional.of(destination));
transferService.transferMoney(1, 2, new BigDecimal(100));
verify(accountRepository).changeAmount(1, new BigDecimal(900));
verify(accountRepository).changeAmount(2, new BigDecimal(1100));
}
}
Figure 15.9 The main parts of the t est implement at ion. (1) Define and control
the dependencies, (2) execut e the t ested met hod, and (3) verify the method
behaved as expect ed.
WRITING A TEST FOR AN EXCEPTION FLOW
Remember tha hap y flows are not he only ones you ned to tes. You also want o
know tha the method excuts in the desir way when it encounters an excption.
Suchfloa wclaedis nexcptionflwIn. ouexamr panle, xcptionflowcouldhap en
if etherthesndero the destination acountdetails r notf undforthe givn DI ,
asprentedinfigure15.0
Listing15.6showsyouhowtowriteheunitesforanexcptionflow.Ifyouwant
to check tha the method throws an excption, you use
the xcption you expct he method wil throw and specify the tsd method. The
assertThrows() . You specify
338
CHAPTER 15
Testing your Spring app
The happy flow is not the only one our tests should cover.
We need to identify all the executuion scenarios that are
relevant to our use case and implement tests to validate
the app’s behavior. For example, what can we expect if
the receiver account details cannot be fetched? In this case,
we expect the app to throw a specific exception.
@Transactional
public void transferMoney(
long idSender,
long idReceiver,
BigDecimal amount) {
Account sender = accountRepository.findById(idSender)
.orElseThrow(() -> new AccountNotFoundException());
Account receiver = accountRepository.findById(idReceiver)
.orElseThrow(() -> new AccountNotFoundException());
BigDecimal senderNewAmount = sender.getAmount().subtract(amount);
BigDecimal receiverNewAmount = receiver.getAmount().add(amount);
accountRepository.changeAmount(idSender, senderNewAmount);
accountRepository.changeAmount(idReceiver, receiverNewAmount);
}
In such a scenario where fetching the receiver account
details fails, the calculations of the new amounts and
the accounts’ update should no longer happen.
Figure 15.10 An except ion flow is an execution t hat encount ered an error or an
exception. For example, if t he receiver account details were not found, t he app should
throw an AccountNotFoundException , and t he changeAmount() method should
not be called. Except ion flows are import ant as well, and we need to implement test s
for t hese scenarios t he same as we do for happy flows.
assertThrows() method cals the tesd method and validtes that it throws the
expctdexption.
Listing 15.6
Test ing an except ion flow
@ExtendWith(MockitoExtension.class)
public class TransferServiceWithAnnotationsUnitTests {
@Mock
private AccountRepository accountRepository;
@InjectMocks
private TransferService transferService;
@Test
public void moneyTransferDestinationAccountNotFoundFlow() {
Account sender = new Account();
Implementing tests in Spring apps
339
sender.setId(1);
sender.setAmount(new BigDecimal(1000));
given(accountRepository.findById(1L))
.willReturn(Optional.of(sender));
given(accountRepository.findById(2L))
.willReturn(Optional.empty());
We control the mock AccountRepository
to return an empty Optional when the
findById() method is called for the
destination account.
We assert that the method throws
an AccountNotFoundException in
the given scenario.
assertThrows(
AccountNotFoundException.class,
() -> transferService.transferMoney(1, 2, new BigDecimal(100))
);
verify(accountRepository, never())
.changeAmount(anyLong(), any());
}
We use the verify() method with the
never() conditional to assert that the
changeAmount() method hasn’t been
called.
}
TESTING THE VALUE A METHOD RETURNS
Anoften encounterdcaseinedingtocheckthevalueamethodretuns.Thenext
listnhg owmeas thodweimplementedinchapin9te,r hpe ro“sjeqct -h9-eHox1.” w
wouldyouimplemenuat ntfeois hr meis thodco, nsidernyog unedtoehs cenariowhertheusrpovidesthecortdentialso gin?
Listing 15.7
The implement at ion of t he login cont roller act ion we want t o unit test
@PostMapping("/")
public String loginPost(
@RequestParam String username,
@RequestParam String password,
Model model
) {
loginProcessor.setUsername(username);
loginProcessor.setPassword(password);
boolean loggedIn = loginProcessor.login();
if (loggedIn) {
model.addAttribute("message", "You are now logged in.");
} else {
model.addAttribute("message", "Login failed!");
}
return "login.html";
}
Youfol wthesamestpyoulearnedinthisecton:
1
2
3
Identifyandcontrolhedpendencies.
Calthetsdmethod.
Verifythestdmethodexcutionbehavedsxpectd.
340
CHAPTER 15
Listing 15.8 shows the unit es mplementaion. Observ tha we mocked the depndenwhcies boehs weaviorwancot hverifyo:t l
oWebjects. inthsruce
toasuminthugpesrovidethcordet na tils), dwethmecal e thodwewant
toes.
Weverifythefol wing:
Testing your Spring app
Modelandthe
That he method retuned the string “loni .html.” We use an asert method to
validte he method retuned a vlue. As hs own in listng 15.8, we can use the
assertEquals() method,whichomparesnexpctdvaluewithhevaluthe
methodretuned.
The
Model instancoe ntaintshvealidmesa“gYoe unare owlogedinWe.” use
the
verify() method to validte the
instancehasbencaledwith ecortvaluesparmetr.
Listing 15.8
LoginProcessor
LoginProcessormoretuo(wbnckjet hquicshvalent
addAttribute() method of the
Model
Test ing t he ret urned value in a unit t est
@ExtendWith(MockitoExtension.class)
class LoginControllerUnitTests {
@Mock
private Model model;
@Mock
private LoginProcessor loginProcessor;
@InjectMocks
private LoginController loginController;
@Test
public void loginPostLoginSucceedsTest() {
given(loginProcessor.login())
.willReturn(true);
String result =
We define the mock
objects and inject them
into the instance whose
behavior we test.
We control the LoginProcessor mock
instance, telling it to return true
when its method login() is called.
loginController.loginPost("username", "password", model);
We call
the tested
We verify the tested
method with
method returned value.
assertEquals("login.html", result);
the given
assumptions.
verify(model)
.addAttribute("message", "You are now logged in.");
}
}
Bycontrolinhg e pu(thps earmvluanetrs dhowthmoe obck jeths yoavue),
can also tes what hap ens in difernt scenarios. In the next listng, we make the
LoginProcessormoockbjet’s
iftheloginfails.
login()methodretuwhosnfale woat uldhap en
We verify the message
attribute was added
with the correct value
on the model object.
Implementing tests in Spring apps
Listing 15.9
Adding t he t est t o validat e t he failed login scenario
@ExtendWith(MockitoExtension.class)
class LoginControllerUnitTests {
// Omitted code
@Test
public void loginPostLoginFailsTest() {
given(loginProcessor.login())
.willReturn(false);
String result =
loginController.loginPost("username", "password", model);
assertEquals("login.html", result);
verify(model)
.addAttribute("message", "Login failed!");
}
}
15.2.2 Implementing integration tests
Inthisecton,wediscuintegraiontes.Anintegraiontes ivrymilartoaunit
tes. We’l evn conti ue writng them with JUnit. But instead of ocusing on how a
particul component works, an integraion tes focuse on how two r more compone tsinterac.
Remembther anlowigy th cadre’s hboardindicatohIf?rs cate’nfuisk l,
busot methinbg reakins thgadse itrbutionbetwenthaenk dthengineth, caer
wostil nUnstar’. fortunthay,el ims the ingas dicatowor nsh’t owyousomethinsg
wrong becaus the tank has enough gas, nd as n isolated component, i works correctly. In such a case, we don’t know why the car doesn’t work. The same problem
might hap en to an ap . Even if some compone ts work coetly when they ar isolatedone from another,theydon’t coretly“ak” o eachother.Writngintegraion
tes helps us mitigae problems that could hap en when compone ts work coetly
indepndentlybutdon’tcommunicateorly.
Wethak’el smexampwele usedfothr ue nfteosi hr examis pthle: money
transferucaweimplementedinchapter14( oject“sq-h14-ex”).
Whatkindofni tegraionscanwetes?Wehavefwposiblte:
Integraiobwentw(ormoore)bjcytsfuapTe. stingthta eobjeincts eract
corehtly pyos uidenptify roblemins howthecyolaboyrifate uchangoe ne
ofthem.
Integraio f n objectfyurap with somecapbilty h frmework enhacs it with .
Testing how an object interacs with some capbilty the framework provides
helps you identify sue that cn ocur when you upgrade the framework to a
new version. The integraion tes helps you immediately identify something
changed in the framework and the capbilty he object rlis on doesn’t work
thesameway.
341
342
CHAPTER 15
Testing your Spring app
Inetgraio fhpwithspernclay(thdbse).Testing howtherpository works with the datbse nsure you quickly dentify problems that might
ocur when upgrading or changin a depndency that helps your ap work
withpersitd at(suchastheJDBCdrive).
An integraion tes lo ks very similar to a unit es. You stil fol w the same stp of
identifyntgheasumptioncsa,lintghestdmethoda,ndvali tntghresultTh. e
difernceisthatnowthetsdoens ’tfocusona isolatedpiecofl gic,soy udon’t
necsarily have to mock al the depndencies. You might alow a method you tes o
cal another’s real object’s (not a mock’s) method becaus you want o tes the two
objects communicate coretly. So, if for a unit tes it was mandatory to mock the
reposit ry,foanintegraionteshatisnol ngermandatory.Y ucanstilmockitf
thesytouwridte oesnc’atrebouht owthservicnteracswith at reposit rby, ut
if you want o tes how thes two objects ommunicate, you can let he ral object be
caled(figure15.)
An integration test might verify
how two objects interact.
TransferController
TransferService
transferMoney()
TransferMoneyTests
testCase1()
testCase2()
testCase3()
...
AccountRepository
If, for a unit test, there was
mandatory mocking of the
repository, for an integration
test the decision of mocking
the object depends on the
test’s purpose.
Figure 15.11 In a unit t est ’s case, all the dependencies needed to be mocked. If t he integrat ion test’s
purpose is t o verify how t he TestService and AccountRepository int eract, the reposit ory can be
the real object. An int egrat ion test can st ill mock an object if it s purpose doesn’t verify t he int egrat ion
wit h a specific component .
If you deci not to mock the reposit ry in an integraion tes, you
should use an in-memory datbse such as H2 instead of the real datbse.
Thiswilhelpyoukepyourtesindepndentofheinfrastuc rethatruns
the ap . Using the ral datbse could cause latncies n tes xcutions and
evn make ts fail n case of infrastuc re or networking problem.s Since
you tes he ap licaton and not he infrastuc re, you should avoid al this
trouble yusingamockin-memorydatbse.
NOTE
Implementing tests in Spring apps
WithSpa rinapg yo, ugen’l ueray ins tegraiontoeshvrify oat upr b’s ehavior coretly interacs with the capbiltes Spring provides. We name such a tes a
“Spring integraion tes.” Unilke a unit es, an integraion tes nables Spring to createhebansndconfigurethecontex(jusaitdoeswhenrun ingtheap ).
Listing15.0showsyouhowsimpleitso transformaunitesntoaSpringintegration tes. Observ that we can use the
object in our Spring Boot ap licaton. This an otai n is quite similar to the
an otai n we used for unit es, but i also makes ure the mock object is ad ed to
the ap licaton contex. This way, ou can simply use
chapter3)oinjectheobjectwhosebhaviory utes.
Listing 15.10
343
@MockBean an otai n to creat a mock
@Mock
@Autowired (as you learned in
Implementing a Spring int egrat ion t est
@SpringBootTest
class TransferServiceSpringIntegrationTests {
Create a mock object that is also
part of the Spring context.
@MockBean
private AccountRepository accountRepository;
@Autowired
private TransferService transferService;
Inject the real object from the Spring
context whose behavior you’ll test.
@Test
void transferServiceTransferAmountTest() {
Account sender = new Account();
sender.setId(1);
sender.setAmount(new BigDecimal(1000));
Account receiver = new Account();
receiver.setId(2);
receiver.setAmount(new BigDecimal(1000));
Define all the
assumptions
for the test.
when(accountRepository.findById(1L))
.thenReturn(Optional.of(sender));
when(accountRepository.findById(2L))
.thenReturn(Optional.of(receiver));
transferService
.transferMoney(1, 2, new BigDecimal(100));
verify(accountRepository)
.changeAmount(1, new BigDecimal(900));
verify(accountRepository)
.changeAmount(2, new BigDecimal(1100));
}
}
Call the tested method.
Validate the tested
method call has the
expected behavior.
344
CHAPTER 15
NOTE
The
plain Spring ap and not a Spring Boot one as presnted her, you won’t be
abtole use
taing the configuraton clas with
Anexampleusingthisan otai nisntheproject“sq-h3-ex1.”
@MockBean an otai n is a Spring Boot an otai n. If you have
@MockBean Ho. wevyor, ucanustil he samape roachbany o@ExtendsWith(SpringExtension.class) .
Your nthetshesamewayoudof ranyotherts.Howevr,niftlo ksvery
similatrountiesS,prng owknowths etsdobjeactndmanagesitwouldin
arun ingap .Forexample,ifweupgrade theSpringversionand,fors merason,
thdepndeni cyjeoti nlonwoger workedths, e weuvenifdla nch’t ange
anything in the tsd object. The same ap lies to any capbilty Spring ofers to the
tesdmethodtra:nsctionalisety,curhinag, dso nYo. uwouldbae tol s
yourmethod’sintegraiontoanyofthescapbilteshemethoduseinyourap .
NOTE
Testing your Spring app
In a real-world ap , use unit tes to validte components’ behavior
and the Spring ni tegraion tes o validte he necsary integraion scenarios. Even if a Spring integraion tes could be used to validte the compone t’sbehavior (mpeml entlahetscnariosf rthe method’slogic),t’s
nogat odi etoa uinse tgraiontesfohr pis urpoIens. tgraionteask
a longer time to excut becaus they have to configure the Spring contex.
Every method cal also triges sevral Spring mechanisms Spring neds,
depnding on what capbiltes it ofers to that specif method. It doesn’t
masenk toespendtimane dresoutorces xuthe foscenvry aio f
yourap ’slogic.Tosavetime,thebstap roachistorely nunitesovalidate your ap s’ compone ts’ logic and use the integraion tes only to validatehowtheyintegrawithheframework.
Summary
Atesi amalpiec ofc deyouwriteovalidte hebhavior fcertainlogic
implementdinyouapr Te. narest bcyeauths ey lpyouensuthre at
fut re ap devlopments don’t break existng capbiltes. Test also help as
documentaion.
inTetwafolucegintsdr:Eapegaiot uns.hc rpasoe.
– A unit es only focuse on an isolated piec of logic and validtes how one
simple compone t works without checking how it ntegras with other fatureUns. teisarhelpfubl ecaustheyxcuftasndpoinut ds irectlyo
theproblemaspecifomponentmightface.
– An integraion tes focuse on validtng the interacion betwen two or
more components. They are esntial becaus sometimes two compone ts
might work coretly in isolat n but don’t communicate wel. Integraion
teshelpusmitigaeproblemsgenratedbysuchcase.
Sometimesintesyouwantoelimineatdpendencisto mecompone tso
alow the ts o f cus on how some but not al parts interac. In such case, we
replac the components we don’t want to tes with “mocks”: fake objects you
Summary
control to eliminate depndencies you don’t want o tes and alow the ts o
focusonlyonspecifnteracions.
Anyteshasthremainparts:
– Asumptions —Definetheinputval esndthewaythemockobjects have.
– Cal/Execution —Calthemethodyouwantoes.
– Validtons —Verifythewaythetsdmethodbehavd.
345
apendixA
Architeualpos
In this ap endix, we discu a few architecural concepts you encounter. To fuly
understand evrything we discu in this bo k, you ned to at least be aware na d
have hig -lev overiw of thes concepts. I’l take you through the concepts of
monolith, servic-onted architecur, and microsevi. I’l also ref you to
othersourcesyoucanusetolarnthesubjectsfurher.
Thsue bcoarejts mpmalex; nby o anks d ozenospf resntaoi nhs bave n
delivronmathIo’lca espy ’tic, yokueanxpfiwjueart bs geu, t
readinthwig is hl epyounderstandwhyouSpserinspgcenif arweosdiscusinthebo k.We’ltakenap scenario sanexampleand iscu thechange
inarchitecuralp roachesfromthearlygsof twaredvlopmento day.
A.1
The monolithic approach
In this section, we discu what a monolith is. You’l understand why in the early
days devlopers designed ap s monotlhi caly, nd then, in the next scions, this
wilhelpyou nderstandwhyotherachitecuralsyp eard.
When devlopers ref to an ap as being “monolithc” or “a monolith,” it
meansthaitconsitofjustonecompone tyoudeployandexcut.Thiscompone timpeml entsalifunctionalties.Foxrample,consideranp formanaging
a bo kstore. The user manage the products he shop sel, the invoices, the deliverias,ndthcue stomeInrs. figurA.e 1th, pe rsntedsymmoais nolithb, ecaus
althesfunctionalitesrpofthesameproces.
A busines flow is omething the uers xpects o do in the ap lication. For example, when the shop owner sl bo ks, the flow could be as
fol ws: The products functionality resv some bo ks from the stock,
thbe linfgunctionalitcyresni vofice thr obse o kasn, dthde livries plan when to delivr the bo ks and notifes he customers. Figure A.2
presntsaviulrepsntaionofthe“slbo ks”businesflow.
NOTE
347
348
APPENDIX A Architectural approaches
Each of the round-cornered
rectangles inside the square
representing the process
are functionalitites executed
within the process.
The main square represents
a process that you execute
on a specific machine.
Products
Billing
Deliveries
To define business flows, these
functionality implementations
communicate with each other
inside the process.
Customers
Figure A.1 A monolithic application. The application implement s all t he funct ionalit ies in just one process.
The implement at ions int eract wit h one anot her inside t he process t o develop t he business flow.
User
Client app
Backend
Products
Billing
Deliveries
Customers
Sell books
Sell books
Find requested
products
Create invoice
Request delivery
Notify customers
Order status
Figure A.2 An example of business flow. The user wants to sell books. The client app sends t he request
to t he backend. Each responsibilit y of t he backend has a role in the ent ire flow. The functionalit ies
communicate with each ot her to complet e the business flow. In the end, t he client app receives the
st at us of t he order
NOTE Infigure A.simI 2, plifedthcoemmunicatonbetwenthcoemponents
toal wyoutof cusonthediscued subject.Theclasdesign,whichresult
inhowthecompone tscommunicatewithonea other,maybedifrnt.
APPENDIX A Architectural approaches
Initaly, al p licatons were devloped in a monolithic fashion, and this ap rocah
worked great in the arly days of ap licaton devlopment. In the 190s, the internet
was only a network of a ew computers, but in a few years, it became a network f billionosdf Toevics. dtechay, nolnisgy ol nfogertchfoi’se;vrybodAny. dthis
change implied a signficant growth in the number of user and dat procesd for
mansytemThs. eaygoirstb, nabgtocle nywhyoer uarevnse ding a mesage from the stre while waitng to cros the road wasn’t something we
couldhaveimaginedposbi le.
To deal with this chna ge in the number of user and the growth of dat, he ap s
ned more resources, and using only one proces makes the management of the
resourcemos dre ifcuThtl. ne umboer uf anser dthqe uantoiy df aretnh’ oe nly
things tha changed with time; people stared to use ap s for almost anything they
wantedodoremotely.Forexample,todayoucanmanageyourbankacountswhile
drinkcapg ucinyoatuWhfvcé.rite thilesmimt easy, pmoiels secur riThskty. sytemos ferinyog uthsernvic edtobwee l-securdandreilab.
Of course, al thes changesalo broughtchanges in the waythe ap s are ctd
and evloped.Let’sconsiderjustheinsecrainthenumberofusertoimplifyour
discuon. What’s one thing you can do to enable your ap to serv more quest?
Wel, we could run the same ap on multipe sytms. This way, sevral instances of
run ing ap licatons wil split he rquest among them so that he sytem can deal
with a more signifcant load (figure A.3.) We name this ap roach
Assuming a linear gowth for simplicty; f one run ing ap instance was able to deal
horizntal scaling
The clients make requests
to the backend.
LOAD
BALANCER
A component named
Load Balancer redirects
the requests to one of the
available app instances.
349
Products
Billing
Deliveries
Customers
Products
Billing
Deliveries
Customers
Products
Billing
Deliveries
Customers
.
The same app runs in various
instances on different servers.
Figure A.3 Horizont al scaling. Running t he same instance multiple t imes enables us to use more resources
and serve more client request s.
350
APPENDIX A Architectural approaches
with 50, simultaneous request, thre run ing ap instances should be able to
respondto150,c ncurentrequest.
One otheraspectwetake into c nsideraton is that,ingeneral,n ap is continuouslyevoing.Whenyoumakevnasmalchangeinamonolithicap ,younedto
redploy evrthing. At the same time, with a microsevi architecur, you benefit
fromredployinthg serviconwhly eyor umadthe c anThge. simplifcatonais
benfitorhesytmaswel.
thIs paer oblemwithcontinuintogumoase nolithapc roachtodiegns a p ?
Ther might not be a problem at al. Like with any other technol gy or technique,
designi g your ap as monolith could be the best ap roach for your scenario. We
discunae whichmoa nolithsnth’ rieghct obice, udIt onwa’t nyot utohge
impresion tha using a monolithc architecur is wrong or that the ap roaches I
presntrepsntaberwaytodevlopyourap s.
Inmanycase,peoplejudegtheuseofamonolith wrongly.Iawaysheardevlopers complain g that heir monolithic ap s are chalengi to maintain. The truh is
that he problem is proba ly not he ap being a monolith. Mesy code is lkey the
maincauseofmakingtheap difcultomaintani .Orthefacthatdevlopersmixed
responsibltane d idnu’t abse trcionps ropceroly uldbwhe thy ape becomde ifficult o maintain. But a monolithic ap doesn’t necsarily ned to be mes.y With
software evolution, ther are situaons in which a monolithic ap roach no longer
works,owenedtofindalternatives.
A.2
Using a service-oriented architecture
In this ection, we discu servic-onted architecur. We’l use the xample from
section 1. to prove that a monolithic ap roach has limitaons and that, in some
cirumstances, we ned to use a difernt syle o design your ap . You’l earn how a
servic-onted architecur solve the presnted isue, but we’l also discu the
difculteshisnewap roachad stoheap ’sdevlopment.
Let’s go back to our case with the ap for selni g bo ks. We have four main functionalitescovrdbytheap :products,delivrbng,andcustomWhers. atofen
hap ens in real-world ap s is tha not al featurs consume the resources equaly.
Some consume more than others, posibly becaus they’r more complex or used
moreoftn.
We can ot deci that only a part of the ap should be scald with a monolithci
ap . In our case, we either scale al four featurs or none of them. To manage the
resources betr, we’d like to scale only the fatures tha rely ned more sources
andavoidscalngtheothers(figuA.4).
Can we do something to enable us only to scale the products feaur but not he
others? Y, we can split he monolith into multipe srvic. We’l change the ap ’s
architecur from a monolith to a servic-onted architecur (SOA). Instead of
having just one proces for al the featurs in a SOA, we have multipe proces
APPENDIX A Architectural approaches
The products functionality
consumes most of the
resources. It needs to
be scaled.
5%
70%
Products
351
The billing and deliveries
functionalities don’t consume
that many resources. They
don’t need to be scaled.
Billing
5%
20%
Deliveries
Customers
The customers functionality
consumes more resources.
Maybe we need to scale it.
Figure A.4 Some features are more intensively used t han ot hers. For this reason, t hese feat ures
consume more resources and need t o be scaled.
implementi hg featuWers. canthendeci otsalnthlyimservc plementi g
thefaturhatnedsmoresources(fig A.5).
In a service-oriented architecture,
we design each feature as a separate
process. This way, you can decide to
scale only the features that need more
resources.
Products
Billing
Deliveries
Customers
Figure A.5 In a SOA, each feat ure is an independent process. This way, you can
decide t o scale just the feat ures that need more resources.
A SOA also has the advntage of having the rsponsiblte betr isolated: now you
knowyou have de icatd ap for the bilngand a de icatd ap forthe delivrs,
andso n,andit’searokptheimplementaionsdecoupledandmorecohesvi.
This is benefical for the maintainabilty of the sytem. As a consequence, it’s also
352
APPENDIX A Architectural approaches
easir to manage the teams working on the sytem becaus you can ofer difernt
teams pecif srv on which they wo,rk instead of having multipe tams working
onthesameap (figureA.6).
Monolith
Service-Oriented
Both teams work
on the same app.
TEAM A
The system is composed
of multiple apps.
The teams can work
on individual apps.
TEAM A
Products
Billing
Products
Billing
Deliveries
Customers
Deliveries
Customers
TEAM B
TEAM B
Figure A.6 A monolithic syst em consist s of only one app, so if you have multiple t eams working
on t he syst em, t hey all work on t he same app. This approach requires more coordinat ion. In a SOA
where the syst em is composed of multiple apps, each team can work on different apps. This way,
they need t o coordinat e less.
Atgflanirst mice, ghlot ekasWiy. thal esdvantagwhes, dy i nwe’t hatvhle
ap s like this from the begin ing? Why evn bother saying a monolith is tl a solution in some caes? To understand the answers to thes questions, let’s dcisu the
compyolexits untroduce sinSOag A.Heosare mde omains whichweencounterdifntisuewhenusingSOAs:
1
2
3
4
Communicatonamongthesrvic
Security
Datapersitnce
Deployment
Let’slo katsomexamples.
A.2.1
Complexity caused by communication among services
The functionalites til ned to communicate to implement he busine logic flow.
Eariewil, thmoa nolithapic roacht, weey pre oat hf same ape wh, ichmadlienkintwg ofeatuwisyr thmea thodBucal. nt owthwea hdave ifrnpt rothces, i
ismorecomplex.
APPENDIX A Architectural approaches
Featurs now ned to communicate v the network. One of the sntial principles you ned to remember is tha the network isn’t entirely iable. Many fal into
thetrapof rgetingtoc nsiderwhathap ensif,atomepoint,hecommunicaton
betwen two compone ts breaks. Unfortunelayt, unlike a monolithic ap roach, any
calbetwentwoc mpone tscanfailtsomepointnaSOA.Dependingontheap ,
devlopersudiferntechniquesorpatensto lvethisue,likrpeatinglcas,
cirutbreaks,oches.
Asecondasptoec nsidther at mare noy ptiontoseablihcommunication among the srvic (fgure A.7). You could use REST servic, Grpa hQL, SOAP,
gRPCJM, meS sbage rokKaes, fakn, dso nWh. ichts be apst roachOf? course,
inanysituaononeormoreofthesap roachesifne.You’lfindlongdebatsnd
discuonsi manybo ksonhowtocho setherightfiorypicalsenarios.
Does this call affect the
performance of the system?
Products
Billing
What happens if communication
between these two fail?
Deliveries
Customers
How should I implement
communication between
these two services?
Figure A.7 Communicat ion between services adds complexit y to the syst em. We need
to decide how t o implement t he communicat ion bet ween two services. We also need to
understand what could happen if t he communication fails and how t o solve potent ial
problems caused by malfunctioning communicat ion.
A.2.2
Complexity added to the security of the system
By splitng our functionalites nto separt sevic, we also introduce omplexity n
security configuratons. Thes servic exchange mesage via the network, which
mighexpt oinse formationSo. metimwees wanpt oiecshf de xacht ngednot be
senpik(latwordbs, ankincardg oetais,l rhper sondal Wet). nowned
toencrypthdes btail efosnr dinthg emEv. enweif donsoifcare’tmeoncae s
thexchanged etails,nmostceawedon’twantanyonetobea ltochangethem
whiletheyflowfromonecompone toanother(figuA.8).
353
354
APPENDIX A Architectural approaches
I could try to find a way to
change this request and send
a list of products so big that
the billing service cannot process
it and crashes. This way I’d affect
all the placed orders.
If the credit card details are not
encrypted, I can try to steal them.
Products
Billing
Deliveries
Customers
Maybe I can change the message
sent to the deliveries such that
I receive more products than
I’ve paid for.
Could I alter this exchange to
send spam messages to customers?
Figure A.8 In a SOA, feat ures are separat e services and communicat e over t he net work. This aspect
int roduces many vulnerable points t hat developers need t o consider when building t he app.
A.2.3
Complexity added for the data persistence
In most case, an ap neds a way to store dat. Databse are a popular way persitence is mplemented in ap s. With a monolithci ap roach, an ap had one datbase to store the dat, s presnted in figure A.9. We caled this a
becaus it consit of thre tiers: the client, he backend, and the datbse used for
persitnce.
t h re - i a c u r
Products
Client
Deliveries
Billing
Customers
Backend
WithSOA,younowhavemultipesrvcthatnedtos redat.Andwithmoresvices, you also have more design options. Should you use just one datbse hared by
althesrvic?Shouldyouhaveonedatbseforachservic?FgureA.10visualze
thesoptions.
Mobst elivhsat rindag tbaise dpractie.Fommyownexprincewith
splitnmoag nolithntomultipesrcvI,antyeol utha vinsgahred atbse
canbecomdae ployment ightmaBure. ht aving div udal tbapes rvilco
Database
Figure A.9 Wit h a monolit hic
approach, you only have one
applicat ion and usually one
database. The syst em is simple
and can be easily visualized
and understood.
APPENDIX A Architectural approaches
Services that need to persist data
can share the same database.
Sharing a database
Client
355
Products
Billing
Deliveries
Customers
Products
Billing
Deliveries
Customers
Database per service
Client
Each service
can have its own
database to store
the data.
Figure A.10 In a SOA, you can decide t hat more services share t he same database or have an
individual dat abase per service. Having various alt ernat ives, each with it s benefits and drawbacks,
makes t he persist ence layer’s design in SOA more difficult.
implies difcultes. As you’l es when we discu transactions, it’s much eiasr to
asudre coat nsitenwicy thonde atbWhse. enhavinmog inre depndendt abes,
it’schalengingtomakesurthedatrmainsconsitentamongal.
A.2.4
Complexity added in the deployment of the system
Maybe the asiet chalenge to observ is tha we ad a lot of complexity to the sytemd’s eploymenWet. alsohavmoe rsevicnowb, uyaost ulearnedfromthpe rvious parg hs, you might have multipe datbse as wel. When you also consider
that securing the sytm wil ad evn more configuratons, you se how much more
compelxthedploymentofhesytmbecomes.
Why does a monolit h have a negat ive connot at ion?
You can see that the SOAs aren’t necessarily easy, so you might wonder why monolithic architecture tends to be associated with something negative. The reality is that
for some systems, a monolith makes more sense than SOA.
My opinion is that the negative connotation of monolithic architecture comes from the
fact that it represents old systems. In most cases, old systems were implemented
before anyone was concerned about clean coding and design principles. We now consider all these principles to make sure we write maintainable code.
356
APPENDIX A Architectural approaches
(continued)
It might feel strange to look back to the times when they didn’t exist, and sometimes
I’ve even seen developers blame those who started the implementation of such old
systems when problems arise. But the truth is that it’s not the fault of the folks who
used the tools and practices that everyone considered the best at that time.
Today, many developers associate messy and poorly written code with a monolith
concept. However, monolithic apps can be modular, and their code can be clean,
while service-oriented apps can be messy and poorly designed.
A.3
From microservices to serverless
In this ecton, wel’ discu microsevi. In this bo k, I ref to microsevi her
andther,andI’ likeyoutobeatlswareofwhatheymean.Microseviar
particul implementaion of the SOA. A microesvi us aly is designed with one
responsibltyandhasitownpersitnceapbilty(doesn’tsharedtbase).
With time,the way we deploy ap s changed. The software chitecur is not nly
relatdohfue nctionoalityhf ape A. wisoe ftwarche knitc owtosadpthsy-e
tem’s architecur to both the way teams work on the styem and how the sytem is
deployed. You might have heard about what we cal the DevOps movement, which
implibes oth owwedeplosy ftwwearse hasl owwewoork nsoftwdare vlopment.
Today, we deploy the ap s in the cloud using virtual machines or c ntainerizd environments,andthesap roachesgneralyimpliedthenedformakingap smaler.
Of course, evolution came with another incertiude: how smal should a servic be?
Manydebatdhisquestioninbo ks,articlend iscuons.
Thmie nimizatonoservwefic nsothfar todweay canimplemenshat ofurt nctionaltiy with onyl a few lines of code and deploy it n an environment. An evnt like
an HTTP request, a timer, or a mesage triges this functionality nd makes it excute. We cal thes smal implementaions
doesn’t imply tha the function doesn’t excute on a serv. But becaus evrything
regading the devlopment is hid en and we only case for the code tha implements
itslogcandthevntshatrige,merelyo kslienoservxit.
A.4
servl
Further reading
Softwarechitecurandietvsolutionisuchfantasicndcomplseux bjedcIt. on’t
thinkther’lvbto manybo kstoc verthisubjecthor ughl.yI’vead edthis
discuon to the bo k to help you understand the refnces I’l make to thes
noti ns. Stil, you might want o go depr into the subjects, o her’s a list of bo ks
frommyshelf.Thebo ksareintheordeIcommendyoureadthem.
1
MicrosevinAction
is an exclnt bo k you can star with when learni g microsevi. In the
bo k,you’lfindalthemicrosevi fundamentalsubjedcts iusedwithusefulexamples.
,byMorganBruceandPauloA.Peria(Man ing,2018)
functions. The term “servl”
APPENDIX A Architectural approaches
2
3
4
5
Microsevi Patrns
mend you continue with after thor ughly reading
author presnts a pragmatic ap roach on how to devlop produocti n-drea y
ap suingmicrosevi.
Spring Microsevi in Action
(Man ing, 20), helps you betr understand how to ap ly Spring to build
microsevi.
MiAinSecuryotsv
20),goesintodetailwithwhatp lyingsecuritywithamicrosevi architectumere ancruSsepoil. ctrfyman, dyoualwnays edtoc nsidertfomthedvlopmentproces’alytg.Thebo kexplainsecurity
from the ground up, and reading it wil give you a betr understanding the
aspectyounedtobeawareofinregadstoecurityfomicrosevi.
MonMitolih crosevi
for transforming a monolithc architecur into microsevi. The bo k also
discuewhetheryounedtousemicroseviandhowtodeci this.
357
, by Chris Richardson (Man ing, 2018) is a bo k I recomMicrosevi in Action
, by John Carnel and Ilary Huaylupo Sánchez
bP,y rabthSirwardena dNuwanDi(Mas an ing
b, Samy Newman(O’RMeeily d20trpeia),s ns
. The
UsingXMLfor
theconxfigura
A long time ago, when I stared using Spring, the devlopers used XML to configure the contex and the Spring framework in genral. Today, you can only find
XML configuratons in older ap licatons tha re stil up orted. The devlopers
quit snXML
g configuratonagoyersndreplacdthemwithusinag notai ns
becauosthf de ifcuolty readf inthg coe nfiguratoncodWhe. trui’les XMLhas
its go d points, i’ much easir to use an otai ns for eading and enhanci g the
ap ma’s intainabiFlty.ohr easoi ndI, eci dnot includXML
e co n figu rat o n s
inthisbo k.
yoIf uj’re nst owtsarinwig thSprinmyg, adtovisce larnXMLconfiguratons
only if you ned to maintain an older project and have no other choice. Star by
learningtheap roachesprntedinthisbo k.Youcanap lytheskilwithany
configuraton,ev XML.Thoe nlythingthatdifershatyou seda ifrnsytntax. But it makes no sen to learn thes congfiuratons if you’l nevr se this
a p ro a ch in pr ac ti e .
To give you a tse of what using XML for configuraton means, I’l hs ow you
howtoad abentoheSpringcontexusingthisold-fashionedway.Youcanfind
thexampleintheproject“sq-ap 2-ex1.”
Onde ifrnthsce wiat thXML,younedtohsepavinflrt whichyou’l
define the configuratons (in fact, hey can be multipe fils, but I won’t get into
un ecasry details). I’l name this file “config.xml,” and ad it to my Maven
project’s resources folder. The contex of this file is presnted in the next code
snip et:
358
apendixB
APPENDIX B Using XML for the context configuration
359
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="parrot1" class="main.Parrot">
<property name="name" value="Kiki" />
</bean>
Sets the value of the
</beans>
Creates a bean of type Parrot
with the identifier parrot1
parrot’s name to Kiki
The
<beans> tag is the ro t of this XML file. Inside the ro t ag, you find the defintionofabenoftype
Parrot .Asintheprviousnip et,odefineabnyoucanuse
another XML tag,
<bean> , and to give a name to the parot instance we use the
<property> XML tag. This the idea of XML configuratons: you se difernt XML
toags c nfiguspre fciatuWhres. atevwer ’d ousinag notai ns, owyouned
touseanXMLtag.
Inthmae weinacls,ret sanrepc sntinhSpg erincog antex, dwecan
teshatSpringad edthebansucef lybrefingtoheparotndprint gits
nameinthcoe nsole.Thne xtcodesnip etprsnths eimplementaionotfhmae in
method.InedtouseanotherclastoheinstanceoftheSpringcontex.
WhencreatingtheSpringcontexinstanceusingtheclas
tionContext , I also ned to provide the “config.xml” file's locati n contain g the
XMLconfiguraton:
ClassPathXmlApplica-
public class Main {
public static void main(String[] args) {
var context = new ClassPathXmlApplicationContext("config.xml");
Parrot p = context.getBean(Parrot.class);
System.out.println(p.getName());
}
}
Whenyour ntheap ,thenameyougavetoheparotinstance(
theXMLconfiguratonwilbeprintedintheconsole.
Kiki inmycase)in
apendixC
introducHTTP
In this ap endix, we discu the sntial spect of HTTP any devloper neds to
know.Fortunately,oudon’thavetobeanexprtinHTTPandknowitsrefnce
bhy toearimplemenxcltenwet bap Ons. youjor urnsoa ftwey dare vloper,
you’l also learn other HTTP pas ect, but I want to make sure you heav al the
ned information to understand the xamples we work on in this bo k, staring
withchapter7.
WhleyarnbouHTTP
t inba o abk ouSpt rinBeg? cautose dmoay ost fhape s
we implement with an ap licaton framework (such as Spring) are web ap s—na d
webap sueHTTP.
We’lbegni withwhatHTTPis,andwe’lanlyzeitsdefintioninavisual.We’l
thendiscuthedtailsyounedtoknowaboutHTTPrequestaclintmakesand
howthesrvponds.
C.1
What is HTTP?
Inthisecton,wediscuwhatHTTPis.pI refsimpledfintions,oIdescribt
as how a client communicates with the srv in a web ap . Applicatons pref to
havergidwaysto“peak,”ndtheprot cols fertherulstheynedtoexchange
information.Let’sanlyzethHTTPdefintonwithavisul(fg reC.1).
HTTP
Staels, x-based, request-rponse prot col tha use the clint-
servcomputingmodel.
360
Aquick
APPENDIX C A quick introduction to HTTP
361
Data is transferred as text.
A request cannot affect and
is unaware of other requests.
Each request is independent.
The client makes a request
and waits for a server’s response.
HTTP is a stateless, text-based, request-response protocol . . .
The user
REQUEST: Give me the product list
page I need to display.
RESPONSE: Here is what you need
to display to the user.
. . . that uses the client-server computing model.
HTTP is a protocol that defines the communication
between a client and a server. HTTP only makes
sense for web apps where a client needs to exchange
data with a server.
Figure C.1 HTTP is a prot ocol t hat describes how a client and a server t alk. HTTP assumes a client makes a
request, and t he server responds. The prot ocol describes what t he client ’s request and the server’s response
look like. HTTP is st at eless, meaning t he request s are independent of one anot her, and text -based, which means
the informat ion is exchanged as plain t ext .
C.2
The HTTP request as a language between client and server
Inthisecton,wediscutheHTTPrequest.Intheap syouimplementwithSpring,
you’l ned to use the HTTP request o send dat from client o serv. If you implement he clint, you’l ned to ad dat on the HTTP request. If you implement he
serv, you’l ned to get dat from the rquest. Either way, ou ned to understna d
theHTTPrequest.
TheHTTPrequesthasimpleformat.Thethingsyouhavetokintoc nsiderationarethefol wing:
362
APPENDIX C A quick introduction to HTTP
1
2
3
4
5
The requst URI
request. The request URI lo ks like this one:
bo ks/pring-starher
The rqust method
with the rquestd resource. For example, when you write an ad res in a web
browadser’ btrehsa, rowalwser uaysne HTTPmethodnamedGET.In
other ciumstances, you’l find in the next parg hs, the clint can isue an
HTTPrequestwithadiferntmethodsuchasPOST,PUT,orDELETE.
The requst parmetrs (optinal)
serv with the rquest. When I say “mal quantiy,” I ref to something that
can be exprsd in maybe 10 to 50 chartes. Parmetrs on the request
aren’t mandatory. The request parmetrs (also refd to as query parmeters)antintheURIbyap endingaqueryxpsion.
Therqust ade (opinl)
Unlikerquestparmetrs,hesvaluesrnotvisblentheURI.
The requst body (optinal)
serv in the requets. When the client neds to send dat composed of some
hundre os fcharctes,inusethHTTPbody.Abodyontherquestinot
mandatory.
—The client use the path to tel the serv what resource it
hwtp/ww.: man ing.com/
—A verb tha the clint use to indicate what cion it wil do
—Data in smal quantiy the client esnds to the
—Data in smal quantiy sent in the rquest headr.
—A large quantiy of dat the client sends to the
Thefol wingsnip ethesdtailnanHTTPrequest:
POST /servlet/default.jsp HTTP/1.1
The request specifies the method and the path.
Accept: text/plain; text/html
Accept-Language: en-gb
Connection: Keep-Alive
Host: localhost
Referer: http://localhost/ch8/SendDetails.html
User-Agent: Mozilla/4.0 (MSIE 4.01;Windows 98)
Content-Length: 33
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
lastName=Einstein&firstName=Albert
Different headers with
values can be added
as request data.
Request parameters can
also be used to transfer
request data.
TherquestURIidentifesarourceonthesrvidethclientwantsoworkwith.
TheURIisthepartofheHTTPrequestmostpeopleknowaboutbecauswehaveto
wrURIitae inoubr owsera’d rbes achtimwee aweces bsiThte. URIe has
format like that in the next snip et. In the snip et, <srv_locati n> is the network
ad res of the sytm wher the srv ap runs, <ap icalton_port> is he port number identifyng the serv ap instance run ing, and <resource_path> si a path the
devloper asocited with a specif resource. The client neds to request a specif
pathtoworkwithaprticulaesource:
http://<server_location>:<application_port>/<resource_path>
APPENDIX C A quick introduction to HTTP
http:// means you send requests to
the backend app using the HTTP protocol.
363
The system where you
run the web app
http://localhost:8080/home
The port is a value that identifies
the server app you call.
The path represents the resource
the client wants to work with.
In your app, you identify a method
with the path. When the client requests
a specific path, the app executes the
method identified by the path.
Figure C.2 The HTTP request URI ident ifies the resource t he client request s t o work wit h. The first part of the
URI identifies t he prot ocol and the server that runs t he server app. The pat h ident ifies a resource exposed by
the server.
FigureC.2anlyzestheformatofnHTTPrequestURI.
Auniformresourciedntife(rURI)includeaus niformresourceloator (URL) and a path. We can say the formula is URI = URL + path. But in
many case, you’l find people confusing the URI with the URL or considerinthg emtobhe samthe inYog. unedtormembther a URL
e identifes
thesrvandtheap licaton.Whenyouad apathtoaspecifrsourceof
thap licaton,itbecomesaURI.
NOTE
Once the client identifes the resource in the request, it use a verb named
requst method
the method depnds on how it sends the cal to he srv. For example, if the cal is
madtbheircly owwhser, enyouwrandite nthres adbthresa, owser
wiselndGET
a requesInt. mocsatwhe, enyoucsliak bmbit utononfaormona
webpthage, rowuPser OSTTh. devlopthweefr pbdageciwhes meta thod
thberowsher oulduwhse ens dinreqaugthesoatrignesuoatdlf bmitng
foa rmY.oule’arnmoarebouthasipecnt hapAnte8.r HTTPrequcanest lobe
sent by a script writen in a client-side languae such as JavScript. In this case, the
devloperofthescriptdeci swhatHTTPmethodtherquestwiluse.
TheHTTPmethodsyou’lfindmostofeni webap sarefol ws:
HTTP
to specify what i wil do with the rsource. The way the clint specif
364
APPENDIX C A quick introduction to HTTP
GET
P O ST
PUT
DELETE
—Exprestheclint’sintentionto btainsomedatfromthesrv
—Exprestheclint’sinte iontoad datonthesrv
—Exprestheclint’sinteniontochangedatonthesrv
—Exprestheclint’si entiontoremoves medatfromthesrv
Alwremays embther at verbnas ocatnstrainotwhyoat uimplement.TheHTTPprot colan otf rceyounot implementanHTTPGET
functionhaliotyndhbagcesknHoide. wyoshuevr, ounldevr
misuthHTTP
e methodAls! wcoaysnidthmeer ani tohHTTP
fg e method
usedtoensureyourap ’sreliabty,curiandmaintai abilty.
NOTE
Les often encounterd, but often enough to be relvant are the fol wing HTTP
method:s
OPTIONS
—Tethls eorv turnlista opf armsuetir p ofrts equest.
Forexample, theclintcanaskwhichHTTPmethodsthesrv up orts.The
most encounterd functionality hat use the OPTIONS method is cros- rign
resource sharing (CORS) relatd to security mplementaions. You can find an
exclnt discuon about CORS in chapter 10 of another bo k I wrote,
(Man ing,20;
SecuritynAction
security-naction/chapter-10/
PATC H
—May be used if only part of the dat repsnting a specif rsource
on the backed is changed. HTTP PUT is used only when the client’s action
complety replacs a specif resource or evn ad s it wher the dat to be
update doesnIxit.’ myexprindce, vloptensilr dtouHTTP
se PUT
inmostcae—evnwhertheactionrepsntsonlyaPATCH.
S prin g
hlivebto/ps: k.man ing.com/bo k/spring).
The URI and the HTTP method are mandatory. The client neds to mention the
resource it works with (through URI) and what it does with that resource (the
method)whenmakinganHTTPrequest.
For example, the request repsnted in the next snip et could be a way to
instruc the serv to retun al the products i manages. We consider her that the
produsctiareourcethesrvmanages:
GET http://example.com/products
The request repsnted in the next snip et could mean that the client wants to
removealtheproductsfromthesrv:
DELETE http://example.com/products
But sometimes the clint also neds to send dat with the rquest. The srv neds
this dat o complet he rquest. Say the clint doesn’t want o delt a the produjcts, pa ecoif nThe. enthclient edtos hel swhrv pat rodutoc delt
and send this detail n the rquest. The HTTP requets could lo k like the one pre-
APPENDIX C A quick introduction to HTTP
365
sented in the next snip et, wher the clint use a parmetr o tel he srve they
wantodeltheproduct“Ber”:
DELETE http://example.com/products?product=Beer
Aclientuseiherthe
tohseThrv. requpest armanetrs dthrequbest odarey ptionfoalthr HTTP
e
request. A client neds to ad them only if they want to send specif dat to the
se rv .
The request parmetrs are key-valu pairs the client can atch to the HTTP
request o send specif nformation to the srv. We use the rquest parmetrs o
sendsmlin,a div ualquantioes df moatI. dre ant edtos bexchangedth, be st
waytosendthedatishroughtheHTTPrequestbody.Inchapters7hrough10,we
useboth esap roachestond atfromclientoservintheHTTPrequest.
C.3
requstpametrs
, req u st h a d
,orthe
req u st bod y
The HTTP response: The way the server responds
In this ecton, we discu the HTTP response. HTTP is the prot col tha lows the
clientoc mmunicatewitht esrvinawebap .Onceyoutakecrofheclint’s
request in an ap , it’s me to implement he srv’ esponse. In response to a client’srequest,hesrvndsthefol wing:
Therspon tau
sentaionoftherquest’r l.
Respon headrs (optinal)
valuepairdt.Theyardsignedforsendingasmalmountofdat(10o5
charctes)fomservtoclintinresponsetoaclint’srequest.
The rspon bdy (optinal)
the serv neds to send some hundre s of charctes or entire files) of dat
backtoheclint.
—An integr betwen 10 and 59 that defines a hort epr—Similar to request parmetrs, they repsnt key-
—A way for the srv to send a lrge quantiy (e.g,
Thenxtsnip et helpsyouvis alzetheHTTPresponse.
HTTP/1.1 200 OK
The HTTP response specifies the HTTP
version and the response code and message.
Server: Microsoft-IIS/4.0
Date: Mon, 14 May 2012 13:13:33 GMT
Content-Type: text/html
Last-Modified: Mon, 14 May 2012 13:03:42 GMT
Content-Length: 112
<html>
<head><title>HTTP Response</title></head>
<body>Hello Albert!</body>
</html>
The HTTP response can
send data through the
response headers.
The HTTP response
can send data in
the response body.
tosend at
366
APPENDIX C A quick introduction to HTTP
The rsponse taus i the only mandatory detail srv delivrs n response to a clienrqt’s ueThst. staeuhl cienthf seurv ndersto dthrequaenst devrything worked fine, or if the serv encounterd ius e while procesing the client’s
request.Forexample,thesrv turnsatusvaluetsaringwith2toeltheclint
thaevrythinwag fins The. HTTP
e tsauhi orept sntaionothf resultofhe
ful request (including if the serv was able to manage the busines logic of the
requYoest). udon’t edtolearnthsaue indenI’ltai. umanert d escrib
theonesyou’lfindmoreoftni real-worldimplementaions:
Staring with 2, meani g the serv coretly procesd the request. The
requestprocesingsokay,ndthesrvxcutedwhatheclintasked.
Staring with 4, wher the serv tels the client something is wrong with its
request (i’ a problem on the clint side). For example, the clint requestd a
resourcethatdoesn’t exis, orthe clintsentsomerquest parmetrshat he
servdi n’texpc.
Staring with 5, wher the srv communicates hat something went wrong on
its de. For example, the srv ned to c n ect o a datbse ut he it was
noacestibInl. thcasei, nrv dbstauck elins thg clienthiat
couldn’t complet he rquest but not becaus of something the clint di n’t
dowel.
NOTE
I wil skip the values taring with 1 and 3, which you’l encounter ls
ofteni ap s,othatyoucanfocusontheotherthresntialcegors.
Difernt values taring with 2 are varitons of mesage saying that he srve correctlypocesdtheclint’srequest.Afewexamplesarfo ws:
20 —OK
It just el the clint he srv di n’t encounter any isue when procesing its
request.
201 —Creatd
thclientha maserv nagedtoad threquestdrounIt’srce. oalwt ays
mandatory ad suchdetailohersponsetau,ndthat’swhy20—OKis,
ingenral,themostuedrsponseuta oidentifyhatevryhing’sokay.
204 —No Conte
thisreponse.
is the most known and most raightforward of the rsponse taues.
mightbeusd,forexample,inresponsetoaPOSTrequestol
could tel the client it shouldn’t expct a response body for
Whena HTTPresponstaue vl wistare th4, telsrv cinsot mething
wawrs onwig threquThest. cliendtisomethinwrg onwhg enrquspetinacfg
resocuIt re. ldbthe rasoudrceosn(thexiwe’ l-known40—NoFot und),
or maybe some validton of the dat di n’t go wel. Some of the most ofen encounterdclinterosponsetausreafol ws:
40 —Bad Requst
lem with the HTTP requets (.g, validton of the dat or problem with readingaspecifvaluentherquestbodyoraequestparmetr).
—A generic stau often used to repsnt any kind of prob-
APPENDIX C A quick introduction to HTTP
041 —Unauthorized
thatherquestnedsauthenticaon.
403 —Forbiden
notauhorizedtoexcutisrequest.
40 —Not Found
requestdrourcedoesn’texis.
When the rsponse taus tar with 5, it means omething went wrong on the srv
side,buti’shesrv’iue.Theclintsentavlidrequest,buthesrvcouldnot
complet i for some rason. The most often used stau from this category is
InternalServ Erro
informthecilnthatnius eocuredwhilethebackndwasprocesingitsrequest.
If you want o go more in-depth na d learn about more stau codes, this page is
hdtpa/rcke.ifos: g/doc/html/rfc7231
nceitorad:
Optionaly,thesrvndsbackdtoheclintinresponsethrougheitherthe
re sp o ns eh ad e rso t he r sp o n se b od y.
C.4
—Astauvaluegneralyusedtoc mmunicateotheclint
—A stau value gneralysnt bythe srvto el the clinti’s
—A stau value sent by the serv to inform the client the
50—
.Thisrepones tausiagenriceovaluethesrv ndsto
The HTTP session
Inthisecton,wediscutheHTTPseion,amechanismthatlowsaervtos re
dat bewenmultipe rquest-rponse interacionswith the sameclint. Remember
tha for HTTP evry request is indepndent of another. In other words, a request
doesnk’t owanythinabgouthper viouns, oimextr ultaneourqsuAest. rquest
can ot share dat with orde rquest or aces the details he backend responds for
them.
Howevr, you’l find scenarios wher the srv neds to corelat some rquets.
Ago dexampthleis cartfunctionoality nf onlinshe opA. userad mus ltipems
to heir cat. To ad an item to he cart, he clint makes a rquest. To ad a second
item,theclintmakesanotherquest.Thesrvnedsawaytoknowthathesame
clientpreviouyslda edanitemtohesamecart(figuC.3).
One way to implement such behavior is using the HTTP seion. The backend
asignsauniqueidentifernamed“sionID”toaclientandthenasocite witha
placeintheap ’smemory.EachrequestheclintsendsafterbingasinedthessionIDnedtosc ntainhseionIDinreqa uhest adTher. wais thy, be ackndap
knowstoa citehespcifesonrequest(figureC.4).
The HTTP seion us aly ends after a time if the client doesn’t send more
request. You can configure this time, us aly both in the servlt container and the
ap . It shouldn’t be more than maybe a few hours. If the sion lives to long, the
serv wil spend a lot of memory. For most ap s, a seion ends after ls than one
houriftheclintdones ’tendmoreques.t
If the clint sends another quest afr the sion ende , the srv wil tsar
newseionforthatclient.
367
368
APPENDIX C A quick introduction to HTTP
Paul
I’ll buy some bananas!
Paul’s cart
The backend needs to somehow
remember that Paul bought some
bananas.
POST /product
Paul
I also need a new bike!
Paul’s cart
POST /product
Paul
Let’s pay for everything!
Paul sends a second request to
buy the bike. The requests don’t
know about one another, but the
server needs to add the bike to
the same cart.
Paul’s cart
When Paul sends a request to pay
for his products, the server needs
to again know which products
Paul previously added.
POST /purchase
Figure C.3 For an online shop, t he backend needs t o identify the client s and remember the product s t hey
added to t heir cart s. The HTTP request s are independent one from anot her, so t he backend needs to find
another way t o remember the product s added by each client .
Paul
I’ll buy some bananas!
POST /product
Paul’s cart
(Session-ID: FA001B...)
Okay. You didn’t have a session
so I created one for you and
assigned the Session ID: FA001B...
Paul
I also need a new bike!
POST /product
Session-ID:FA001B...
Paul’s cart
(Session-ID: FA001B...)
I found your session and added
the bike together with your bananas.
Paul
Let’s pay for everything!
POST /purchase
Session-ID:FA001B...
You pay for two products I found
in the memory location associated
with your HTTP session.
If the client doesn’t send a
session ID in the HTTP request,
the server generates a unique
one and associates it with a
memory location where data
can be stored throughout
multiple HTTP requests.
Paul’s cart
(Session-ID: FA001B...)
When the client sends a new
request, it also sends the
session ID, which helps the
server identify the client and
find the details associated with
this client that the server keeps
in its memory.
Figure C.4 The HTTP session mechanism. The server ident ifies t he client wit h a unique session ID it generat es.
The client sends the session ID in t he next request s, so the backend app knows which memory location it
reserved earlier for the client.
apendixD
UsingJSONformating
In this ap endxi, we dcisu JavScript Object Notaion (JSON). JSON is an oftenusedwaytof rmathedatexchangedbyap sintheHTTPrequestandresponse
when using REST endpoints to communicate (figure D.1). Because REST endpoints are one of the most encounterd ways to establih communicaton betwen
ap s,andJSON isthemainwayto f rmat hedatexchanged, understandingand
knowinghowtouseJSONformatingsential.
POST /payment
requestId: <some random ID>
{"amount":1000}
When you implement communication
between two apps using REST endpoints,
you most often use JSON to format
the exchanged data.
{"id":"211499...","amount":1000.0}
App A
App B
Figure D.1 When you implement business logic, it sometimes implies est ablishing communicat ion bet ween
multiple apps. Most oft en, you use JSON t o format t he data t he apps exchange. To implement and test your
REST endpoint s, you need t o underst and JSON.
Fortunately, JSON is eay to understand, and it only fol ws a few rules. First, you
ned to know that what you repsnt with JSON are object instances using their
atributes. Like in the cas of a Jv clas, the atributes ar identifed with names
andholdvaues.Youmaysatheobject
bute
price . An instance of the
exampleth, e
name is“choc late”ndthe
JSON,younedtoc nsiderthefol wingrules:
Product hasnatribute
Product clas asigns values to the atributes. For
price s5Ifyio. uwantorepsnthins
369
name andanatri-
370
APPENDIX D Using JSON formatting
TodefineanobjectinstanceinJSON,weusec rlybaces.
Betwen the curly braces, we enumerat the atribute-val pairs, separnti g
themwithcommas.
Theatributenamesarwritenbetwendoublequotes.
The string values are writen betwen double quotes. (Any double quote the
stringcontai snedstohaevbckshl “”ni \frontofi.)
Thenumericalvusrewritenwithoutquotes.
Theatributenameanditsvaluerspatedbyacol n.
Figure D.2 presnts the JSON-formated product instance with the atribute name
“choc late”ndthepric“5.”
Object instances are defined
between curly braces.
String values are written
between quotes.
The attribute-value pairs are
separated with commas.
{
"name" : "chocolate",
"price" : 5
}
The attribute names are written
between double quotes.
Numerical values are
written without quotes.
The attribute name and its value
are separated with a colon.
Figure D.2 Describing an object inst ance in JSON. We surround t he at tribut e-value pairs
wit h curly braces. A colon separates t he at t ribute name and it s value. The at t ribute-value
pairs are separat ed wit h commas.
InJSON,theobjectislfdoesn’thavenameoratype.Nowherdoesitayhesnippet describ a product. The object’s only revant iems are it butes. Figure D.2
detailsheJSONrulesfordescibnganobject.
An object might contain another object instance as the value of one of its atrib u tes. If th e
Product has
color ,thenarepsntaionofa
Pack and the
Pack is an object describd by its aribute
Product instancelo ksliethenextsnip et:
{
"name" : "chocolate",
"price" : 5,
"pack" : {
"color" : "blue"
}
}
The value of the attribute
pack is an object instance.
APPENDIX D Using JSON formatting
The same rules rpeat. You can have many atributes rpesnti g other objects and
nesthemasmanytimesayouned.
yoIf uwantodefni coaelti nof binjects JSON,you bse anrckt, dyouseparte he ntries with commas. The next code snpi et shows you how to define a collectionthatcontainstwo
Product insta ces:
We use brackets to surround the
object instances in a collection.
[
{
"name" : "chocolate",
"price" : 5
},
{
"name" : "candy",
"price" : 3
}
]
The instances are
separated with commas.
371
andcretigbs
InstaligMySQL
apendixE
In this ap endix, I wil show you how to creat MySQL datbse. In some of the
examples we implement in chapters 12 through 14, we use an extrnal datbse
managementsyem(DBMS).Forthesxamples,you’lnedtocrea datbse
fory urap tousepriot implementi gtheproject.
For the datbse technol gy, you have plenty of options to cho se from, like
MySQL,Postgre,Oracle,MSSQL serv, and so n. I encourage you to selct he
technol gy ou like if you alredy have prefd one. For the xamples in the
bo k,Ihadtocho seacrtindatbse chnol gy,andIdeci dtouseMySQL,
which is fre, lit and easy to instal on any operating sytem. You’l find MySQL
usedingeneralfotuorialsndexamples.
For learni g Jav nd Spring, it’s irelvant which DBMS technol gy ou use.
The Jav and Spring clase and methods are the same, whether you cho se
MySQL,Oracle,Postgre, anyotherlationaldtbasechnol gy.
Thestpforceatingadtbaseforuseinthexamplesar thefol wing:
1
2
3
4
InstalheDBMSonyourlocasytem;wewiluseMySQL.
Instal a client ap licaton for the DBMS; we wil use MySQL Workbench,
whichsoneofthemostknownclientap sforMySQL.
Intheclintap ,con ectohelocaDBMSinstalion.
Creathedatbseyouwantouseinthexample.
Step 1: Install a DBMS on your local system
The first p is to make sure you have DBMS to work with. The xamples in this
bo k use MySQL, but you can cho se to instal nother DBMS if you pref using
another tchnol gy. fI you cho se to instal MySQL, you can find the instaler for
downloadher:
hdtp/ev.ms: ysql.com/downloads/mysql/
.
372
APPENDIX E Installing MySQL and creating a database
Download the instaler coding to y ur operating sytem and fol w the stp as
presnted in the instalion guide her:
en/instaling.html
Note hatduringtheinstalionofthe DBMSyou mightberquiredtocrea n
acount.Rememberthescrdntialsbecusyou’lnedtheminstep3.
373
hdtpe/v.ms: ysql.com/doc/refman/8.0
.
Step 2: Install a client application for your DBMS
To work with the DBMS, you ned a client ap , which is used to creat he datbse
and sometimes alter its truc re and validte your ap . You ned to instal a client
ap acording to he DBMS technol gy of y ur choice. If oy u work with MySQL, you
can useMySQLWorkbench,oneofthemostuedMySQLclients.
Download MySQL Workbench instaler acording to your operating sytem
( hdtp/ev.ms: ysql.com/downloads/workbench/
instalionmanual:
) a n d in sta l it a s d e scr ib d in the
hdtp/ev.ms: qys l.com/doc/workbench/en/wb-instaling.html
.
Step 3: Connecting to the local DBMS
Onyoce uinthsal DBMS
e onyoulor sytceamandcliena fotyr uDBMS
r yo, uned
toc n thec lintohDBMS
e To. uset pthcoe n ectionyo, unedthcredntials
you configured in step 1. If the DBMS intsalion di n’t request you set up a usernameandpasword,youcouldusetheursname“ro t”withanempty asword.
shI owyouhowatdo hcoen ectionMySQLWorkbenchAs. presntedinfgure
E.on1y, ouce penMySQLWorkbenthpclikueo,ns “Mear ySQLCon ections.”
Click the plus icon near
“ MySQL Connections.”
Figure E.1 Once you open MySQL Workbench, click on t he plus icon near the label “ MySQL Connect ions” to
add a new connect ion.
Apopupwindowap oears nyoce uthclik pe lubs utona, dyouhtoavehgi coe nnectiona meandusethecrdntialsyouconfigured urinthg eDMBSinstalion.
MySQLWorkbenchusethescrdntialsouthenticaeheDBMS(figureE.2).
374
APPENDIX E Installing MySQL and creating a database
Fill in a name for your
connection. For example, you
can name it “ local DBMS.”
Type your username and
a password if you configured
one during the DBMS installation.
Click the “ Test Connection”
button to verify the connection
works properly before adding it.
Figure E.2 Give t he connect ion a name and fill in the credentials you configured when inst alling t he DBMS.
Then, click on t he “ Test Connect ion” butt on to verify t hat MySQL Workbench can connect t o t he dat abase.
For s me MySQL evrsions, MySQL Workbenhc might display warni g mesage. For
implementi gthexamplesinthisbo k,thiswon’tafecyou,os clikthe“Conti ue
Anyway”butonifyou getsuchamesage(fiureE.3).
If you get such a warning
message, don’t worry; just
click on “ Continue Anyway.”
Figure E.3 Sometimes MySQL Workbench displays a warning message. This warning won’t affect the
way you implement t he examples in the book. You can click on t he “ Continue Anyway” but t on if such a
message is displayed.
APPENDIX E Installing MySQL and creating a database
375
If the con ection details r coret and MySQL Workbench managed to con ect o
yourlocaDBMS,youwilseapopupliketheoneinfigureE.4.
Click the “ Test Connection” button to verify
the connection works properly before adding it.
If the connection works correctly, you’ll get a
popup window like this.
Figure E.4 If MySQL Workbench connected t o t he local DBMS, it displays a “ Successfully made the
MySQL connect ion” message in a popup dialog.
Once you clik the OK buton, the new con ection is ad ed, and in the MySQL
Workbenchhomescrn,youcannowse ita recnglewiththenameyougaveit
(figureE.5).
376
APPENDIX E Installing MySQL and creating a database
Once you’ve added a new connection,
double-click on the rectangle representing it
in the home screen of MySQL Workbench.
Figure E.5 In t he MySQL Workbench main screen, you can now see the connection you added. The
connection is displayed as a gray rect angle, and it has the connect ion’s name.
Step 4: Add a new database
Now that you’ve ad ed a con ection, it’s time to use it and creat a datbse. The
examples we implement in chapters 12 through 14 use datbse. You ned to ad a
datbse foredvlopinga p thauseit.
After you double clik on the rctangle in the MySQL Workbench home scren
threapsnths coe n ectiontohloe DBMS
ca yo, uwiscaerlnithke onie
figureE.6.Clickonthesmalcyindericoni theto lbartod anewdatbse.
Youhtoave gihde atbnse amthe, ncolik nthApe pbly utonpas, rented
infgureE.7.
APPENDIX E Installing MySQL and creating a database
377
Click on the small cylinder icon
to create a new database.
Figure E.6 After connecting t o t he DBMS, you can add a new
database by clicking on the t oolbar' s small cylinder icon.
Fill in a name for your database.
For the projects in this book,
I use the name “ spring_quickly.”
Click on the
“Apply” button
after you give your
database a name.
Figure E.7 Give t he dat abase a name. Our examples use “ spring_quickly.” Click on the Apply but ton t o
creat e the dat abase.
378
APPENDIX E Installing MySQL and creating a database
Befoadre inthg de atbMyse, SQLWorkbenchyoask utoc nfirmonmoce Clre. ick
theApplybutonagin,asprentedinfgureE.8.
This popup window shows you the
SQL query that MySQL Workbench will
send to the DBMS to add the new database.
Click on the Apply button to send the SQL
query and create the database.
Figure E.8 You need t o again confirm t he creat ion of t he database. In this screen, you also see the query
MySQL Workbench sends t o t he DBMS to creat e t he new dat abase. Click the Apply but ton t o execute t he
query and creat e the new database.
Ifyoufni dyournewdatbseonthelftsidofthewindow,itmeansyous cefuly
creatdi,ndyourSpingap shouldbea ltouseitawel(figureE.9).
APPENDIX E Installing MySQL and creating a database
379
If everything went fine, the new database
appears on the left side of the window.
Figure E.9 The new dat abase appears on the left side of the window. If you can see it t here, it means you
successfully creat ed a new database.
apendixF
Recommendetols
In this ap endix, I’l enumerat the to ls used throughout the bo k’s examples
andothercommende altrnativesohesto ls.
IDES
JetBrains IteliJ DEA
in this bo k. You can use the fre InteliJ Community editon to open or
build the xample projects yourself. I you can use it, InteliJ Ultimate d s
various elments that help with implementi g Spring ap s. The Ultimtae
version requires a ilcense. You find more about InteliJ on its ofical web
hwtp/ww.s: jetbrani s.com/idea/
page:
Eclipse IDE
—Eclipse i an open source IDE you can use a n alternative o
InteliJ IDEA. I recommend you use Ecpli se with Spring Tools for a betr
exprince in Spring ap devlopment.You find more details bout Eclipse
andcandownloadher:htps:
TSpring ols
—SprinTog osetafilyos ucani witegra thknownopen
sourcIeDEssuchEcas lipsteoha Seprinapg implementaionYo. ufind
moreaboutSpringTools nitsofcalpge:
—InteliJ s the IDE I used to implement he xamples
.
/ www.eclips.org/downloads/.
hspt/rins: g.io/to ls
.
REST TOOLS
Postman
—Postmanisaneasy-touseto ltoesRESTendpoints.Youcanuse
it o tes he bo k’s examples with ap s that expose REST endpoints. Howevr, Postman is more complex and has various other capbiltes that
ni clude automation scrpi t and ap documentaion. Find out more about
Postmanonitswebpage:
cURL
—cURL is a simple command-line to l you can use to cal REST endpoints. You can use it as light alernative o Postman for tesing the REST
examples provide with the bo k. You can download cURL na d find more
detailsonhowtoinstaliher:
hwtp/ww.s: postman.com/
.
hcutp/rl.se :download.html
380
.
APPENDIX F Recommended tools
381
M YSQL
MySQLServ
—MySQLServisaDBMSyoucaneasilyntsalonyourlocasytemtohes bo examk’s pthles rqat uloairedc atbYose. ucandownload
and find more deitlas bout MySQL Serv on its web page:
.com/downloads/mysql/
MySQWoL rkbench
—MySQLWorkbclientohMyf arelchis SQYoLuServ.
canuthosedaci ltbmaase nagedthbMyy e SQvLatloidser
thyoatupr wocowirkselyt ht persitdYoat.ucndownloadndfind
more details about MySQL Worbk ench on the fol wing page:
.mysql.com/products/workbench/
S Q L Yo g
—An alternative to MySQL Workbench is SQLYog. You can downol ad
theo lher:
hwtp/ebs: yog.c m/product/sqlyog/
hdtp/ev.ms: ysql
.
hwtp/wws:
.
.
POSTGRESQL
PostgreSQL
—PostgreSQL is an alterntaive DBMS to MySQL that you can use to
tes the examples in the bo k or implement similar ap s that require a datbase. You find more details about PostgreSQL on its web page:
.postgreql.org/download/
p gA dm in
—pgAdmtoina ys lucantoadse minPastroe gSQLDBMSIf .
youchotseuPse ostgreSQLinsteadoMyf SQLtoruna exmpthle rqa uires
da tbaeyso, uwouldasonedpgAdmintomanagtehDBMS
e . Discovemor re
detailsboutpgAdminonthefol wingpae:
hwtp/wws:
.
hwtp/ww.s: pgadmin.org/
.
materialsfouhdy
apendixG
Recommendelarig
This ap endix enumerats some exclnt learni g material I recommend you
conti uewithafterdingthisbo k.
Spring in Action,6th ed., by Craig Wals(Man ing,201).
tinuingyoureadingonSpringwiththisbo k.Youwilstarwitharefsher
on what you learned in Spring Star Here and conti ue learni g a arviety of
projects tha are part of the Spring ecosytm. You’l find exclnt discusions on Spring Security, asynchronous communicaton, Project Reactor,
RSocket,andusingSpringBoot’sacutor.
Spring Security in Action by Lauren
ţiu Spilc
is a parmount subject you ned to learn right after you finsh with the
bYoasic. ufnda etild iscuononusinSpg rinSecug toriypoytec ur
ap fromdifernkit dos atfckbpy ropeimrly plementinaug thenticaon
andauthorizat ni thisbo k.
Spring Boot Up and Running by Mark Heckler (O’Reily Media, 201).
Boot is one of the most importan projects in the Spring ecosytm. Most
teams today use Spring Boot to eas the implementaion of their Spring
ap s.This alowhyweusedSpringBootinmorethanhalfthechaptersof
this bo k. Once you fni sh with the basic, I recommend you to take dep
dive into the details of Spring Boot. I found this bo k to be an exclnt
resourcefoadevloperlani gSpring.
382
Irecommendcon-
ă (Man ing, 20).
Securing ap s
Sprni g
APPENDIX G Recommended learning materials for further study
383
Reactive Spring bJoy shLon(gself-published20,I)n. myprojecuts, inreacgtive ap roach for implementi g web ap s comes with great advntages. Long
discue thes advntages and demonstrae how to properly implement
Spring reactiv p s in this bo k. I recommend you read this bo k after dS prin g A ction
byCraigWals.
ing
JUnit in Action by C
ăt ălin Tudose (Man ing, 20).
As we discued in chapter
15, it’s mportant o tes your ap licaton. In this bo k, we discu the bsiac of
tesing Spring ap s. But as this ubject is o complex, it desrv it own bo k.
CatalindiscuetsingJavp sindetailnthisbo k.Irecommendyouread
thisbo ktosrengthenyourknowledgofwritngtes.
Learning SQL, 3rd ed., by Alna Beaulie (O’Reily Media,20).
In chapters 12
through 14, we discu implementing the Spring ap ’s persitnce layer. In
thces apuIters, SQLquaersi, minyog ualredkny owthSQe LbasIifc.
you ned a refsher on SQL, I recommend you read this bo k, which details
althesntialSQLtechniquesyounedtouseinmostap s.
OCP Oracle Certified Professional Java SE 11 Developer Complete Study Guide by
Jean eBoyarskndScot elikof(Sybex,20).
Tostarleni gSpring,you
ned to ap ly most of the basic. But we sometimes ned to refsh our knowledg evn on the most fundamental syntaxes and techniques. Jean e and
Scot’s bo k for the OCP exam pre ation is the first one I use to remember
the basic syntaxes, and I always read the lates editon when I pre a to
upgrademyOCPcertifaon.
Spring Framework playlist on my YouTube channel. Ifyouenjoyvideotuorialsnd
live evnts, you can find me on my YouTube chan el (
yout be.com/c
)discungJavsubjects.Youfind afulpaylistonSpringher:
laurentiuspilca
hmtp/: ng.bz/yJQE
. Subscri e to he chan el to ge notifed when I post new
videos rchedule newlivents.
My blog ( laurspilca.om/blog
). AsidefrommyYouTubechan yoel, ufi’lndme
writng articles on my blog. I recommend you fol w the blog, wher you can
read iferntariclesonJavtopics.
index
Symbols
@Afteran oita n 143
@AfterReturni gan otai n 143
@AfterThrowinga notai n 143
@an otai n(ToLog) 142
@Aroundan otai n 132
@Aspectan oati n 129
@Autowiredan otai n 1,5 61–65, ,8 14,
12, 34
sfclaied,nctije gbeans 61–63
construcor,inject gbeans 64–65
usingdepndne cyi jectionthroughetrs 65
@Bean noita n 51, ,10 129, 260, 281
ad ingbeanstoc ntex 3–40
tincrea gmethodtharetunsBean dan odnefi gconufig ratonsclia protjec 34
maink gSpring italczeos ntexuins gcon-
smetae thod with@Bean –34 35
figuratonclas 35–40
prot ypebanscope,dlarinc g 13
sinletog nbeanscope,darincl g 10–103
@Beforean oati n 143
@Compone nta otai n 41, 58, 86, ,208 274
@Compone catnS notia n 41, 62, 8, 106, 912
@Configuraton an otai n 34
@Controlean otai n 71, 27
@DisplayNamane otai n 32
@EnableAsptJAec utoProanxy otai n 129
@EnableFignClientsa notai n 25
@ExceptionHna dleran otai n 241
@ExtendWithM( ockit Eenxt sion.s)cla
an otai n 36
@Figne Clienta notai n 251
@GetMap inag notai n 195, 27
@Idan otai n 314
@InctMje ocksan otai n 36
@Layanz otai n 109
@Mockan otai n 36
@MockBean notai n 34
@Modifynga notai n 316
@Orderan oita n 146
@Phat Varibnle otai n 18
@PotMs ap inga notai n 195
@PDre estroyan otai n 45
@Primaryn otia n 40, ,91 93–94
@Qualifern otai n 68, 1,9 94–96
@Queryan oita n 316
@Reposit ryan otai n 96, 274
@RequestBodnya otai n 24
@RequestMap ni ga notai n 17,
@RequestParman otai n 184
@RequestParmetran otia n 197
@RequestScoped an otai n 208
@Reps onseBodany otai n 27
@RetCs ontroalne otai n 28
@Scopean otai n 1
@Svicearn otia n 96, 812
@Ssioe nScopnea otai n 213
@Spinr gBo tAp licatona notai n 61
@Tagetarn oita n 14
@Tets an otai n 32
@Trna sctional notai n 289, 317
@Vaul ean otai n 28
Numerics
20OK 235
20OKstau 523
40BadRequest 235
40NotFound 235
50Erro nvers 235
385
18
386
INDEX
A
abrctios ns,dpe ndenicy jetonwith 85–96
auto-wirngfommultipme plemenations
91–96
cho singobtsjec 85–90
adicev 123
adicenv oita ns
rnalte iv 143–14
nteli gSpringwhena dwhichmethodcals
tointercp 213
amountfield 92, 31
an otai ns
inrcept inga notaedmethods 140–143
eostr ypean otai ns
ad ingbeanstoc ntex 1–4 43
obctrejsponbsi ltewith 96–97
AOP(aspect-oinr tedproamg ming) 9, 12,
126–14
rinalte g tperc dmethod’sparmtersand
retunedvalue 135–140
rnalte ivadcen otai ns 143–41
implementi smg pleas ct 127–135
adicenv otai ntopelS ringwhena d
tincrea glsdefin gaspectnda ding
enba lingasptmeec chanmis for
trancios ns 301
unesti 328–034
defind 287
inSpring 289–902
using Sprinpga s 291–130
archteui ralp roaches 7–34 357
frommicrosetvi lr 356
monolithcap or ach 347–503
usinervgc-oni ted archteui r(SOA)
350–53
complexityad de fordatpersince
complexityad de indeplomy entof
354–53
sytem 35
complexityad de tosecuyorit fsem 35
complexitycauds bycommunicatonma ong
servic 352–35
whhic methodcalstoinrcept 132
inast ceinSpinr gcontex 13
ap licaton 130
mi plementaspeclogi 3–1 135
inrcept inga notaedmethods 140–143
ap licatonmfra ework 3
ap licatonpropertisfl
cuost mizngdtasourceonfiguratoni
279–280
projectinaiolz nservic 168
ap licatonsce arios 12–61
automationties gap –14 15
delov pmentofbackendpa 12–14
delov pmentofdesktopa p 16
inmobileap s 16
ap licatonscope 20
ap licaton-scopedbeans –218 21
ApplicatonContexi stance 46
ap s
dsoat urcesin 283
cuost mizngconfiguratonof 278–28
dnefi d 265–692
usingJdbcTemplateoworkwithpistedr
dat 269–278
RESTservixchangi datbewen
26–27
intes g 327–43
ingratoe nste 341–34
asptinec ghemethod 9
asptec 150
excutionchain 14–149
howspa ectwork inSpring –123 126
impmle enti gwithSprinspga ect-orinted
proamg ming(AOP) 126–41
altneri g cetpr dmethodp’sarmanerst d
retunedvalue 35–1 140
alternivadcne otai ns 143–14
ineptrc inga notaedmethods 140–431
simpeasl ct 7–12 135
asumptions 329
atomicty 287
autow- irng 91–69
mainrk g implementaiondfaue ltorinjecton
with@Primary 3–9 94
namni gmplemne taionfodr epndenyc
inoject nwith@Qualifer –94 96
autoc nfiguratonbasedondepndenisc 162
automationtesi gap 14–15
B
bancke d 15
bancke dap s –12 14
beans
ad ingtoc ntex 29–48
proamg matiycal 45–48
usin@Beg an notai n 3–40
usintergoypane otai ns 41–43
webcos pes
ap caltion-scopedbeans 8–21 21
requst-ceopedbeans 201–082
seion-scopedbeans 209–182
wiring 74
cho singfrommultipebna si Spring
conxte 68–73
387
INDEX
bnea s(cotinud)e
ucir ladepndencis 6–67
implementi relagonshipsamongbane s
using@Autowredi an oita ntointjec
<bane s>tg 935
Beua lie ,Alan 271, 38
BigDecimaltype 274
Boarsky,Jen e 271, 38
Bruce,Morgan 356
<build><plugins>…</pul gins></build>
dnefi dinconiguf ratonlefi 51–60
beans 61–65
tags 167
C
/cal exution 329
Canr el,John 573
hcat block 926
CDI(Contexa dDependencyI ioject n) 1
CIco( nti uouins tegraion) 324
ucir ladepndencis 6–67
sfclaied
dnefi gaspnect da ding stancei
Spnri gcontex 13
inctje gvaluthes rough 1–6 63
Cnlea od(Mrtina ) 80
nclie tsdeofwebap 15
CommentProesc rbean 16
CommentReposit rybean 14
CommentReposit rype 104
CommentScervbi an 3,10 134
communicatoncompliesxt 352–35
complexits
ad edfordpat ersince 354–35
ad edindeploymentosefmy 35
ad edtosecuityor fsem 35
causedbycommunicatonamongicesrv
352–35
configuratonlasc
dnefi ginprojects 34
implementi relagonshipsamongbane s
dnefi din 51–60
dctimere thodcalbetwen@Bean
using@Bean notaedmethod’s
meht ods 5–58
pmar etrs 58–60
ni alzt gcontexusing 5–3 40
construcor 64–65
contex 49, 98, 120
ad ing ewbnea sto 29–84
progammalytica 45–48
using@Bean notai n 3–40
usintergoypane otai ns 41–43
crneati gMavenproject 23–28
depndencyi toje nwith
abctsrions 85–96
auto-wirngfommultipe
impmle entaions 91–96
cho ins gobjects 85–90
inactersfdin gconstrac 76–85
fordcoe uplingmplemeniota ns 76–79
impmle enti qgre uiremenwit thout nsi g
framwe ork 80–58
requremi entocenfs ario 79–80
obtrespjc onsibltewitheros type
an otai ns 96–97
prot ypebancos pe 1–19
dericlna gusinterog ypnea otai ns
14–15
dericlna gwith@Bean noati n 13
inl-wrea orldscenarios 15–19
sintogle nbeanosc pe 10–1
dericlna gusinterog ypnea otai ns
104–061
dericlna gwith@Bean an oati n 10–103
inl-wrea orldscenarios 107–108
usineagrndlazyinsta ion 108–1
wiringbeans 74
cho ins gfrommultipebna si Spring
conxte 68–73
dealingwithucir ladepndencis 6–67
impmle enti lagroe nshipams ongbnea s
defindinconufig ratonfile 51–60
usin@Au
g towdire an otai ntoinject
beans 61–65
XMLforc nfiguraton 358–359
Conexta dDependencyI jetion(CDI) 1
conti uousinrateog n(CI) 324
conactsr
inactersfdin g 76–85
fordcoe uplingmplemeniota ns 76–79
impmle enti qgre uiremenwit thout nsi g
framwe ork 80–58
requremi entocenfs ario 79–80
conve tion-ocver nfiguorat nprincpel 169
CORS(cros- inrg esoushrce aing) 643
CrudReposit cory ntrac 830
cuorl mmand 302
cURLto l 29, 803
customizng
avoidngframeworksand 18
daots urceoniguf raton 78–2 28
inap licatonpor pertisfl 279–280
usincug stomDataSourceban 280–28
388
INDEX
D
endpoints,REST
DAO(datesoc bjects) 80
dat
onHTTPrequest 182–183
RESTservic
hexc angi dtabewenap s 26–27
usingrequestbodytogedatfrom
usinReg stTempatel 253–625
usinSpg ringCloudOpenFigne 249–325
usinWeg bClient 256–263
excptionsat 7–23 241
impmle enti g 27–231
excptionflow 37–38
excutionchainsp, ect 4–1 149
sendingfromlienc toersv
dsoat urces 832
client 24–243
HTTPrequpest armetrs 183–186
pathvribles –187 18
cuost mizngconfiguratonof 278–28
inpa licatonpropeilrtsf 279–280
usingcustomDataSourceban 280–82
dnefi d 265–692
usingJdbcTemplateoworkwith pistedr
dat 269–278
dat transfe object (DTO) 23
DaaSot urceban 275, 280–28
DBMS(datbsemanagementsym) 265, 372
ad ing ewdabt se 376–378
con ectingol ca 37–753
inalst gclientap licatonfor 37
inalst gonlocasytem –372 37
DDL(dat dcripes tonla guae) 273
DELETE 316, 364
<dpe nden>ci</s depndencis>tag 28
depndencrtysa 162
deploymenst,my 35
dktoes pa ps 61
DId( epndenyic jeton) 51
throughsetr 65
withabstrcions 85–96
auto-wirngfommultipe
implementaions 91–96
cho singobtsjec 85–90
Dis,Nua wan 573
dctimere thodcals 5–58
dispatchersltv 173
DTO(datrnsfeob)ject 23
dynamicvew 7–1 18
inget datonHTTPrequest 182–318
usingpathvbri lestond atfromcliento
ersv 187–18
usingrequestparmetors nd fraot m
nclie toserv 183–186
E
eraing st ioa n 108–1
Ecpli seIDEto l 380
EJB(EnterpJavisBeans) 1
caling 263
F
framwe orks
avoidng 17–19
abundantexisngcustomtioza ns 18
secuityrquirements 18
smfoal tprint 7–1 18
reasonsforusing 4–7
fronet dofwebap s 15
G
GETmethod 9–18 197, 364
H
handlermap ing 173
hap y flows 329
Helecr,kMark 67,1 382
HiiCkar P(Hickaor n ectionpo l) 926
horiz ntalscing 349
<html>tag 182
HTTP(HTryptexr anProsfe t col) 159, 360–367
defind 360
requste
aslnguaebtwencli nta dserv
getindaton –182 183
usinpg armestor nd tafromnclie to
response 231–124
aswayservponds 365–367
mangia excptionsate dpointlev
seion 367
HTTPGET 189
HTTPrequestbody 183
HTTPrequesthader 183
HTTPrequestmethod 36
HTTPrequestparmetr 831
HttpEntiy 254
HttpHeadrs 425
sendni gobjesrctaponbse ody 23–342
setingrponstaue ndheadrs –234 235
361–653
serv 183–186
237–412
389
INDEX
I
i18n( ternoati nalizton) 10
id 702
idelf 29, 31
IDEs(integdra evlopment vironments)
24, 380
inalzt gcontex 35–40
INES RTstaement 31
Ingertyp 36
ingratoe nste 32, 341–34
inrfacetsgion 308
inrfacets 76–58
fodr ecouplinmg plemenations 76–97
implementi reqg uirementwithout sing
framework 80–85
requirementoscenf ario 9–7 80
InodutrcigMaenv(Varnsi) 24
IoC(inversionofc ntrol) 8
J
JDBC(JavDaabt se Con ectivy) 62
JdbcTemplate ,19 264, ,269 275–278, ,293 304
JetBrainsI iJteDl EAto l 380
joinpoint 123
JPA(JakrtPsiencAPI) 309
JSON(JavpScri tObjectNotaion) 32
JSONformating 369–371
JUnit Action(Tudose) ,324 38
POSTHTTPmethod 189–971
retuni gbean dan ointa gmethodwith
@Bena 34–35
tesingvaluert nedby 9–3 340
microsevi 635
MisecrvionAction(Bruance dPa)eri 356
MisecrvioPnat(Richdar son) 357
MisecrvioSutynAction(Srwardne a d
Dias) 357
mobleapi s 16
modle 82
Modltype 18
Monog Reposit ycor ntrac 309
MonlithoMisercvio(Newman) 357
monolithcap or ach 347–503
MySQL 372–378
ad ing ewdbat se 376–783
con ectingol caDBMS 73–375
inlsta gcienpta licatonforDBMS 37
inlsta gDBMSonlocatesym 372–73
to ls 381
MySQLServto l 381
MySQLWorkbenchto l 138
N
namfield 29, 31
Newman,Sam 573
NoUniqueBeanDefintonEcepx tion 93
L
O
inlazy stniaon 108–1
LnearigSQLrd,3 e .(Buea li ) 271, 38
LogedUserMna gemenrvictSbean 213
Logertyp 812
LoginAspect 14, 146
longi 21
Loing Controle 204
Loing CountvicSerban 219
Loing Proces br ean 214
Long,Josh 38
OCPOracleCdrtPifosnalJvSE1Developr
M
parmetrs
mani clas 167
Matinr ,RobC.ert 80
Maenv procjeat,ing 3–2 28
meht ods
adicenv otai nsi tperc ingcals 132
dctimere thodcalbetwen@Bean
meht ods 5–58
GETmethod 89–1 197
ComletSpudyGuide(Bokyanrs d
Selikof) 271, 38
onli eshop incartg 21
OpenFeignto l 246
OPTOI NSmethod 364
org.spingframeworkg upID 31
ORM(object-airol nalmap ing) 10
P
altneri g tercpdmethod’s 135–140
HTTPrequestprametnrs dingdfroat m
clientoserv 83–1 186
wiringbeansuing@Bean notaed
method’s 58–60
PATCHmethod 364
pathvribles 3,18 187–18
PaymentDetypails 24
Pera,i uloA. 356
390
INDEX
usin@Beg an notaedmeht od’s
parmetrs 58–06
psietrnc
oc mplexityad edfor 354–35
next dingwithSpringDaat 1
implementi wig thSprinDag ta 32
dnefi d 30–053
orview 306–093
usingSpringDataJDBC 1–3 321
Spinr gDataAcces 10
usingJdbcTemplatewith –269 278
pgAdminto l 381
pluginconfiguredbyS.ptar ing.IO 167
poni tcu 123
POOJ (plainodl Javobct)je 47
POTS HTTPmethod 189–197
POTS method 364
PotgreSsQLto l 381
Potms anto l 29, 380
peric 270
product 270
progammalytiadc ingbeanstoc ntex 45–48
projectinaiolz nservic 168
ap ’smainscrelatdbyStar.ping.IO 167
ap licatonpropertisfl 168
Spinr gBootMavenpluginconfiguredby
t.Spar ing.IO 167
projects 10–1
next dingpistenr capbilteswithSpring
Daat 1
Spinr gBoot 1
<por perty>ag 359
prot ype 19
prot ypebanscope 1–19
dlareinc gusintergoypane otai ns 14–15
dlareinc gwith@Bean an otai n 13
ineal-wr orldensc arios 5–1 19
prot ypebanscope,dlarinc g 13
proxies 80
proxy 124
Puchr aseRepoits rybean 274
PUTmethod 643
Q
qurype amerst 183
R
-corae nditonsce ario 710
tivreacp rocha 256
tivreacpomgra ming 246
RectiveaSprn(Lg ong) 38
tiorela nships,bean 51–60
dctimere thodcalbetwen@Bean
meht ods 5–58
Rena,tVie ctor ix
repoits re 80, 271
requstbe ody 236
requsthe aders 362
requstmee thod 362
requstpe armerst 362
requstceope 02
requstURIe 362
requst-ceopedbeans 201–082
requst,HTTP
e
aslnguaebtwencli nta dserv –361 365
getindaton –182 183
usinpg armestor nd tafromnclie to
rsev 183–186
responsebody 31,2 365
responsehadser 231, 365
responsetau ,231 365
response,HTTP 231–241
aswayservponds 365–367
mangia excptionsate dpointlev 237–241
sendni gobjesrctaponbse ody 23–342
setingrponstaue ndheadrs –234 235
REST(repsnationaletsrnfe) 24
endpoints 263
calingusingRetTs emplate –253 256
calingusingSpinr gCloudOpenFeign
249–532
calingusingWebClient –256 263
impmle enti g 27–231
exchna gi dbat ewenap s 26–72
mangia HTTPresponse 31–2 241
mangia excptionsate dpointlev
237–412
sendni gobjesrctaponbse ody 23–342
setingrponstaue ndheadrs –234 235
to ls 380
usinreqg uestbodytogedtafromnclie t
24–432
RestTemplate 53–2 256
RestTemplateo l 246
Richrda son,Chisr 357
rolbcka 287
S
Sánchez,IlaryHuaylupo 735
secuityr
avoidngframeworksand 18
complexity ad de to 35
SecuityAr spect 41
SELECTquery 762
Selikof,c t 1,27 38
rseidv ofwebap s 15
391
INDEX
erlsvfunioct ns 17, 635
letscorv ntai re 159
iose nscope 02
iose n-scopedbeans 209–218
ersint jcon 65
simplifedproectjai n 162
sinletog n 19
sinletog nbeanscope 10–1
dlareinc gusintergoypane otai ns 104–106
dlareinc gwith@Bean an otai n –10 103
ineal-wr orldensc arios –107 108
usingear dlazyinsta ion –108 1
sinletog nbeanscope,darincl g 10–103
sinletog ns 19
wSir ardena,Pbr ath 357
SOA(servic-ontedarchiteur) 62,1 350–53
complexity ad ed for dat persitnce 354–35
complexityad edindeploymentosefmy 35
complexityad edtosecuityor fsem 35
complexitycausd bycommunicatonamong
icesrv 352–35
SpEL(SpringExpresionLanguae) 8
Spinr gBoot ,1 162
implementi weg bap swith 198
dynamicvew 7–1 18
usGETing anPdOSTHTTPmethods 9–18 197
usingprojectinalztonservic 168
ap ’smainscrelatdby
t.Spar ing.IO 167
ap licatonpropertisfl 168
Spnri gBootMavenparencot nfiguredby
t.Spar ing.IO 167
nSprigBot(Hckler) 167, 382
nSprigBotAction(Wal) 167
Spinr gBootMaven
pluing configured 167
nSprigBot:UpandRunig(Hecklr) 167, 382
Spinr gCloudOpenFeign –249 253
Spinr gCore 8, 10
Spinr gData 23
dnefi d 30–053
next dingpistenr cwith 1
orview 306–093
usingSpringDataJDBC 1–3 321
Spinr gDataAcces 8, 10
Spinr gDataJDBC 31–132
Spinr gfamework 21
ap licatonsce arios 12–61
automationties gap 14–15
dloev pmentofbackendpa 12–14
dloev pmentofdesktopa p 16
inmobileap s 16
aspctien 123–126
avodi ng framwe orks 17–91
abundanteixs gcustomzations 18
secuityrquirements 18
smfoal tprint 7–1 18
ecostmy 7–1
proctjsfe m 10–1
SpringCore 8–01
SpringDataAcsfecatumri plementi g
SpringMVCcapbiltesfodr evlopinweg b
ap p’s eritnce 10
ap s 10
Springtes atugfe r 10
reasonsforusinframg ewosrk 4–7
trancisonsi 89–2 290
SpringActionh,6 ed.(Wls)a 256, 238
SprinMig crosevinAction(Carnelnd
Sánchez) 357
SpringMVC
deovl pingwebpa s 10
impmle enti gwebap swith 198
dynamicvew 7–1 18
usinGETg andPOSTHTTPmethods
189–971
SpringMVC(model-viw-controle) 8
SprinecugtyAction(Spl
Springtes g 8
SpringTools 038
spring-aspectdpendency 127
spring-contexdpendency 31, 127
spring.datsoueprc operty 280
spring.datsoue.inrc taolz n-mode
proprtye 279
spring.datsoue.prc aswordproperty 792
spring.datsoue.rc lproprtye 279
spring.datsoue.rc snampe roperty 792
SQLYogt ol 381
Stpar. ing.IO
ap ma’s incrlasetdby 167
SpringBootMaenv pluginoc nfiguredby 167
steroypean oati ns
ad ingbeanstoc ntex 41–43
obtrespjc onsibltewith –96 97
prot ypebancos pe,drincla g 14–15
sintogle nbeanosc pe,dinclar g 104–610
Strinypg e 36
System.out 128
T
toarge bject 123
tesing 345
automationtesingap 14–15
impmle enti g ste in Spring ap s 327–34
inratoeg ntes 341–34
unesti 328–034
Springtes atugfe r 10
writngcoreimtly plemendt es –325 326
ă) 2,0 382
392
the-irachteui r 354
to ls 380–381
IDEs 380
MyQS L 381
PotgreSsQL 138
RESTto ls 380
transcionality 123
transcions 130
dnefi d 287
inpS ring 289–290
using Sprinapg s 291–301
Trna sferRequstype 297
Trna sferSvic 317
atrych- finbaly ock 135
Tudose,C
U
untesi 32, 340
UPDATE 316
URI(uniformresourceidntifer) 36
INDEX
webcos pes 23
ăt ălin 24,3 38
impmle enti gwithSpringBootandSpring
MVC 198
dynamicvew 7–1 18
usGETing anPdOSTHTTPmethods 189–197
Springwebscopes
ap caltion-scopedbeans 8–21 21
requst-ceopedbeans 201–082
seion-scopedbeans 209–182
ap caltion-scopedbeans 8–21 21
requst-ceopedbeans 201–082
seion-scopedbeans 209–182
WebClient 246, –256 263
WebFlux 260
wiringbeans 74
cho singfrommultipebna si Spring
conxte 68–73
ciruladepndne cis 6–76
impmle enti lagroe nshipams ongbnea s
defindinconufig ratonfile 51–60
ditmerec thodlbca etwen@Bean
usin@Beg an notaedmeht od’s
V
-voption 231
dvali tons 329
typvar e 34
Vaanr si,Bailaj 24
W
Wals,Craig 7,16 256, 382
wevina g 124
webap s 16
delov ping 10
usin@Au
g towdire an otai ntoinject
beans 61–65
throughclasdfie 61–63
throughconstrucor 64–65
usindg epndeniyc jetonthroughrset 65
writngSpring teraionste 327
writnges 325–326
writngunitoes valdmete thodlo’s gic 327
X
XML 358–359
methods 5–58
parmetrs 58–06
Spring creates a bean and adds it to its context.
Spring uses the type of the bean to create new
instances each time they are requested.
Spring context
@Configuration
public class ProjectConfig {
Adds the bean
@Bean
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public CommentService commentService() {
return new CommentService();
}
}
commentService
Gets an instance
Creates the context
public class Main {
Gets an instance
public static void main(String[] args) {
var c = new AnnotationConfigApplicationContext(ProjectConfig.class);
Figure 1 Using the @Scope
annot ation t o change t he bean
scope in protot ype: t he bean is
now represented as a coffee
plant because you get a new
object instance each t ime you
refer t o it . Variables cs1 and
cs2 will always cont ain
different references, so t he
out put is always “ false.”
var cs1 = c.getBean("commentService", CommentService.class);
var cs2 = c.getBean("commentService", CommentService.class);
boolean b1 = cs1 == cs2;
System.out.println(b1);
}
}
This line always prints “ false.”
Spring creates a new instance
every time the getBean() method
is called. The variables cs1 and cs2
always contain references to two
different instances.
The tasks that need to be performed
Come on folks! We have three
simultaneous requests!
Hey Ginny, I’ll take step 2 of the fi rst request.
Thread 1
Okay George! I’ll take step 3 of the fi rst request.
I see it doesn’t depend on you!
Thread 2
Guys, I’m blocked waiting for the external
credit list on step 4 of the second request.
I’ll leave it for later and start on step 1 of the
third request.
Thread 3
Ginny, the task you left earlier because it was
blocked can be solved now. I’ll continue it!
Thread 4
Figure 2 An analogy of t he way a react ive app works:
all t asks from all request s are on a backlog, and any
available t hread can work on tasks from any request .
JAVA/ SOFTWARE DEVELOPMENT
Spring Start Here
LAU REN ȚI U SPI LCĂ
For Java developers, Spring is the must-learn framework.
This incredible development tool powers everything from
small business ecommerce applications to enterprise-scale
microservices. Mastering Spring is a long journey. Taking
your first step is easy! Start here.
Spring Start Here teaches Java developers how to build applications using Spring framework. Informative graphics,
˘ s clear and
relevant examples, and author Laurentiu
¸ Spilca’
lively writing make it easy to pick up the skills you need.
You’ll discover how to plan, write, and test applications.
And by concentrating on the most important features, this
no-nonsense book gives you a firm foundation for exploring Spring’s rich ecosystem.
W H AT ’S I N SI D E
Build web applications with Spring
● Minimize repetition and manual work
● Persisting data in a Spring application
● HTTP and REST-based web services
● Testing your Spring implementations
●
For readers with beginning to intermediate Java skills.
“Takes you on a quick,
entertaining, and pragmatic
journey into the world
of Spring.”
—Christian Kreutzer-Beck,
ARAG IT
“A well-written and thorough
introduction to Spring and
Spring Boot.”
—Jim Welch
Equifax Workforce Solutions
“Fantastically pragmatic
resource on Spring framework fundamentals.”
—Andrew Oswald
Chariot Solutions
“A great resource for
individuals looking to bridge
the gap from student to
professional developer. A
solid introduction to Spring.”
—Daniel Carl, Oatey Co.
Laurentiu
¸ Spilca˘ is a skilled Java and Spring developer and
an experienced technology instructor.
SEE FIRST PAGE
Register this print book to get free access to all ebook formats.
Visit https:/ / www.manning.com/ freebook
ISBN: 978-1-61729-869-1
M AN N I N G
$49.99 / Can $65.99 [INCLUDING eBOOK]
0
You can add this document to your study collection(s)
Sign in Available only to authorized usersYou can add this document to your saved list
Sign in Available only to authorized users(For complaints, use another form )