Getting Started With Spring Framework, Second Edition J Sharma Ashish Sarin Framework A Hands On Guide To Begin Developing Ap
User Manual:
Open the PDF directly: View PDF .
Page Count: 517 [warning: Documents this large are best viewed by clicking the View PDF Link!]
- Preface
- Chapter 1 – Introduction to Spring Framework
- Chapter 2 – Spring Framework basics
- Chapter 3 - Configuring beans
- Chapter 4 - Dependency injection
- Chapter 5 - Customizing beans and bean definitions
- Chapter 6- Annotation-driven development with Spring
- Chapter 7 - Database interaction using Spring
- Chapter 8 - Messaging, emailing, asynchronous method execution, and caching using Spring
- Chapter 9 - Aspect-oriented programming
- Chapter 10 – Spring Web MVC basics
- Chapter 11 – Validation and data binding in Spring Web MVC
- Chapter 12 –Developing RESTful web services using Spring Web MVC
- Chapter 13 – More Spring Web MVC – internationalization, file upload and asynchronous request processing
- Chapter 14 – Securing applications using Spring Security
- Appendix A – Importing and deploying sample projects in Eclipse IDE (or IntelliJ IDEA)
GettingstartedwithSpringFramework
SecondEdition
AshishSarin,JSharma
Tableofcontents
Preface
Howtousethisbook
Conventionsusedinthisbook
Feedbackandquestions
Abouttheauthors
Chapter1–IntroductiontoSpringFramework
1-1Introduction
1-2SpringFrameworkmodules
1-3SpringIoCcontainer
1-4BenefitsofusingSpringFramework
Consistentapproachtomanaginglocalandglobaltransactions
Declarativetransactionmanagement
Security
JMX(JavaManagementExtensions)
JMS(JavaMessageService)
Caching
1-5AsimpleSpringapplication
Identifyingapplicationobjectsandtheirdependencies
CreatingPOJOclassescorrespondingtoidentifiedapplicationobjects
Creatingtheconfigurationmetadata
CreatinganinstanceofSpringcontainer
AccessbeansfromtheSpringcontainer
1-6FrameworksbuiltontopofSpring
1-7Summary
Chapter2–SpringFrameworkbasics
2-1Introduction
2-2Programmingtointerfacesdesignprinciple
Scenario:Dependentclasscontainsreferencetotheconcreteclassofdependency
Scenario:Dependentclasscontainsreferencetotheinterfaceimplementedbythe
dependency
Spring’ssupportfor‘programmingtointerfaces’designapproach
2-3DifferentapproachestoinstantiatingSpringbeans
Instantiatingbeansviastaticfactorymethods
Instantiatingbeansviainstancefactorymethods
2-4Dependencyinjectiontechniques
Setter-basedDI
Constructor-basedDI
2-5Beanscopes
Singleton
Prototype
Choosingtherightscopeforyourbeans
2-6Summary
Chapter3-Configuringbeans
3-1Introduction
3-2Beandefinitioninheritance
MyBank–Beandefinitioninheritanceexample
Whatgetsinherited?
3-3Constructorargumentmatching
Passingsimplevaluesandbeanreferencesusing<constructor-arg>element
Constructorargumentmatchingbasedontype
Constructorargumentmatchingbasedonname
3-4Configuringdifferenttypesofbeanpropertiesandconstructorarguments
Built-inpropertyeditorsinSpring
Specifyingvaluesfordifferentcollectiontypes
Specifyingvaluesforarrays
Defaultcollectionimplementationfor<list>,<set>and<map>elements
3-5Built-inpropertyeditors
CustomCollectionEditor
CustomMapEditor
CustomDateEditor
3-6RegisteringpropertyeditorswiththeSpringcontainer
CreatingaPropertyEditorRegistrarimplementation
ConfiguringtheCustomEditorConfigurerclass
3-7Concisebeandefinitionswithpandcnamespaces
p-namespace
c-namespace
3-8Spring’sutilschema
<list>
<map>
<set>
<properties>
<constant>
<property-path>
3-9FactoryBeaninterface
MyBankapplication–Storingeventsinthedatabase
MyBank–FactoryBeanexample
AccessingtheFactoryBeaninstance
3-10Summary
Chapter4-Dependencyinjection
4-1Introduction
4-2Innerbeans
4-3Explicitlycontrollingthebeaninitializationorderwithdepends-onattribute
MyBank–implieddependenciesbetweenbeans
Implicitdependencyproblem
4-4Singleton-andprototype-scopedbean’sdependencies
Singleton-scopedbean’sdependencies
Prototype-scopedbean’sdependencies
4-5Obtainingnewinstancesofprototypebeansinsidesingletonbeans
ApplicationContextAwareinterface
<lookup-method>element
<replaced-method>element
4-6Autowiringdependencies
byType
constructor
byName
default/no
Makingbeansunavailableforautowiring
Autowiringlimitations
4-7Summary
Chapter5-Customizingbeansandbeandefinitions
5-1Introduction
5-2Customizingbean’sinitializationanddestructionlogic
MakingSpringinvokecleanupmethodspecifiedbythedestory-methodattribute
Cleanupmethodsandprototype-scopedbeans
Specifyingdefaultbeaninitializationanddestructionmethodsforallbeans
InitializingBeanandDisposableBeanlifecycleinterfaces
JSR250’s@PostConstructand@PreDestroyannotations
5-3InteractingwithnewlycreatedbeaninstancesusingBeanPostProcessor
BeanPostProcessorexample–Validatingbeaninstances
BeanPostProcessorexample–Resolvingbeandependencies
BeanPostProcessorbehaviorforFactoryBeans
RequiredAnnotationBeanPostProcessor
DestructionAwareBeanPostProcessor
5-4ModifyingbeandefinitionsusingBeanFactoryPostProcessor
BeanFactoryPostProcessorexample
PropertySourcesPlaceholderConfigurer
PropertyOverrideConfigurer
5-5Summary
Chapter6-Annotation-drivendevelopmentwithSpring
6-1Introduction
6-2IdentifyingSpringcomponentswith@Component
6-3@Autowired-autowiringdependenciesbytype
6-4@Qualifier–autowiringdependenciesbyname
6-5JSR330’s@Injectand@Namedannotations
6-6JSR250’s@Resourceannotation
6-7@Scope,@Lazy,@DependsOnand@Primaryannotations
6-8Simplifyingcomponentconfigurationusing@Valueannotation
6-9ValidatingobjectsusingSpring’sValidatorinterface
6-10SpecifyingconstraintsusingJSR303annotations
JSR303supportinSpring
6-11ProgrammaticallyconfiguringSpringbeansusing@Configurationand@Bean
annotations
6-12Summary
Chapter7-DatabaseinteractionusingSpring
7-1Introduction
7-2MyBankapplication’srequirements
7-3DevelopingtheMyBankapplicationusingSpring’sJDBCmodule
Configuringadatasource
CreatingDAOsthatuseSpring’sJDBCmoduleclasses
7-4DevelopingtheMyBankapplicationusingHibernate
ConfiguringSessionFactoryinstance
CreatingDAOsthatuseHibernateAPIfordatabaseinteraction
7-5TransactionmanagementusingSpring
MyBank’stransactionmanagementrequirements
Programmatictransactionmanagement
Declarativetransactionmanagement
Spring’ssupportforJTA
7-6Summary
Chapter8-Messaging,emailing,asynchronousmethodexecution,andcachingusing
Spring
8-1Introduction
8-2MyBankapplication’srequirements
8-3SendingJMSmessages
ConfiguringActiveMQbrokertoruninembeddedmode
ConfiguringaJMSConnectionFactory
SendingJMSmessagesusingJmsTemplate
SendingJMSmessageswithinatransaction
DynamicJMSdestinationsandJmsTemplateconfiguration
JmsTemplateandmessageconversion
8-4ReceivingJMSmessages
SynchronouslyreceivingJMSmessagesusingJmsTemplate
AsynchronouslyreceivingJMSmessagesusingmessagelistenercontainers
8-5Sendingemails
8-6Taskschedulingandasynchronousexecution
TaskExecutorinterface
TaskSchedulerinterface
@Asyncand@Scheduledannotations
8-7Caching
ConfiguringaCacheManager
Cachingannotations-@Cacheable,@CacheEvictand@CachePut
8-8RunningtheMyBankapplication
8-9Summary
Chapter9-Aspect-orientedprogramming
9-1Introduction
9-2AsimpleAOPexample
9-3SpringAOPframework
Proxycreation
expose-proxyattribute
9-4Pointcutexpressions
@Pointcutannotation
executionandargspointcutdesignators
beanpointcutdesignator
Annotations-basedpointcutdesignators
9-5Advicetypes
Beforeadvice
Afterreturningadvice
Afterthrowingadvice
Afteradvice
Aroundadvice
9-6SpringAOP-XMLschema-style
ConfiguringanAOPaspect
Configuringanadvice
Associatingapointcutexpressionwithanadvice
9-7Summary
Chapter10–SpringWebMVCbasics
10-1Introduction
10-2Directorystructureofsamplewebprojects
10-3Understandingthe‘HelloWorld’webapplication
HelloWorldController.java–HelloWorldwebapplication’scontrollerclass
helloworld.jsp–JSPpagethatshowsthe‘HelloWorld!!’message
myapp-config.xml–WebapplicationcontextXMLfile
web.xml–Webapplicationdeploymentdescriptor
10-4DispatcherServlet–thefrontcontroller
AccessingServletContextandServletConfigobjects
10-5Developingcontrollersusing@Controllerand@RequestMappingannotations
Developinga‘HelloWorld’webapplicationusinganannotatedcontroller
10-6MyBankwebapplication’srequirements
10-7SpringWebMVCannotations-@RequestMappingand@RequestParam
Mappingrequeststocontrollersorcontrollermethodsusing@RequestMapping
@RequestMappingannotatedmethodsarguments
@RequestMappingannotatedmethodsreturntypes
Passingrequestparameterstocontrollermethodsusing@RequestParam
10-8Validation
10-9Handlingexceptionsusing@ExceptionHandlerannotation
10-11LoadingrootwebapplicationcontextXMLfile(s)
10-12Summary
Chapter11–ValidationanddatabindinginSpringWebMVC
11-1Introduction
11-2Addingandretrievingmodelattributesusing@ModelAttributeannotation
Addingmodelattributesusingmethod-level@ModelAttributeannotation
Retrievingmodelattributesusing@ModelAttributeannotation
Requestprocessingand@ModelAttributeannotatedmethods
Behaviorof@ModelAttributeannotatedmethodarguments
RequestToViewNameTranslator
11-3Cachingmodelattributesusing@SessionAttributesannotation
11-4DatabindingsupportinSpring
WebDataBinder–databinderforwebrequestparameters
ConfiguringaWebDataBinderinstance
Allowingordisallowingfieldsfromdatabindingprocess
InspectingdatabindingandvalidationerrorsusingBindingResultobject
11-5ValidationsupportinSpring
ValidatingmodelattributesusingSpring’sValidatorinterface
SpecifyingconstraintsusingJSR303annotations
ValidatingobjectsthatuseJSR303annotations
11-6Spring’sformtaglibrary
HTML5supportinSpring’sformtaglibrary
11-7Summary
Chapter12–DevelopingRESTfulwebservicesusingSpringWebMVC
12-1Introduction
12-2Fixeddepositwebservice
12-3ImplementingaRESTfulwebserviceusingSpringWebMVC
JSON(JavaScriptObjectNotation)
FixedDepositWSwebserviceimplementation
12-4AccessingRESTfulwebservicesusingRestTemplate
12-5ConvertingJavaobjectstoHTTPrequestsandresponsesandviceversausing
HttpMessageConverter
12-6@PathVariableand@MatrixVariableannotations
12-7Summary
Chapter13–MoreSpringWebMVC–internationalization,fileuploadand
asynchronousrequestprocessing
13-1Introduction
13-2Pre-andpost-processingrequestsusinghandlerinterceptors
Implementingandconfiguringahandlerinterceptor
13-3Internationalizingusingresourcebundles
MyBankwebapplication’srequirements
InternationalizingandlocalizingMyBankwebapplication
13-4Asynchronouslyprocessingrequests
Asynchronousrequestprocessingconfiguration
ReturningCallablefrom@RequestMappingmethods
ReturningDeferredResultfrom@RequestMappingmethods
Settingdefaulttimeoutvalue
Interceptingasynchronousrequests
13-5TypeconversionandformattingsupportinSpring
CreatingacustomConverter
ConfiguringandusingacustomConverter
CreatingacustomFormatter
ConfiguringacustomFormatter
CreatingAnnotationFormatterFactorytoformatonly@AmountFormatannotated
fields
ConfiguringAnnotationFormatterFactoryimplementation
13-6FileuploadsupportinSpringWebMVC
UploadingfilesusingCommonsMultipartResolver
UploadingfilesusingStandardServletMultipartResolver
13-7Summary
Chapter14–SecuringapplicationsusingSpringSecurity
14-1Introduction
14-2SecurityrequirementsoftheMyBankwebapplication
14-3SecuringMyBankwebapplicationusingSpringSecurity
Webrequestsecurityconfiguration
Authenticationconfiguration
SecuringJSPcontentusingSpringSecurity’sJSPtablibrary
Securingmethods
14-4MyBankwebapplication-securingFixedDepositDetailsinstancesusingSpring
Security’sACLmodule
Deployingandusingch14-bankapp-db-securityproject
DatabasetablestostoreACLanduserinformation
Userauthentication
Webrequestsecurity
JdbcMutableAclServiceconfiguration
Method-levelsecurityconfiguration
Domainobjectinstancesecurity
ManagingACLentriesprogrammatically
MutableAclandsecurity
14-5Summary
AppendixA–ImportinganddeployingsampleprojectsinEclipseIDE(orIntelliJ
IDEA)
A-1Settingupthedevelopmentenvironment
A-2ImportingasampleprojectintoEclipseIDE(orIntelliJIDEA)
Importingasampleproject
ConfiguringtheM2_REPOclasspathvariableintheEclipseIDE
A-3ConfiguringEclipseIDEwithTomcat7server
A-4DeployingawebprojectonTomcat7server
RunningtheTomcat7serverinembeddedmode
Preface
Howtousethisbook
Downloadsampleprojects
This book comes with many sample projects that you can download from the following Google Code
project:http://code.google.com/p/getting-started-with-spring-framework-2edition/.Youcandownloadthe
sampleprojectsasasingleZIPfileoryoucancheckoutthesampleprojectsusingSVN.Formoredetails,
refertotheaboveURL.
ImportsampleprojectsintoyourEclipseorIntelliJIDEAIDE
IfyouseeIMPORTchapter<chapter-number>/<projectname>at anypoint while reading the book,
youshouldimportthespecifiedprojectintoyourEclipseorIntelliJIDEAIDE(oranyotherIDEthatyou
areusing).ThesampleprojectsuseMaven3.xbuildtoolforbuildingtheproject;therefore,you’llfinda
pom.xmlfileinsideeachoftheprojects.Apom.xmlfileisalsoprovidedattherootofthesourcecode
distribution,whichbuildsalltheprojects.
ReferappendixAtoseethestepsrequiredforimportingandrunningthesampleprojects.
Refertocodeexamples
Each example listing specifies the sample project name (using Project label) and the location of the
sourcefile(usingSourcelocationlabel).IftheProjectandSourcelocationlabelsarenotspecified,you
canassumethatthecodeshownintheexamplelistingisnotbeingusedanywhereinthesampleprojects,
andithasbeenshownpurelytosimplifyunderstanding.
Conventionsusedinthisbook
Italicshasbeenusedforemphasizingterms
Comic Sans MS has been used for example listings, Java code, configuration details in XML and
propertiesfiles
Comic Sans MS has been used in example listings to highlight important parts of the code or
configuration
ANOTEhighlightsanimportaintpoint.
Feedbackandquestions
You can post your feedback and questions to the authors in the following Google Groups forum:
https://groups.google.com/forum/#!forum/getting-started-with-spring-framework
Abouttheauthors
AshishSarinisaSunCertifiedEnterpriseArchitectwithmorethan14yearsofexperienceinarchitecting
applications.HeistheauthorofSpringRoo1.1Cookbook(byPacktPublishing)andPortletsinAction
(byManningPublications)
JSharmaisafreelanceJavadeveloperwithextensiveexperienceindevelopingSpringapplications.
Chapter1–IntroductiontoSpringFramework
1-1Introduction
InthetraditionalJavaenterpriseapplicationdevelopmentefforts,itwasadeveloper’sresponsibilityto
createwell-structured,maintainableandeasilytestableapplications.Thedevelopersusedmyriaddesign
patternstoaddressthesenon-businessrequirementsofanapplication.Thisnotonlyledtolowdeveloper
productivity,butalsoadverselyaffectedthequalityofdevelopedapplications.
Spring Framework (or ‘Spring’ in short) is an open source application framework from SpringSource
(http://www.springsource.org) that simplifies developing Java enterprise applications. It provides the
infrastructurefordevelopingwell-structured,maintainableandeasilytestableapplications.Whenusing
Spring Framework, a developer only needs to focus on writing the business logic of the application,
resultinginimproveddeveloperproductivity.YoucanuseSpringFrameworktodevelopstandaloneJava
applications,webapplications,applets,oranyothertypeofJavaapplication.
ThischapterstartsoffwithanintroductiontoSpringFrameworkmodulesanditsbenefits.Attheheartof
SpringFrameworkisitsInversionofControl(IoC)container,whichprovidesdependencyinjection(DI)
feature. This chapter introduces Spring’s DIfeature and IoC container, and shows how to develop a
standalone Java application using Spring. Towards the end of this chapter, we’ll look at some of the
SpringSource’sprojectsthatuseSpringFrameworkastheirfoundation.Thischapterwillsetthestagefor
theremainingchaptersthatdelvedeeperintotheSpringFramework.
NOTEInthisbook,we’lluseanexampleInternetBankingapplication,MyBank,tointroduceSpring
Frameworkfeatures.
1-2SpringFrameworkmodules
SpringFrameworkconsistsofmultiplemodulesthataregroupedbasedontheapplicationdevelopment
featurestheyaddress.ThefollowingtabledescribesthedifferentmodulegroupsinSpringFramework:
Modulegroup Description
Corecontainer
ContainsmodulesthatformthefoundationofSpringFramework.Themodulesinthisgroup
provideSpring’sDIfeatureandIoCcontainerimplementation.
AOPand
instrumentation
Contains modules that support AOP (Aspect-oriented Programming) and class
instrumentation.
DataAccess/Integration
Contains modules that simplify interaction with databases and messaging providers. This
modulegroupalsocontainsmodulesthatsupportprogrammaticanddeclarativetransaction
management,andobject/XM Lmappingimplementations,likeJAXBandCastor.
Web Containsmodulesthatsimplifydevelopingwebandportletapplications.
Test Containsasinglemodulethatsimplifiescreatingunitandintegrationtests.
TheabovetableshowsthatSpringcoverseveryaspectofenterpriseapplicationdevelopment;youcan
useSpringfordevelopingwebapplications,accessingdatabases,managingtransactions,creatingunitand
integration tests, and so on. The Spring Framework modules are designed in such a way that you only
needtoincludethemodulesthatyourapplicationneeds.Forinstance,touseSpring’sDIfeatureinyour
application,youonlyneedtoincludethemodulesgroupedunderCorecontainer.Asyouprogressthrough
thisbook,you’llfinddetailsofsomeofthemodulesthatarepartofSpring,andexamplesthatshowhow
theyareusedindevelopingapplications.
Thefollowingfigureshowstheinter-dependenciesofdifferentmodulesofSpring:
Figure1-1Springmodulesinter-dependencies
YoucaninferfromtheabovefigurethatthemodulescontainedintheCorecontainergrouparecentralto
theSpringFramework,andothermodulesdependonit.Equallyimportantarethemodulescontainedin
theAOPandinstrumentationgroupbecausetheyprovideAOPfeaturestoothermodulesintheSpring
Framework.
Now,thatyouhavesomebasicideaabouttheareasofapplicationdevelopmentcoveredbySpring,let’s
lookattheSpringIoCcontainer.
1-3SpringIoCcontainer
AJavaapplicationconsistsofobjectsthatinteractwitheachothertoprovideapplicationbehavior.The
objectswithwhichanobjectinteractsarereferredtoasitsdependencies.Forinstance,ifanobjectX
interactswithobjectsYandZ,thenYandZaredependenciesofobjectX.DIisadesignpatterninwhich
thedependenciesofanobjectaretypicallyspecifiedasargumentstoitsconstructorandsettermethods.
And,thesedependenciesareinjectedintotheobjectwhenit’screated.
In a Spring application, Spring IoC container (also referred to as Spring container) is responsible for
creating application objects and injecting their dependencies. The application objects that the Spring
containercreatesandmanagesarereferredasbeans.AstheSpringcontainerisresponsibleforputting
togetherapplicationobjects,youdon’tneedtoimplementdesignpatterns,likeFactory,ServiceLocator,
andsoon,tocomposeyourapplication.DIisalsoreferredtoasInversionofControl(IoC)becausethe
responsibilityofcreatingandinjectingdependenciesisnotwiththeapplicationobjectbutwiththeSpring
container.
Let’ssaythattheMyBankapplication(whichisthenameofoursampleapplication)containstwoobjects,
FixedDepositController and FixedDepositService. The following example listing shows that the
FixedDepositControllerobjectdependsonFixedDepositServiceobject:
Examplelisting1-1:FixedDepositControllerclass
publicclassFixedDepositController{
privateFixedDepositServicefixedDepositService;
publicFixedDepositController(){
fixedDepositService=newFixedDepositService();
}
publicbooleansubmit(){
//--savethefixeddepositdetails
fixedDepositService.save(.....);
}
}
In the above example listing, FixedDepositController’s constructor creates an instance of
FixedDepositService which is later used in FixedDepositController’s submit method. As
FixedDepositController interacts with FixedDepositService, FixedDepositService represents a
dependencyofFixedDepositController.
To configure FixedDepositController as a Spring bean, you first need to modify the
FixedDepositControllerclassofexamplelisting1-1suchthatitacceptsFixedDepositServicedependency
as a constructor argument or as a setter method argument. The following example listing shows the
modifiedFixedDepositControllerclass:
Example listing 1-2: FixedDepositController class – FixedDepositService is passed as a constructor
argument
publicclassFixedDepositController{
privateFixedDepositServicefixedDepositService;
publicFixedDepositController(FixedDepositServicefixedDepositService){
this.fixedDepositService=fixedDepositService;
}
publicbooleansubmit(){
//--savethefixeddepositdetails
fixedDepositService.save(.....);
}
}
TheaboveexamplelistingshowsthattheFixedDepositServiceinstanceisnowpassedasaconstructor
argumenttotheFixedDepositControllerinstance.Now,theFixedDepositServiceclasscanbeconfigured
as a Spring bean. Notice that the FixedDepositController class doesn’t implement or extend from any
Springinterfaceorclass.
Foragivenapplication,informationaboutapplicationobjectsandtheirdependenciesisspecifiedusing
configurationmetadata. Spring IoC container reads application’s configuration metadata to instantiate
applicationobjectsandinjecttheirdependencies.Thefollowingexamplelistingshowstheconfiguration
metadata(inXMLformat)foranapplicationthatconsistsofMyControllerandMyServiceclasses:
Examplelisting1-3:Configurationmetadata
<beans.....>
<beanid="myController"class="sample.spring.controller.MyController">
<constructor-argindex="0"ref="myService"/>
</bean>
<beanid="myService"class="sample.spring.service.MyService"/>
</beans>
Intheaboveexamplelisting,each<bean>elementdefinesanapplicationobjectthatismanagedbythe
Springcontainer,andthe<constructor-arg>elementspecifiesthataninstanceofMyServiceispassedas
anargumenttoMyController’sconstructor.The<bean>elementisdiscussedindetaillaterinthischapter,
andthe<constructor-arg>elementisdiscussedinchapter2.
Spring container reads the configuration metadata (like the one shown in example listing 1-3) of an
application and creates the application objects defined by <bean> elements and injects their
dependencies. Spring container makes use of Java Reflection API
(http://docs.oracle.com/javase/tutorial/reflect/index.html) to create application objects and inject their
dependencies.ThefollowingfiguresummarizeshowtheSpringcontainerworks:
Figure 1-2 Spring container reads application’s configuration metadata and creates a fully-configured
application
TheconfigurationmetadatacanbesuppliedtotheSpringcontainerviaXML(asshowninexamplelisting
1-3),Javaannotations(referchapter6)andalsothroughtheJavacode(referchapter6).
AstheSpringcontainerisresponsibleforcreatingandmanagingapplicationobjects,enterpriseservices
(like transaction management, security, remote access, and so on) can be transparently applied to the
objectsbytheSpringcontainer.TheabilityoftheSpringcontainertoenhancetheapplicationobjectswith
additional functionality makes it possible for you to model your application objects as simple Java
objects(alsoreferredtoasPOJOsorPlainOldJavaObjects).JavaclassescorrespondingtoPOJOs
are referred to as POJO classes, which are nothing but Java classes that don’t implement or extend
framework-specificinterfacesorclasses.Theenterpriseservices,liketransactionmanagement,security,
remoteaccess,andsoon,requiredbythesePOJOsaretransparentlyprovidedbytheSpringcontainer.
Now,thatweknowhowSpringcontainerworks,let’slookatsomeexamplesthatdemonstratebenefitsof
developingapplicationsusingSpring.
1-4BenefitsofusingSpringFramework
Intheprevioussection,wediscussedthefollowingbenefitsofusingSpring:
§Springsimplifiescomposing Javaapplications bytakingcare ofcreating applicationobjects and
injectingtheirdependencies
§SpringpromotesdevelopingapplicationsasPOJOs
SpringalsosimplifiesinteractionwithJMSproviders,JNDI,MBeanservers,emailservers,databases,
andsoon,byprovidingalayerofabstractionthattakescareoftheboilerplatecode.
Let’s take a quick look at a few examples to better understand the benefits of developing applications
usingSpring.
Consistentapproachtomanaginglocalandglobaltransactions
If you are using Spring for developing transactional applications, you can use Spring’s declarative
transactionmanagementsupporttomanagetransactions.
ThefollowingexamplelistingshowstheFixedDepositServiceclassofMyBankapplication:
Examplelisting1-4–FixedDepositServiceclass
publicclassFixedDepositService{
publicFixedDepositDetailsgetFixedDepositDetails(.....){.....}
publicbooleancreateFixedDeposit(FixedDepositDetailsfixedDepositDetails){.....}
}
TheFixedDepositService class is a POJO class that defines methods to create and retrieve details of
fixeddeposits.Thefollowingfigureshowstheformforcreatinganewfixeddeposit:
Figure1-3HTMLformforcreatinganewfixeddeposit
Acustomerentersthefixeddepositamount,tenureandemailidinformationintheaboveformandclicks
theSave button to create a new fixed deposit. The FixedDepositService’s createFixedDeposit method
(referexamplelisting1-1)isinvokedtocreatethefixeddeposit.ThecreateFixedDepositmethoddebits
theamountenteredbythecustomerfromhisbankaccount,andcreatesafixeddepositofthesameamount.
Let’ssaythatinformationaboutthebankbalanceofcustomersisstoredinBANK_ACCOUNT_DETAILS
databasetable,andthefixeddepositdetailsarestoredinFIXED_DEPOSIT_DETAILSdatabasetable.If
a customer creates a fixed deposit of amount x, amount x is subtracted from the
BANK_ACCOUNT_DETAILStable,andanewrecordisinsertedinFIXED_DEPOSIT_DETAILStable
toreflectthenewlycreatedfixeddeposit.IfBANK_ACCOUNT_DETAILStableisnotupdatedoranew
recordisnotinsertedinFIXED_DEPOSIT_DETAILStable,it’llleavethesysteminaninconsistentstate.
ThismeansthecreateFixedDepositmethodmustbeexecutedwithinatransaction.
The database used by the MyBank application represents a transactional resource. In the traditional
approachtoperforma setof databasemodificationsasasingleunitof work,you’llfirstdisableauto-
commit mode of JDBC connection, then execute SQL statements, and finally commit (or rollback) the
transaction. The following example listing shows how to manage database transactions in the
createFixedDepositmethodusingthetraditionalapproach:
Examplelisting1-5–ProgrammaticallymanagingdatabasetransactionusingJDBCConnectionobject
importjava.sql.Connection;
importjava.sql.SQLException;
publicclassFixedDepositService{
publicFixedDepositDetailsgetFixedDepositDetails(.....){.....}
publicbooleancreateFixedDeposit(FixedDepositDetailsfixedDepositDetails){
Connectioncon=.....;
try{
con.setAutoCommit(false);
//--executeSQLstatementsthatmodifydatabasetables
con.commit();
}catch(SQLExceptionsqle){
if(con!=null){
con.rollback();
}
}
.....
}
}
TheaboveexamplelistingshowsthatthecreateFixedDepositmethodprogrammaticallymanagesdatabase
transactionusingJDBCConnectionobject.Thisapproachissuitableforapplicationscenariosinwhicha
singledatabaseisinvolved.Transactionsthatareresource-specific,likethetransactionassociatedwitha
JDBCConnection,arereferredtoaslocaltransactions.
When multiple transactional resources are involved, JTA (Java Transaction API) is used for managing
transactions.Forinstance,ifyouwanttosendaJMSmessagetoamessagingmiddleware(atransactional
resource)andupdateadatabase(anothertransactionalresource)inthesametransaction,youmustusea
JTA transaction manager to manage transactions. JTA transactions are also referred to as global (or
distributed)transactions.TouseJTA,youfetchUserTransactionobject(whichispartofJTAAPI)from
JNDIandprogrammaticallystartandcommit(orrollback)transactions.
As you can see, you can either useJDBC Connection (for local transactions) or UserTransaction (for
globaltransactions)objecttoprogrammaticallymanage transactions.Itisimportanttonotethatalocal
transaction cannot run within a global transaction. This means that if you want database updates in
createFixedDepositmethod(referexamplelisting1-5)tobepartofaJTAtransaction,youneedtomodify
thecreateFixedDepositmethodtousetheUserTransactionobjectfortransactionmanagement.
Spring simplifies transaction management by providing a layer of abstraction that gives a consistent
approach to managing both local and global transactions. This means that if you write the
createFixedDepositmethod(referexamplelisting1-5)usingSpring’stransactionabstraction,youdon’t
needtomodifythemethodwhenyouswitchfromlocaltoglobaltransactionmanagement,orviceversa.
Spring’stransactionabstractionisexplainedinchapter7.
Declarativetransactionmanagement
Springgivesyoutheoptiontousedeclarativetransactionmanagement.Youcanannotateamethodwith
Spring’s@TransactionalannotationandletSpringhandletransactions,asshownhere:
Examplelisting1-6–@Transactionalannotationusage
importorg.springframework.transaction.annotation.Transactional;
publicclassFixedDepositService{
publicFixedDepositDetailsgetFixedDepositDetails(.....){.....}
@Transactional
publicbooleancreateFixedDeposit(FixedDepositDetailsfixedDepositDetails){.....}
}
TheaboveexamplelistingshowsthattheFixedDepositServiceclassdoesn’timplementorextendfrom
any Spring-specific interface or class to use Spring’s transaction management facility. The Spring
Framework transparently provides transaction management feature to @Transactional annotated
createFixedDeposit method. This shows that Spring is a non-invasive framework because it doesn’t
require your application objects to be dependent upon Spring-specific classes or interfaces. Also, you
don’tneedtodirectlyworkwithtransactionmanagementAPIstomanagetransactions.
Security
Security is an important aspect of any Java application. Spring Security
(http://static.springsource.org/spring-security/site/) is a SpringSource’s project that is built on top of
SpringFramework.SpringSecurityprovidesauthenticationandauthorizationfeaturesthatyoucanusefor
securingJavaapplications.
Let’s say that the following 3 user roles have been identified for the MyBank application:
LOAN_CUSTOMER, SAVINGS_ACCOUNT_CUSTOMER and APPLICATION_ADMIN. A customer
mustbeassociatedwiththeSAVINGS_ACCOUNT_CUSTOMERortheAPPLICATION_ADMINroleto
invokethecreateFixedDepositmethod of FixedDepositService class (refer example listing 1-6). Using
Spring Security youcan easily address this requirementby annotating createFixedDeposit method with
SpringSecurity’s@Securedannotation,asshowninthefollowingexamplelisting:
Examplelisting1-7–SecuredcreateFixedDepositmethod
importorg.springframework.transaction.annotation.Transactional;
importorg.springframework.security.access.annotation.Secured;
publicclassFixedDepositService{
publicFixedDepositDetailsgetFixedDepositDetails(.....){.....}
@Transactional
@Secured({"SAVINGS_ACCOUNT_CUSTOMER","APPLICATION_ADMIN"})
publicbooleancreateFixedDeposit(FixedDepositDetailsfixedDepositDetails){.....}
}
If you annotate a method with Spring Security’s @Secured annotation, security feature is transparently
applied to the method by the Spring Security framework. The above example listing shows that for
implementingmethod-levelsecurityyoudon’tneedtoextendorimplementanySpring-specificclassesor
interfaces.Also,youdon’tneedtowritesecurity-relatedcodeinyourbusinessmethods.
SpringSecurityframeworkisdiscussedindetailinchapter14.
JMX(JavaManagementExtensions)
Spring’sJMXsupportsimplifiesincorporatingJMXtechnologyinyourapplications.
Let’ssaythatthefixeddepositfacilityofMyBankapplicationshouldonlybeavailabletocustomersfrom
9:00 AM to 6:00 PM everyday. To address this requirement, a variable is added to the
FixedDepositServiceclass,whichactsasaflagindicatingwhetherthefixeddepositserviceisactiveor
inactive.ThefollowingexamplelistingshowstheFixedDepositServiceclassthatusessuchaflag:
Examplelisting1-8–FixedDepositServicewithactivevariable
publicclassFixedDepositService{
privatebooleanactive;
publicFixedDepositDetailsgetFixedDepositDetails(.....){
if(active){.....}
}
publicbooleancreateFixedDeposit(FixedDepositDetailsfixedDepositDetails){
if(active){.....}
}
publicvoidactivateService(){
active=true;
}
publicvoiddeactivateService(){
active=false;
}
}
TheaboveexamplelistingshowsthatavariablenamedactiveisaddedtotheFixedDepositServiceclass.
If the value of the active variable is true, the getFixedDepositDetails and createFixedDeposit methods
work as expected. If the value of the active variable is false, the getFixedDepositDetails and
createFixedDeposit methods throw an exception indicating that the fixed deposit service is currently
inactive.TheactivateServiceanddeactivateServicemethodssetthevalueofactivevariabletotrueand
false,respectively.
Now, who calls the activateService and deactivateService methods? Let’s say a separate scheduler
application, Bank App Scheduler, runs at 9:00 AM and 6:00 PM to execute activateService and
deactivateService methods, respectively. The Bank App Scheduler application uses JMX (Java
ManagementExtensions)APItoremotelyinteractwithFixedDepositServiceinstance.
NOTE Refer to the following article to learn more about JMX:
http://docs.oracle.com/javase/tutorial/jmx/index.html.
AsBankAppSchedulerusesJMXtochangethevalueoftheactivevariableoftheFixedDepositService
instance,youneedtoregistertheFixedDepositServiceinstanceasamanagedbean(orMBean)withan
MBean server, and expose FixedDepositService’s activateService and deactivateService methods as
JMXoperations.InSpring,youregisterinstancesofaclasswiththeMBeanserverbyannotatingtheclass
withSpring’s @ManagedResource annotation, and expose the methods of the class as JMX operations
usingSpring’s@ManagedOperationannotation.
Thefollowingexamplelistingshowsusageof@ManagedResourceand@ManagedOperationannotations
to register instances of the FixedDepositService class with the MBean server, and to expose its
activateServiceanddeactivateServicemethodsasJMXoperations:
Examplelisting1-9–FixedDepositServiceclassthatusesSpring’sJMXsupport
importorg.springframework.jmx.export.annotation.ManagedOperation;
importorg.springframework.jmx.export.annotation.ManagedResource;
@ManagedResource(objectName="fixed_deposit_service:name=FixedDepositService")
publicclassFixedDepositService{
privatebooleanactive;
publicFixedDepositDetailsgetFixedDepositDetails(.....){
if(active){.....}
}
publicbooleancreateFixedDeposit(FixedDepositDetailsfixedDepositDetails){
if(active){.....}
}
@ManagedOperation
publicvoidactivateService(){
active=true;
}
@ManagedOperation
publicvoiddeactivateService(){
active=false;
}
}
The above example listing shows that the FixedDepositService class doesn’t directly use JMX API to
registeritsinstanceswiththeMBeanserverandtoexposeitsmethodsasJMXoperations.
JMS(JavaMessageService)
Spring’sJMSsupportsimplifiessendingandreceivingmessagesfromJMSproviders.
InMyBankapplication,whenacustomersubmitsarequesttoreceivedetailsoftheirfixeddepositsvia
email, the FixedDepositService sends the request details to a JMS messaging middleware (like
ActiveMQ).Therequestislaterprocessedbyamessagelistener.SpringsimplifiesinteractionwithJMS
providers by providing a layer of abstraction. The following example listing shows how
FixedDepositServiceclasssendsrequestdetailstoaJMSproviderusingSpring’sJmsTemplate:
Examplelisting1-10–FixedDepositServicethatsendsJMSmessages
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.jms.core.JmsTemplate;
publicclassFixedDepositService{
@Autowired
privatetransientJmsTemplatejmsTemplate;
.....
publicbooleansubmitRequest(Requestrequest){
jmsTemplate.convertAndSend(request);
}
}
TheaboveexamplelistingshowsthattheFixedDepositServicedefinesavariableoftypeJmsTemplate,
andisannotatedwithSpring’s@Autowiredannotation.Fornow,youcanassumethatthe@Autowired
annotationprovidesaccesstoaJmsTemplateinstance.TheJmsTemplateinstanceknowsabouttheJMS
destinationtowhichtheJMSmessageistobesent.HowtheJmsTemplateisconfiguredisdescribedin
detail in chapter 8. The FixedDepositService’s submitRequest method invokes JmsTemplate’s
convertAndSend method to send request details (represented by Request argument of submitRequest
method)asaJMSmessagetotheJMSprovider.
Onceagain,theaboveexamplelistingshowsthatifyouareusingSpringFrameworktosendmessagesto
JMSproviders,thenyoudon’tneedtodirectlydealwithJMSAPI.
Caching
Spring’scacheabstractionprovidesaconsistentapproachtousecachinginyourapplication.
It’scommontousecachingsolutionstoimprovetheperformanceofanapplication.MyBankapplication
usesacachingproducttoimprovetheperformanceofreadoperationsforfixeddepositdetails.Spring
Frameworksimplifiesinteractingwithdifferentcachingsolutionsbyabstractingcaching-relatedlogic.
ThefollowingexamplelistingshowsthattheFixedDepositService’sgetFixedDepositDetailsmethoduses
Spring’scacheabstractionfeaturetocachefixeddepositdetails:
Examplelisting1-11–FixedDepositServicethatcachesfixeddepositdetails
importorg.springframework.cache.annotation.Cacheable;
publicclassFixedDepositService{
@Cacheable("FixedDeposits")
publicFixedDepositDetailsgetFixedDepositDetails(.....){.....}
publicbooleancreateFixedDeposit(FixedDepositDetailsfixedDepositDetails){.....}
}
In the above example listing, Spring’s @Cacheable annotation indicates that the fixed deposit details
returned by the getFixedDepositDetails method are cached. If the getFixedDepositDetails method is
invoked with the same argument value(s), the getFixedDepositDetails method is not executed, and the
fixeddepositdetailsarereturnedfromthecache.ThisshowsthatifyouareusingSpringFrameworkyou
don’tneedtowritecaching-relatedlogicinyourclasses.Spring’scacheabstractionisexplainedindetail
inchapter8.
In this section, we saw that Spring Framework simplifies developing enterprise applications by
transparentlyprovidingservicestoPOJOs,thereby shieldingdevelopersfrom lowerlevelAPIdetails.
Spring also provides easy integration with standard frameworks, like Hibernate, iBATIS, Quartz, JSF,
Struts,EJB,andsoon,whichmakesSpringanidealchoiceforenterpriseapplicationdevelopment.
Now,thatwehavelookedatsomeofthebenefitsofusingSpringFramework,let’stakealookathowto
developasimpleSpringapplication.
1-5AsimpleSpringapplication
Inthissection,we’lllookatasimpleSpringapplicationthatusesSpring’sDIfeature.TouseSpring’sDI
featureinanapplication,followthesesteps:
1.identifyapplicationobjectsandtheirdependencies
2.createPOJOclassescorrespondingtotheapplicationobjectsidentifiedinstep1
3.createconfigurationmetadatathatdepictsapplicationobjectsandtheirdependencies
4.createaninstanceofSpringIoCcontainerandpasstheconfigurationmetadatatoit
5.accessapplicationobjectsfromtheSpringIoCcontainerinstance
Let’snowlookatabovementionedstepsinthecontextofMyBankapplication.
Identifyingapplicationobjectsandtheirdependencies
WediscussedearlierthattheMyBankapplicationshowsaformforcreatingafixeddeposit(referfigure
1-3) to its users for creating a fixed deposit. The following sequence diagram shows the application
objects(andtheirinteraction)thatcomeintopicturewhentheusersubmitstheform:
Figure1-4MyBank’sapplicationobjectsandtheirdependencies
In the above sequence diagram, FixedDepositController represents a web controller that receives the
requestwhentheformissubmitted.ThefixeddepositdetailsarecontainedintheFixedDepositDetails
object.TheFixedDepositController invokes the createFixedDeposit method of FixedDepositService (a
servicelayerobject).Then,FixedDepositServiceinvokesFixedDepositDaoobject(adataaccessobject)
to save the fixed deposit details in the application’s data store. So, we can interpret from the above
diagram that FixedDepositService is a dependency of FixedDepositController object, and
FixedDepositDaoisadependencyofFixedDepositServiceobject.
IMPORT chapter 1/ch01-bankapp-xml (This project shows a simple Spring application that uses
Spring’s DI feature. To run the application, execute the main method of the MyBankApp class of this
project)
CreatingPOJOclassescorrespondingtoidentifiedapplicationobjects
Onceyouhaveidentifiedapplicationobjects,thenextstep istocreatePOJOclassescorresponding to
these application objects. POJO classes corresponding to the FixedDepositController,
FixedDepositService and FixedDepositDao application objects are available in ch01-bankapp-xml
project.Thech01-bankapp-xmlprojectrepresentsasimplifiedversionofMyBankapplicationthatuses
Spring’sDIfeature.Youshouldimportthech01-bankapp-xmlprojectintoyourIDEasintheremaining
stepswe’llbelookingatthefilescontainedinthisproject.
In section 1-3 we discussed that a dependency is passed to an application object as a constructor
argument or as a setter method argument. The following code listing shows that an instance of
FixedDepositService(adependencyofFixedDepositController)ispassedasasettermethodargumentto
theFixedDepositControllerobject:
Examplelisting1-12–FixedDepositControllerclass
Project–ch01-bankapp-xml
Sourcelocation-src/main/java/sample/spring/chapter01/bankapp
packagesample.spring.chapter01.bankapp;
.....
publicclassFixedDepositController{
.....
privateFixedDepositServicefixedDepositService;
.....
publicvoidsetFixedDepositService(FixedDepositServicefixedDepositService){
logger.info("SettingfixedDepositServiceproperty");
this.fixedDepositService=fixedDepositService;
}
.....
publicvoidsubmit(){
fixedDepositService.createFixedDeposit(newFixedDepositDetails(1,10000,
365,"someemail@something.com"));
}
.....
}
In the above example listing, FixedDepositService dependency is passed to FixedDepositController
throughsetFixedDepositServicemethod.We’llsoonseethatthesetFixedDepositServicesettermethodis
invokedbySpring.
NOTE If you look at the FixedDepositController,FixedDepositService and FixedDepositDao classes,
you’ll notice that none of these classes implement any Spring-specific interface or extend from any
Spring-specificclass.
Let’s now look at how application objects and their dependencies are specified in the configuration
metadata.
Creatingtheconfigurationmetadata
We saw in section 1-3 that the configuration metadata specifies application objects and their
dependencies, which is read by the Spring container to instantiate application objects and inject their
dependencies.Inthissection,we’llfirstlookatwhatotherinformationiscontainedintheconfiguration
metadata,followedbyanin-depthlookathowconfigurationmetadataisspecifiedinXMLformat.
The configuration metadata specifies information about the enterprise services (like transaction
management,securityandremoteaccess)thatarerequiredbytheapplication.Forinstance,ifyouwant
Spring to manage transactions, you need to configure an implementation of Spring’s
PlatformTransactionManager interface in the configuration metadata. The PlatformTransactionManager
implementation is responsible for managing transactions (refer chapter 7 to know more about Spring’s
transactionmanagementfeature).
Ifyourapplicationinteractswithmessagingmiddlewares(likeActiveMQ),databases(likeMySQL),e-
mailservers,andsoon,thenSpring-specificobjectsthatsimplifyinteractingwiththeseexternalsystems
arealsodefinedintheconfigurationmetadata.Forinstance,ifyourapplicationsendsorreceivesJMS
messages from ActiveMQ, then you can configure Spring’s JmsTemplate class in the configuration
metadata to simplify interaction with ActiveMQ. We saw in example listing 1-10 that if you use
JmsTemplateforsendingmessagestoaJMSprovider,thenyoudon’tneedtodealwithlower-levelJMS
API(referchapter8toknowmoreaboutSpring’ssupportforinteractingwithJMSproviders).
YoucansupplytheconfigurationmetadatatotheSpringcontainerviaanXMLfileorthroughannotations
inPOJOclasses.StartingwithSpring3.0,youcanalsosupplytheconfigurationmetadatatotheSpring
containerthroughJavaclassesannotatedwithSpring’s@Configurationannotation.Inthissection,we’ll
seehow configurationmetadata is specifiedinXMLformat.In chapter 6,we’ll see how configuration
metadataissuppliedviaannotationsinPOJOclassesandthrough@ConfigurationannotatedJavaclasses.
You provide the configuration metadata for an application in XML format by creating an application
contextXMLfilethatcontainsinformationabouttheapplicationobjectsandtheirdependencies.Example
listing 1-3 showed how an application context XML file looks like. The following XML shows the
application context XML file of MyBank application that consists of FixedDepositController,
FixedDepositService and FixedDepositDao objects (refer figure 1-4 to see how these objects interact
witheachother):
Examplelisting1-13–applicationContext.xml-MyBank’sapplicationcontextXMLfile
Project–ch01-bankapp-xml
Sourcelocation-src/main/resources/META-INF/spring
<?xmlversion="1.0"encoding="UTF-8"standalone="no"?>
<beansxmlns="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-4.0.xsd">
<beanid="controller"
class="sample.spring.chapter01.bankapp.FixedDepositController">
<propertyname="fixedDepositService"ref="service"/>
</bean>
<beanid="service"class="sample.spring.chapter01.bankapp.FixedDepositService">
<propertyname="fixedDepositDao"ref="dao"/>
</bean>
<beanid="dao"class="sample.spring.chapter01.bankapp.FixedDepositDao"/>
</beans>
ThefollowingaretheimportantpointstonoteabouttheapplicationcontextXMLfileshownabove:
·The<beans>elementistherootelementoftheapplicationcontextXMLfile,andisdefinedin
spring-beans-4.0.xsdschema(alsoreferredtoasSpring’sbeansschema).Thespring-beans-4.0.xsd
schema is contained in spring-beans-4.0.0.RELEASE.jar JAR file that comes with the Spring
Frameworkdistribution.
·Each<bean>elementconfiguresanapplicationobjectthatismanagedbytheSpringcontainer.In
SpringFramework’sterminology,a<bean>elementrepresentsabeandefinition.Theobjectthat
theSpringcontainercreatesbasedonthebeandefinitionisreferredtoasabean.Theidattribute
specifiesauniquenameforthebean,andtheclassattributespecifiesthefully-qualifiedclassname
ofthebean.Youcanalsousethenameattributeof<bean>elementtospecifyaliasesforthebean.
InMyBankapplication,theapplicationobjectsareFixedDepositController, FixedDepositService
andFixedDepositDao;therefore,wehave3<bean>elements-oneforeachapplicationobject.As
application objects configured by <bean> elements are managed by the Spring container, the
responsibility for creating them and injecting their dependencies is with the Spring container.
Insteadofdirectlycreatinginstancesofapplicationobjectsdefinedby<bean>elements,youshould
obtainthemfromtheSpringcontainer.Laterinthissection,we’lllookathowtoobtainapplication
objectsmanagedbySpringcontainer.
· No<bean>element is defined corresponding to the FixedDepositDetails domain object of
MyBank application. This is because domain objects are not typically managed by the Spring
container;theyarecreatedbytheORMframework(likeHibernate)usedbytheapplication,oryou
createthemprogrammaticallyusingthenewoperator.
· The <property> element specifies a dependency (or a configuration property) of the bean
configuredbythe<bean>element.The<property>elementcorrespondstoaJavaBean-stylesetter
method in the bean class which is invoked by the Spring container to set a dependency (or a
configurationproperty)ofthebean.
Let’snowlookathowdependenciesareinjectedviasettermethods.
Injectingdependenciesviasettermethods
To understand how dependencies are injected via setter methods defined in the bean class, let’s once
againlookattheFixedDepositControllerclassofMyBankapplication:
Examplelisting1-14–FixedDepositControllerclass
Project–ch01-bankapp-xml
Sourcelocation-src/main/java/sample/spring/chapter01/bankapp
packagesample.spring.chapter01.bankapp;
importorg.apache.log4j.Logger;
publicclassFixedDepositController{
privatestaticLoggerlogger=Logger.getLogger(FixedDepositController.class);
privateFixedDepositServicefixedDepositService;
publicFixedDepositController(){
logger.info("initializing");
}
publicvoidsetFixedDepositService(FixedDepositServicefixedDepositService){
logger.info("SettingfixedDepositServiceproperty");
this.fixedDepositService=fixedDepositService;
}
.....
}
The above example listing shows that the FixedDepositController class declares an instance variable
namedfixedDepositServiceoftypeFixedDepositService.ThefixedDepositServicevariableissetbythe
setFixedDepositServicemethod-aJavaBean-stylesettermethodforfixedDepositServicevariable.This
isanexampleofsetter-basedDI,whereinasettermethodsatisfiesadependency.
The following figure describes the bean definition for the FixedDepositController class in the
applicationContext.xmlfile(referexamplelisting1-13):
Figure1-5Definingdependenciesusing<property>elements
The above bean definition shows that the FixedDepositController bean defines its dependence on
FixedDepositServicebeanvia<property>element.The<property>element’snameattributecorresponds
totheJavaBean-stylesettermethodinthebeanclassthatisinvokedbytheSpringcontaineratthetimeof
beancreation.The<property>element’srefattributeidentifiestheSpringbeanwhoseinstanceneedsto
becreatedandpassedtotheJavaBean-stylesettermethod.Thevalueofrefattributemustmatchtheid
attribute’s value (or one of the names specified by the name attribute) of a <bean> element in the
configurationmetadata.
Infigure1-5,thevalueof<property>element’snameattributeisfixedDepositService,whichmeansthat
the <property> element corresponds to the setFixedDepositService setter method of
FixedDepositController class (refer example listing 1-14). As the value of <property> element’s ref
attribute is service, the <property> element refers to the <bean> element whose id attribute’s value is
service.Now,the<bean>elementwhoseidattribute’svalueisserviceistheFixedDepositServicebean
(refer example listing 1-13). Spring container creates an instance of FixedDepositService class (a
dependency), and invokes the setFixedDepositService method (a JavaBean-style setter method for
fixedDepositService variable) of FixedDepositController (a dependent object), passing the
FixedDepositServiceinstance.
InthecontextofFixedDepositControllerapplicationobject,thefollowingfiguresummarizesthepurpose
ofnameandrefattributesof<property>element:
Figure 1-6 <property> element’s name attribute corresponds to a JavaBean-style setter method that
satisfiesabeandependency,andrefattributereferstoanotherbean.
The above figure shows that fixedDepositService value of name attribute corresponds to the
setFixedDepositServicemethodofFixedDepositControllerclass,andservicevalueofrefattributerefers
tothebeanwhoseidisservice.
NOTEItisfairlycommontorefertoabeandefinitionbyitsname(whichisidattribute’svalue)ortype
(whichisclassattribute’svalue)ortheinterfaceimplementedbythebeanclass.Forinstance,youcan
refer to ‘FixedDepositController bean’ as ‘controller bean’. And, if the FixedDepositController class
implements FixedDepositControllerIntf interface, you can refer to ‘FixedDepositController bean’ as
‘FixedDepositControllerIntfbean’.
ThefollowingdiagramsummarizeshowtheSpringcontainercreatesbeansandinjectstheirdependencies
basedontheconfigurationmetadatasuppliedbytheapplicationContext.xmlfile(referexamplelisting1-
13)ofMyBankapplication:
Figure1-7-ThesequenceinwhichSpringIoCcontainercreatesbeansandinjectstheirdependencies.
The above figure shows the sequence of steps followed by the Spring IoC container to create
FixedDepositController, FixedDepositService and FixedDepositDao beans and inject their
dependencies. Before attempting to create beans, the Spring container reads and validates the
configuration metadata supplied by the applicationContext.xml file. The order in which the beans are
created by the Spring container depends on the order in which they are defined in the
applicationContext.xml file. Spring container ensures that the dependencies of a bean are completely
configured before the setter method is invoked. For example, the FixedDepositController bean is
dependentonFixedDepositServicebean;therefore,SpringcontainerconfigurestheFixedDepositService
beanbeforeinvokingthesetFixedDepositServicemethodofFixedDepositControllerbean.
The bean definitions that we have seen so far, instruct Spring container to create bean instances by
invokingtheno-argumentconstructorofthebeanclass,andinjectdependenciesusingsetter-basedDI.In
chapter 2, we’ll look at bean definitions that instruct Spring container to create a bean instance via a
factorymethod defined in a class. Also, we’ll look at how to inject dependencies through constructor
arguments(referredtoasconstructor-basedDI),throughargumentstothefactorymethodthatcreatesthe
beaninstance,andbyusingsetter-basedDIonthebeaninstancereturnedbythefactorymethod.
Let’snowlookathowtocreateaninstanceofSpringcontainerandpassconfigurationmetadatatoit.
CreatinganinstanceofSpringcontainer
Spring’s ApplicationContext object represents an instance of Spring container. Spring provides a few
built-in implementations of ApplicationContext interface, like ClassPathXmlApplicationContext,
FileSystemXmlApplicationContext, XmlWebApplicationContext, XmlPortletApplicationContext, and so
on. The choice of the ApplicationContext implementation depends on how you have defined the
configuration metadata (using XML, annotations or Java code), and the type of your application
(standalone, web or portlet application). For instance, ClassPathXmlApplicationContext and
FileSystemXmlApplicationContext classes are suitable for standalone applications in which
configuration metadata is supplied in XML format, XmlWebApplicationContext is suitable for web
applications in which the configuration metadata is supplied in XML format,
AnnotationConfigWebApplicationContext is suitable for web applications in which configuration
metadataissuppliedthroughJavacode,andsoon.
As MyBank application represents a standalone application, we can use either
ClassPathXmlApplicationContext or FileSystemXmlApplicationContext class to create an instance of
Spring container. You should note that the ClassPathXmlApplicationContext class loads an application
contextXMLfilefromthespecifiedclasspathlocation,andtheFileSystemXmlApplicationContextclass
loadsanapplicationcontextXMLfilefromthespecifiedlocationonthefilesystem.
The following BankApp class of MyBank application shows that an instance of Spring container is
createdusingtheClassPathXmlApplicationContextclass:
Examplelisting1-15–BankAppclass
Project–ch01-bankapp-xml
Sourcelocation-src/main/java/sample/spring/chapter01/bankapp
packagesample.spring.chapter01.bankapp;
importorg.springframework.context.ApplicationContext;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
publicclassBankApp{
.....
publicstaticvoidmain(Stringargs[]){
ApplicationContextcontext=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
.....
}
}
TheaboveexamplelistingshowstheBankApp’smainmethod,whichisresponsibleforbootstrappingthe
Springcontainer.TheclasspathlocationoftheapplicationcontextXMLfileispassedtotheconstructor
of ClassPathXmlApplicationContext class. The creation of ClassPathXmlApplicationContext instance
resultsincreationofthosebeansintheapplicationcontextXMLfilethataresingleton-scopedandsetto
bepre-instantiated.Inchapter 2,we’ll discussbean scopes, andwhatitmeanstohave beanspre- or
lazily-instantiated by Spring container. For now, you can assume that the beans defined in the
applicationContext.xml file of MyBank application are singleton-scoped and set to be pre-instantiated.
This means that the beans defined in the applicationContext.xml file are created when an instance of
ClassPathXmlApplicationContextiscreated.
Now,thatwehaveseenhowtocreateaninstanceoftheSpringcontainer,let’slookathowtoretrieve
beaninstancesfromtheSpringcontainer.
AccessbeansfromtheSpringcontainer
Theapplicationobjectsdefinedvia<bean>elementsarecreatedandmanagedbytheSpringcontainer.
You can access instances of these application objects by calling one of the getBean methods of the
ApplicationContextinterface.
The following example listing shows the main method of BankApp class that retrieves an instance of
FixedDepositControllerbeanfromtheSpringcontainerandinvokesitsmethods:
Examplelisting1-16–BankAppclass
Project–ch01-bankapp-xml
Sourcelocation-src/main/java/sample/spring/chapter01/bankapp
packagesample.spring.chapter01.bankapp;
importorg.apache.log4j.Logger;
importorg.springframework.context.ApplicationContext;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
publicclassBankApp{
privatestaticLoggerlogger=Logger.getLogger(BankApp.class);
publicstaticvoidmain(Stringargs[]){
ApplicationContextcontext=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
FixedDepositControllerfixedDepositController=
(FixedDepositController)context.getBean("controller");
logger.info("Submissionstatusoffixeddeposit:"+fixedDepositController.submit());
logger.info("Returnedfixeddepositinfo:"+fixedDepositController.get());
}
}
At first, the ApplicationContext’s getBean method is invoked to retrieve an instance of
FixedDepositController bean from the Spring container, followed by invocation of submit and get
methodsofFixedDepositControllerbean.TheargumentpassedtothegetBeanmethodisthenameofthe
beanwhoseinstanceyouwanttoretrievefromtheSpringcontainer.Thenameofthebeanpassedtothe
getBeanmethodmustbethevalueoftheidornameattributeofthebeanthatyouwanttoretrieve.Ifno
bean with the specified name is registered with the Spring container, an exception is thrown by the
getBeanmethod.
In example listing 1-16, to configure the FixedDepositController instance, we didn’t programmatically
createaninstanceofFixedDepositService and set it on the FixedDepositController instance. Also, we
didn’t create an instance of FixedDepositDao and set it on the FixedDepositService instance. This is
becausethetaskofcreatingdependencies,andinjectingthemintothethedependentobjectsishandledby
theSpringcontainer.
If you go to ch01-bankapp-xml project and execute the main method of BankApp class, you’ll see the
followingoutputontheconsole:
INFOsample.spring.chapter01.bankapp.FixedDepositController-initializing
INFOsample.spring.chapter01.bankapp.FixedDepositService-initializing
INFOsample.spring.chapter01.bankapp.FixedDepositDao-initializing
INFOsample.spring.chapter01.bankapp.FixedDepositService-SettingfixedDepositDaoproperty
INFOsample.spring.chapter01.bankapp.FixedDepositController-SettingfixedDepositServiceproperty
INFOsample.spring.chapter01.bankapp.BankApp-Submissionstatusoffixeddeposit:true
INFOsample.spring.chapter01.bankapp.BankApp-Returnedfixeddepositinfo:id:1,depositamount:10000.0,tenure:365,email:
someemail@something.com
The above output shows that Spring container creates an instance of each of the beans defined in the
applicationContext.xmlfileofMyBankapplication.Also,Springcontainerusessetter-basedDItoinject
an instance of FixedDepositService into FixedDepositController instance, and an instance of
FixedDepositDaointotheFixedDepositServiceinstance.
Let’snowlookatsomeoftheframeworksthatarebuiltontopofSpringFramework.
1-6FrameworksbuiltontopofSpring
Though there are many frameworks from SpringSource that use Spring Framework as the foundation,
we’lllook atsomeofthewidelypopular ones.Foramorecomprehensivelistofframeworks,andfor
moredetailsaboutanindividualframework,it’srecommendedthatyouvisittheSpringSourcewebsite
(www.springsource.org).
Thefollowingtableprovidesahigh-leveloverviewoftheframeworksfromSpringSourcethatarebuilt
ontopofSpringFramework:
Framework Description
SpringSecurity
Authenticationandauthorizationframeworkforenterpriseapplications.Youneedto
configure a few beans in your application context XM L file to incorporate
authenticationandauthorizationfeaturesintoyourapplication.
SpringData
Provides a consistent programming model to interact with different types of
databases.Forinstance,youcanuseittointeractwithnon-relationaldatabases,like
MongoDBorNeo4j,andyoucanalsouseitforaccessingrelationaldatabasesusing
JPA.
SpringBatch Ifyourapplicationrequiresbulkprocessing,thisframeworkisforyou.
SpringIntegration ProvidesEnterpriseApplicationIntegration(EAI)capabilitiestoapplications.
SpringSocial If your application requires interaction with social media websites, like Facebook
andTwitter,thenyou’llfindthisframeworkhighlyuseful.
SpringBlazeDS
Integration
IfyouaredevelopinganAdobeFlexbasedapplication,youcanusethisframework
toconnectFlexfrontendwithSpring-basedbusinesstier.
AstheframeworksmentionedintheabovetablearebuiltontopofSpringFramework,beforeusingany
oftheseframeworksmakesurethattheyarecompatiblewiththeSpringFrameworkversionthatyouare
using.
1-7Summary
Inthischapter,welookedatthebenefitsofusingSpringFramework.WealsolookedatasimpleSpring
applicationthatshowedhowtospecifyconfigurationmetadatainXMLformat,createtheSpringcontainer
instanceandretrievebeansfromit.Inthenextchapter,we’lllookatsomeofthefoundationconceptsof
SpringFramework.
Chapter2–SpringFrameworkbasics
2-1Introduction
Inthepreviouschapter,wesawthattheSpringcontainerinvokestheno-argumentconstructorofabean
classtocreateabeaninstance,andsetter-basedDIisusedtosetbeandependencies.Inthischapter,we’ll
goastepfurtherandlookat:
§Spring’ssupportfor‘programmingtointerfaces’designprinciple
§differentapproachestoinstantiatingSpringbeans
§constructor-basedDIforpassingbeandependenciesasconstructorarguments
§constructor-andsetter-basedDIforpassingsimpleStringvaluestobeans,and
§beanscopes
Let’s begin this chapter with looking at how Spring improves testability of applications by supporting
‘programmingtointerfaces’designprinciple.
2-2Programmingtointerfacesdesignprinciple
Insection1-5ofchapter1,wesawthatadependentPOJOclasscontainedreferencetotheconcreteclass
of the dependency. For example, the FixedDepositController class contained reference to the
FixedDepositService class, and the FixedDepositService class contained reference to the
FixedDepositDaoclass.Ifadependentclasshasdirectreferencetotheconcreteclassofthedependency,
it results in tight coupling between the classes. This means that if you want to substitute a different
implementationofthedependency,it’drequirechangingthedependentclass.
Let’snowlookatascenarioinwhichadependentclasscontainsdirectreferencetotheconcreteclassof
thedependency.
Scenario:Dependentclasscontainsreferencetotheconcreteclassofdependency
Let’s say that the FixedDepositDao class makes use of plain JDBC to interact with the database. To
simplify database interaction, you create another DAO implementation, FixedDepositHibernateDao,
whichusesHibernateORMfordatabaseinteraction.Now,toswitchfromplainJDBCtoHibernateORM
implementation,you’llneedtochangeFixedDepositServiceclasstouseFixedDepositHibernateDaoclass
insteadofFixedDepositDao,asshowninthefollowingexamplelisting:
Examplelisting2-1–FixedDepositServiceclass
publicclassFixedDepositService{
privateFixedDepositHibernateDaofixedDepositDao;
publicvoidsetFixedDepositDao(FixedDepositHibernateDaofixedDepositDao){
this.fixedDepositDao=fixedDepositDao;
}
publicFixedDepositDetailsgetFixedDepositDetails(longid){
returnfixedDepositDao.getFixedDepositDetails(id);
}
publicbooleancreateFixedDeposit(FixedDepositDetailsfixedDepositDetails){
returnfixedDepositDao.createFixedDeposit(fixedDepositDetails);
}
}
The above example listing shows that reference to FixedDepositDao class was replaced by
FixedDepositHibernateDaosothatHibernateORMcanbeusedfordatabaseinteraction.Thisshowsthat
if a dependent class refers to the concrete implementation class of the dependency, then substituting a
differentimplementationrequireschangesinthedependentclass.
Let’snowlookatascenarioinwhichadependentclasscontainsreferencetotheinterfaceimplemented
bythedependency.
Scenario:Dependentclasscontainsreferencetotheinterfaceimplementedbythe
dependency
WeknowthataJavainterfacedefinesacontracttowhichtheimplementationclassesconform.So,ifa
class depends on the interface implemented by the dependency, no change is required in the class if a
different implementation of the dependency is substituted. The application design approach in which a
class depends on the interface implemented by the dependency is referred to as ‘programming to
interfaces’.Theinterfaceimplementedbythedependencyclassisreferredtoasadependencyinterface.
Asitisagooddesignpracticeto‘programtointerfaces’thanto‘programtoclasses’,thefollowingclass
diagramshowsthatitisagooddesignifABeanclassdependsonBBeaninterfaceandnotonBBeanImpl
classthatimplementsBBeaninterface:
Figure2-1-‘Programtointerfaces’isagooddesignpracticethanto‘programtoclasses’
The following class diagram shows how FixedDepositService class can make use of ‘programming to
interfaces’designapproachtoeasilyswitchthestrategyusedfordatabaseinteraction:
Figure2-2–TheFixedDepositServicedependsonFixedDepositDaointerface,whichisimplementedby
FixedDepositJdbcDaoandFixedDepositHibernateDaoclasses.
The above figure shows that the FixedDepositService class is not directly dependent on the
FixedDepositJdbcDaoorFixedDepositHibernateDaoclass.Instead,FixedDepositServicedependsonthe
FixedDepositDao interface (the dependency interface) implemented by FixedDepositJdbcDao and
FixedDepositHibernateDao classes. Now, depending on whether you want to use plain JDBC or
Hibernate ORM framework, you supply an instance of FixedDepositJdbcDao or
FixedDepositHibernateDaototheFixedDepositServiceinstance.
As FixedDepositService depends on FixedDepositDao interface, you can support other database
interactionstrategies inthe future. Let’s say that you decidetouse iBATIS(now renamed to MyBatis)
persistence framework for database interaction. You can use iBATIS without making any changes to
FixedDepositService class by simply creating a new FixedDepositIbatisDao class that implements
FixedDepositDao interface, and supplying an instance of FixedDepositIbatisDao to the
FixedDepositServiceinstance.
Sofarwehaveseenthat‘programmingtointerfaces’designapproachresultsinloosecouplingbetweena
dependentclassanditsdependencies.Let’snowlookathowthisdesignapproachimprovestestabilityof
thedependentclasses.
Improvedtestabilityofdependentclasses
In figure 2-2, we saw that the FixedDepositService class holds reference to the FixedDepositDao
interface.FixedDepositJdbcDaoandFixedDepositHibernateDaoareconcreteimplementationclassesof
FixedDepositDaointerface.Now,tosimplifyunittestingofFixedDepositServiceclass,youcansubstitute
amockimplementationofFixedDepositDaointerfacethatdoesn’trequireadatabase.
If the FixedDepositService class had direct reference to FixedDepositJdbcDao or
FixedDepositHibernateDao class, testing FixedDepositService class would have required setting up a
databasefortestingpurposes.Thisshowsthatbyusingamockimplementationofdependencyinterface,
youcansavetheefforttosetuptheinfrastructureforunittestingyourdependentclasses.
Let’snowseehowSpringsupports‘programmingtointerfaces’designapproachinapplications.
Spring’ssupportfor‘programmingtointerfaces’designapproach
Touse‘programmingtointerfaces’designapproach inyour Springapplication,youneedtoensurethe
followingthings:
§the<bean>elementsintheconfigurationmetadataspecifytheconcreteclassesofthedependency
§thedependentbean classes refer tothedependency interface insteadof the concrete class ofthe
dependency
Let’s now look at the modified MyBank application that uses ‘programming to interfaces’ design
approach.
IMPORT chapter 2/ch02-bankapp-interfaces (This project shows how ‘programming to interfaces’
designapproachisusedincreatingSpringapplications.Toruntheapplication,executethemainmethod
oftheBankAppclassofthisproject)
MyBankapplicationthatuses‘programmingtointerfaces’designapproach
The following class diagram depicts the modified MyBank application that uses ‘programming to
interfaces’designapproach:
Figure2-3-MyBankapplicationthatuses‘programtointerfaces’designapproach
Theabovefigureshowsthatadependentclassdependsontheinterfaceimplementedbythedependency,
and not on the concrete implementation class of the dependency. For instance, the
FixedDepositControllerImpl class depends on the FixedDepositService interface, and the
FixedDepositServiceImplclassdependsontheFixedDepositDaointerface.
ThefollowingexamplelistingshowstheFixedDepositServiceImpl class based onthedesignshownin
figure2-3:
Examplelisting2-2–FixedDepositServiceclass
Project–ch02-bankapp-interfaces
Sourcelocation-src/main/java/sample/spring/chapter02/bankapp
packagesample.spring.chapter02.bankapp;
publicclassFixedDepositServiceImplimplementsFixedDepositService{
privateFixedDepositDaofixedDepositDao;
.....
publicvoidsetFixedDepositDao(FixedDepositDaofixedDepositDao){
this.fixedDepositDao=fixedDepositDao;
}
publicFixedDepositDetailsgetFixedDepositDetails(longid){
returnfixedDepositDao.getFixedDepositDetails(id);
}
publicbooleancreateFixedDeposit(FixedDepositDetailsfdd){
returnfixedDepositDao.createFixedDeposit(fdd);
}
}
The above example listing shows that the FixedDepositServiceImpl class contains reference to the
FixedDepositDao interface. The FixedDepositDao implementation that you want to inject into the
FixedDepositServiceImplinstanceisspecifiedintheapplicationcontextXMLfile.Asshowninfigure2-
3, you can inject any one of the following concrete implementations of FixedDepositDao interface:
FixedDepositIbatisDao,FixedDepositJdbcDaoandFixedDepositHibernateDao.
ThefollowingexamplelistingshowstheapplicationContext.xmlfilethat caters tothe design shown in
figure2-3:
Examplelisting2-3–applicationContext.xml-MyBank’sapplicationcontextXMLfile
Project–ch02-bankapp-interfaces
Sourcelocation-src/main/resources/META-INF/spring
<?xmlversion="1.0"encoding="UTF-8"standalone="no"?>
<beans.....>
<beanid="controller"
class="sample.spring.chapter02.bankapp.controller.FixedDepositControllerImpl">
<propertyname="fixedDepositService"ref="service"/>
</bean>
<beanid="service"class="sample.spring.chapter02.bankapp.service.FixedDepositServiceImpl">
<propertyname="fixedDepositDao"ref="dao"/>
</bean>
<beanid="dao"class="sample.spring.chapter02.bankapp.dao.FixedDepositHibernateDao"/>
</beans>
The above applicationContext.xml file shows that an instance of FixedDepositHibernateDao (an
implementation of FixedDepositDao interface) is injected into FixedDepositServiceImpl. Now, if you
decidetouseiBATISinsteadofHibernateforpersistence,thenallyouneedtodoistochangetheclass
attributeofthedaobeandefinitionintheapplicationContext.xmlfiletorefertothefully-qualifiednameof
theFixedDepositIbatisDaoclass.
Let’snowlookatdifferentwaysinwhichSpringcontainercaninstantiatebeans.
2-3DifferentapproachestoinstantiatingSpringbeans
SofarwehaveseenbeandefinitionexamplesthatinstructSpringcontainertocreatebeaninstancesby
invokingtheno-argumentconstructorofthebeanclass.Considerthefollowingbeandefinition:
<beanid=”myBean”class=”mypackage.MyBean”/>
In the above bean definition, MyBean class represents a POJO class that defines a no-argument
constructor. MyBean class doesn’t implement any Spring-specific interface or extend from any Spring-
specific class. This effectively means that the Spring container can create and manage instance of any
classthatprovidesano-argumentconstructor.
NOTE It is important to note that the Spring container can create and manage instance of any class,
irrespectiveofwhethertheclassprovidesano-argumentconstructorornot.Insection2-4,we’lllookat
beandefinitionsinwhichtheconstructorofthebeanclassacceptsoneormorearguments.
Ifyouhaveanexistingprojectthatusesfactoryclassestocreateobjectinstances,youcanstilluseSpring
containertomanageobjectscreatedbythesefactories.Let’snowlookathowSpringcontainerinvokesa
staticoraninstancefactorymethodofaclasstomanagethereturnedobjectinstance.
Instantiatingbeansviastaticfactorymethods
Infigure2-3,wesawthattheFixedDepositDaointerfaceisimplementedbyFixedDepositHibernateDao,
FixedDepositIbatisDao and FixedDepositJdbcDao classes. The following example listing shows a
FixedDepositDaoFactoryclassthatdefinesastaticfactorymethodforcreatingandreturninganinstance
ofFixedDepositDaobasedontheargumentpassedtothestaticmethod:
Examplelisting2-4–FixedDepositDaoFactoryclass
publicclassFixedDepositDaoFactory{
privateFixedDepositDaoFactory(){}
publicstaticFixedDepositDaogetFixedDepositDao(StringdaoType){
FixedDepositDaofixedDepositDao=null;
if("jdbc".equalsIgnoreCase(daoType)){
fixedDepositDao=newFixedDepositJdbcDao();
}
if("hibernate".equalsIgnoreCase(daoType)){
fixedDepositDao=newFixedDepositHibernateDao();
}
.....
returnfixedDepositDao;
}
}
TheaboveexamplelistingshowsthattheFixedDepositDaoFactoryclassdefinesagetFixedDepositDao
staticmethodthatcreatesandreturnsaninstanceofFixedDepositJdbcDao,FixedDepositHibernateDao
orFixedDepositIbatisDaoclass,dependingonthevalueofthedaoTypeargument.
ThefollowingbeandefinitionfortheFixedDepositDaoFactoryclassinstructsSpringcontainertoinvoke
FixedDepositDaoFactory’sgetFixedDepositDao method to obtain an instance of FixedDepositJdbcDao
class:
Examplelisting2-5–BeandefinitionfortheFixedDepositDaoFactoryclass
<beanid="dao"class="sample.spring.FixedDepositDaoFactory"
factory-method="getFixedDepositDao">
<constructor-argindex=”0”value="jdbc"/>
</bean>
Intheabovebeandefinition,classattributespecifiesthefully-qualifiednameoftheclassthatdefinesthe
staticfactorymethod.Thefactory-methodattributespecifiesthenameofthestaticfactorymethodthatthe
SpringcontainerinvokestoobtainaninstanceofFixedDepositDaoobject.The<constructor-arg>element
is defined in Spring’s beansschema and is used for passing arguments to constructors, and static and
instancefactorymethods.Theindexattributereferstothelocationoftheargumentintheconstructor,orin
thestaticorinstancefactorymethod.Intheabovebeandefinition,thevalue0ofindexattributemeans
that the <constructor-arg> element is supplying value for the first argument, which is daoType, of the
getFixedDepositDaofactorymethod.Thevalueattributespecifiestheargumentvalue.Ifafactorymethod
acceptsmultiplearguments,youneedtodefinea<constructor-arg>elementforeachofthearguments.
ItisimportanttonotethatcallingApplicationContext’sgetBeanmethodtoobtaindaobean(referexample
listing 2-5) will result in invocation of the FixedDepositDaoFactory’s getFixedDepositDao factory
method. This means that calling getBean("dao") returns the FixedDepositDao instance created by the
getFixedDepositDaofactorymethod,andnotaninstanceofFixedDepositDaoFactoryclass.
Now,thatwehaveseentheconfigurationofthefactoryclassthatcreatesaninstanceofFixedDepositDao,
the following example listing shows how to inject an instance of FixedDepositDao into
FixedDepositServiceImplclass:
Examplelisting2-6–Injectingobjectinstancescreatedbystaticfactorymethod
<beanid="service"class="sample.spring.chapter02.bankapp.FixedDepositServiceImpl">
<propertyname=“fixedDepositDao"ref="dao"/>
</bean>
<beanid="dao"class="sample.spring.chapter02.basicapp.FixedDepositDaoFactory"
factory-method="getFixedDepositDao">
<constructor-argindex=”0”value="jdbc"/>
</bean>
In the above example listing, <property> element injects an instance of FixedDepositDao returned by
FixedDepositDaoFactory’sgetFixedDepositDao factory methodintoFixedDepositServiceImpl instance.
If you compare the bean definition for the FixedDepositServiceImpl class shown above with the one
shown in example listing 2-3, you’ll notice that they are exactly the same. This shows that the bean
dependencies are specifiedthe same way irrespective of how (using no-argumentconstructor or static
factorymethod)theSpringcontainercreatesbeaninstances.
Let’snowlookathowSpringcontainerinstantiatebeansbyinvokinganinstancefactorymethod.
Instantiatingbeansviainstancefactorymethods
ThefollowingexamplelistingshowstheFixedDepositDaoFactoryclassthatdefinesaninstancefactory
methodforcreatingandreturninganinstanceofFixedDepositDao:
Examplelisting2-7–FixedDepositDaoFactoryclass
publicclassFixedDepositDaoFactory{
publicFixedDepositDaoFactory(){
}
publicFixedDepositDaogetFixedDepositDao(StringdaoType){
FixedDepositDaoFixedDepositDao=null;
if("jdbc".equalsIgnoreCase(daoType)){
FixedDepositDao=newFixedDepositJdbcDao();
}
if(“hibernate”.equalsIgnoreCase(daoType)){
FixedDepositDao=newFixedDepositHiberateDao();
}
.....
returnfixedDepositDao;
}
}
Ifaclassdefinesaninstancefactorymethod,theclassmustdefineapublicconstructorsothattheSpring
containercancreateaninstanceofthatclass.Intheaboveexamplelisting,theFixedDepositDaoFactory
class defines a public no-argument constructor. The FixedDepositDaoFactory’s getFixedDepositDao
methodisaninstancefactorymethodthatcreatesandreturnsaninstanceofFixedDepositDao.
The following example listing shows how to instruct Spring container to invoke
FixedDepositDaoFactory’sgetFixedDepositDaomethodtoobtainaninstanceofFixedDepositDao:
Examplelisting2-8–ConfigurationtoinvokeFixedDepositDaoFactory’sgetFixedDepositDaomethod
<beanid="daoFactory"class="sample.spring.chapter02.basicapp.FixedDepositDaoFactory"/>
<beanid="dao"factory-bean="daoFactory"factory-method="getFixedDepositDao">
<constructor-argindex="0"value="jdbc"/>
</bean>
<beanid="service"class="sample.spring.chapter02.bankapp.FixedDepositServiceImpl">
<propertyname=“fixedDepositDao"ref="dao"/>
</bean>
TheaboveexamplelistingshowsthattheFixedDepositDaoFactoryclass(aclassthatcontainsinstance
factory method) is configured like a regular Spring bean, and a separate <bean> element is used to
configuretheinstancefactorymethoddetails.Toconfiguredetailsofaninstancefactorymethod,factory-
beanandfactory-methodattributesof<bean>elementareused.Thefactory-bean attribute referstothe
beanthatdefinestheinstancefactorymethod,andthefactory-methodattributespecifiesthenameofthe
instance factory method. In the above example listing, <property> element injects an instance of
FixedDepositDao returned by FixedDepositDaoFactory’s getFixedDepositDao factory method into
FixedDepositServiceImplinstance.
Aswithstaticfactorymethods,youcanpassargumentstoinstancefactorymethodsusing<constructor-
arg> element. It is important to note that invoking ApplicationContext’sgetBean method to obtain dao
bean in the above example listing will result in invocation of the FixedDepositDaoFactory’s
getFixedDepositDaofactorymethod.
So far we have looked at bean definition examples in which dependencies are injected into beans via
settermethods.Let’snowlookatdifferentDImechanismsthatyoucanuseforinjectingdependencies.
2-4Dependencyinjectiontechniques
In Spring, dependency injection is performed by passing arguments to a bean’s constructor and setter
methods.Ifyouareusingastaticorinstancefactorymethodtocreatebeaninstances,youcanpassbean
dependencies to the factory method or you can set them on the bean instance returned by the factory
method.
We’llnowlookatexamplesthatdemonstratedifferentDItechniques.
Setter-basedDI
Sofarinthisbook,we’veseenexamplesofsetter-basedDI.Insetter-basedDI,<property>elementsare
used to specify bean dependencies. The <property> element is also used to pass configuration
information(ifany)requiredbythebean.
Let’ssaythattheMyBankapplicationcontainsaPersonalBankingServiceservicethatallowscustomers
toretrievebankaccountstatement,checkbankaccountdetails,updatecontactnumber,changepassword,
and contact customer service. The PersonalBankingService class uses JmsMessageSender (for sending
JMS messages), EmailMessageSender (for sending emails) and WebServiceInvoker (for invoking
external web services) objects toaccomplish it’s intended functionality. The following example listing
showsthePersonalBankingServiceclass:
Examplelisting2-9–PersonalBankingServiceclass
publicclassPersonalBankingService{
privateJmsMessageSenderjmsMessageSender;
privateEmailMessageSenderemailMessageSender;
privateWebServiceInvokerwebServiceInvoker;
.....
publicvoidsetJmsMessageSender(JmsMessageSenderjmsMessageSender){
this.jmsMessageSender=jmsMessageSender;
}
publicvoidsetEmailMessageSender(EmailMessageSenderemailMessageSender){
this.emailMessageSender=emailMessageSender;
}
publicvoidsetWebServiceInvoker(WebServiceInvokerwebServiceInvoker){
this.webServiceInvoker=webServiceInvoker;
}
.....
}
The above example listing shows that a setter method is defined for JmsMessageSender,
EmailMessageSenderandWebServiceInvokerdependenciesofPersonalBankingServiceclass.
We can use setter-based DI to inject the dependencies of the PersonalBankingService class, as shown
here:
Examplelisting2-10–BeandefinitionsforPersonalBankingServiceclassanditsdependencies
<beanid="personalBankingService"class="PersonalBankingService">
<propertyname="emailMessageSender"ref="emailMessageSender"/>
<propertyname="jmsMessageSender"ref="jmsMessageSender"/>
<propertyname="webServiceInvoker"ref="webServiceInvoker"/>
</bean>
<beanid="jmsMessageSender"class="JmsMessageSender">
.....
</bean>
<beanid="webServiceInvoker"class="WebServiceInvoker"/>
.....
</bean>
<beanid="emailMessageSender"class="EmailMessageSender"/>
.....
</bean>
The personalBankingService bean definition shows that a <property> element is specified for each
dependencyofPersonalBankingServiceclass.
PersonalBankingServiceusesEmailMessageSenderbeantosendanemailnotificationtothecustomer’s
emailaddressincasecustomerchangeshiscontactnumber.EmailMessageSenderrequiresemailserver
address, and username and password for authenticating with the email server. The following example
listingshowsthatthe<property>elementcanalsobeusedforsettingbeanpropertiesoftypeString:
Examplelisting2-11EmailMessageSenderclassandthecorrespondingbeandefinition
publicclassEmailMessageSender{
privateStringhost;
privateStringusername;
privateStringpassword;
.....
publicvoidsetHost(Stringhost){
this.host=host;
}
publicvoidsetUsername(Stringusername){
this.username=username;
}
publicvoidsetPassword(Stringpassword){
this.password=password;
}
.....
}
<beanid="emailMessageSender"class="EmailMessageSender">
<propertyname="host"value="smtp.gmail.com"/>
<propertyname="username"value="myusername"/>
<propertyname="password"value="mypassword"/>
</bean>
The above example listing shows that <property> elements have been used to set host, username and
passwordpropertiesofEmailMessageSenderbean.ThevalueattributespecifiestheStringvaluetobeset
for the bean property identified by the name attribute. The host, username and password properties
representconfigurationinformationrequiredbyEmailMessageSenderbean.Inchapter3,we’llseehow
the <property> element is used to set primitive type (like int, long, and so on), collection type (like
java.util.List,java.util.Map,andsoon)andcustomtype(likeAddress)properties.
Setter-based DI is also used to inject dependencies into beans created by static and instance factory
methods.Let’slookathowtousesetter-basedDIinconjunctionwithstaticandinstancefactorymethods.
Injectingdependenciesintobeaninstancescreatedbyfactorymethods
Youcanusesetter-basedDItoinjectdependenciesofthebeaninstancereturnedbyastaticorinstance
factorymethod.
ConsiderthefollowingFixedDepositJdbcDaoclassthatdefinesadatabaseInfoproperty:
Examplelisting2-12–FixedDepositJdbcDaoclass
publicclassFixedDepositJdbcDao{
privateDatabaseInfodatabaseInfo;
.....
publicFixedDepositJdbcDao(){}
publicvoidsetDatabaseInfo(DatabaseInfodatabaseInfo){
this.databaseInfo=databaseInfo;
}
.....
}
In the above example listing, the databaseInfo attribute represents a dependency of the
FixedDepositJdbcDaoclassthatisfulfilledbysetDatabaseInfomethod.
The following FixedDepositDaoFactory class defines a factory method responsible for creating and
returninganinstanceofFixedDepositDaoJdbcclass:
Examplelisting2-13–FixedDepositDaoFactoryclass
publicclassFixedDepositDaoFactory{
publicFixedDepositDaoFactory(){
}
publicFixedDepositDaogetFixedDepositDao(StringdaoType){
FixedDepositDaoFixedDepositDao=null;
if("jdbc".equalsIgnoreCase(daoType)){
FixedDepositDao=newFixedDepositJdbcDao();
}
if(“hibernate”.equalsIgnoreCase(daoType)){
FixedDepositDao=newFixedDepositHiberateDao();
}
.....
returnfixedDepositDao;
}
}
Intheaboveexamplelisting,thegetFixedDepositDaomethodisaninstancefactorymethodforcreating
FixedDepositDao instances. The getFixedDepositDao method creates an instance of
FixedDepositJdbcDaoinstanceifthevalueofdaoTypeargumentisjdbc.Itisimportanttonotethatthe
getFixedDepositDaomethoddoesn’tsetthedatabaseInfopropertyoftheFixedDepositJdbcDaoinstance.
Aswesawinexamplelisting2-8,thefollowingbeandefinitionsinstructSpringcontainertocreatean
instance of FixedDepositJdbcDao by invoking the getFixedDepositDao instance factory method of
FixedDepositDaoFactoryclass:
Examplelisting2-14–ConfigurationtoinvokeFixedDepositDaoFactory’sgetFixedDepositDaomethod
<beanid="daoFactory"class="FixedDepositDaoFactory"/>
<beanid="dao"factory-bean="daoFactory"factory-method="getFixedDepositDao">
<constructor-argindex="0"value="jdbc"/>
</bean>
ThedaobeandefinitionresultsininvocationofFixedDepositDaoFactory’sgetFixedDepositDaomethod,
which creates and returns an instance of FixedDepositJdbcDao. But, the FixedDepositJdbcDao’s
databaseInfopropertyisnotset.TosetthedatabaseInfodependency,youcanperformsetter-basedDIon
theFixedDepositJdbcDaoinstancereturnedbythegetFixedDepositDaomethod,asshownhere:
Examplelisting2-15–ConfigurationtoinvokeFixedDepositDaoFactory’sgetFixedDepositDaomethod
andsetdatabaseInfopropertyofreturnedFixedDepositJdbcDaoinstance
<beanid="daoFactory"class="FixedDepositDaoFactory"/>
<beanid="dao"factory-bean="daoFactory"factory-method="getFixedDepositDao">
<constructor-argindex="0"value="jdbc"/>
<propertyname="databaseInfo"ref="databaseInfo"/>
</bean>
<beanid="databaseInfo"class="DatabaseInfo"/>
The above bean definition shows that <property> element is used to set databaseInfo property of
FixedDepositJdbcDao instance returned by getFixedDepositDao instance factory method. As with the
instancefactorymethod,youcanusethe<property>elementtoinjectdependenciesintothebeaninstance
returnedbythestaticfactorymethod.
Let’snowlookathowtoinjectbeandependenciesviaconstructorarguments.
Constructor-basedDI
Inconstructor-basedDI,dependenciesofabeanarepassedasargumentstothebeanclass’sconstructor.
For instance, the following example listing shows PersonalBankingService class whose constructor
acceptsJmsMessageSender,EmailMessageSenderandWebServiceInvokerobjects:
Examplelisting2-16–PersonalBankingServiceclass
publicclassPersonalBankingService{
privateJmsMessageSenderjmsMessageSender;
privateEmailMessageSenderemailMessageSender;
privateWebServiceInvokerwebServiceInvoker;
.....
publicPersonalBankingService(JmsMessageSenderjmsMessageSender,
EmailMessageSenderemailMessageSender,
WebServiceInvokerwebServiceInvoker){
this.jmsMessageSender=jmsMessageSender;
this.emailMessageSender=emailMessageSender;
this.webServiceInvoker=webServiceInvoker;
}
.....
}
The arguments to the PersonalBankingService’s constructor represent dependencies of the
PersonalBankingService class. The following example listing shows how dependencies of
PersonalBankingServiceinstancearesuppliedvia<constructor-arg>elements:
Examplelisting2-17–PersonalBankingServicebeandefinition
<beanid="personalBankingService"class="PersonalBankingService">
<constructor-argindex="0"ref="jmsMessageSender"/>
<constructor-argindex="1"ref="emailMessageSender"/>
<constructor-argindex="2"ref="webServiceInvoker"/>
</bean>
<beanid="jmsMessageSender"class="JmsMessageSender">
.....
</bean>
<beanid="webServiceInvoker"class="WebServiceInvoker"/>
.....
</bean>
<beanid="emailMessageSender"class="EmailMessageSender"/>
.....
</bean>
In the above example listing, <constructor-arg> elements specify details of the constructor arguments
passedtothePersonalBankingServiceinstance.Theindexattributespecifiestheindexoftheconstructor
argument.Iftheindexattributevalueis0,itmeansthatthe<constructor-arg>elementcorrespondstothe
firstconstructorargument,andiftheindexattributevalueis1,itmeansthatthe<constructor-arg>element
correspondstothesecondconstructorargument,andsoon.Wesawearlierthatrefattributeof<property>
elementisusedforpassingreferencetoabean.Similarly,refattributeof<constructor-arg>elementis
usedforpassingreferencetoabean.Likethe<property>element,the<constructor-arg>elementisalso
usedtopassconfigurationinformation(ifany)requiredbythebean.
You should note that the <constructor-arg> element is also used for passing arguments to static and
instancefactorymethodsthatcreatebeaninstances(refersection2-3).
NOTE Instead of using ref attribute of <property> and <constructor-arg> elements, you can use <ref>
elementinsidethe<property>and<constructor-arg>elementstosetreferencetobeans.Therefattribute
ispreferredasitmakestheXMLlessverbose.
The following example listing shows the EmailMessageSender class and the corresponding bean
definitionthatdemonstratesuseof<constructor-arg>elementstosupplyvaluesforStringtypeconstructor
arguments:
Examplelisting2-18EmailMessageSenderclassandthecorrespondingbeandefinition
publicclassEmailMessageSender{
privateStringhost;
privateStringusername;
privateStringpassword;
.....
publicEmailMessageSender(Stringhost,Stringusername,Stringpassword){
this.host=host;
this.username=username;
this.password=password;
}
.....
}
<beanid="emailMessageSender"class="EmailMessageSender">
<constructor-argindex="0"value="smtp.gmail.com"/>
<constructor-argindex="1"value="myusername"/>
<constructor-argindex="2"value="mypassword"/>
</bean>
Sofarwehaveseenthat<constructor-arg>elementisusedforinjectingbeandependenciesandpassing
valuesforStringtypeconstructorarguments.Inchapter3,we’llseehowthe<constructor-arg>elementis
usedtosetprimitivetype(likeint,long,andsoon),collectiontype(likejava.util.List,java.util.Map,and
soon)andcustomtype(likeAddress)properties.
Let’snowlookathowwecanuseconstructor-basedDIalongwithsetter-basedDI.
Usingamixofconstructor-andsetter-basedDImechanisms
Ifabeanclassrequiresbothconstructor-andsetter-basedDImechanisms,youcanuseacombinationof
<constructor-arg>and<property>elementstoinjectdependencies.
The following example listing shows a bean class whose dependencies are injected as arguments to
constructorandsettermethods:
Examplelisting2-19–PersonalBankingServiceclass
publicclassPersonalBankingService{
privateJmsMessageSenderjmsMessageSender;
privateEmailMessageSenderemailMessageSender;
privateWebServiceInvokerwebServiceInvoker;
.....
publicPersonalBankingService(JmsMessageSenderjmsMessageSender,
EmailMessageSenderemailMessageSender){
this.jmsMessageSender=jmsMessageSender;
this.emailMessageSender=emailMessageSender;
}
publicvoidsetWebServiceInvoker(WebServiceInvokerwebServiceInvoker){
this.webServiceInvoker=webServiceInvoker;
}
.....
}
In the PersonalBankingService class, jmsMessageSender and emailMessageSender dependencies are
injected as constructor arguments, and webServiceInvoker dependency is injected via the
setWebServiceInvoker setter method. The following bean definition shows that both <constructor-arg>
and<property>elementsareusedtoinjectdependenciesofPersonalBankingServiceclass:
Examplelisting2-20–Mixingconstructor-andsetter-basedDImechanisms
<beanid="dataSource"class="PersonalBankingService">
<constructor-argindex="0"ref="jmsMessageSender"/>
<constructor-argindex="1"ref="emailMessageSender"/>
<propertyname="webServiceInvoker"ref="webServiceInvoker"/>
</bean>
Now,that we have seenhowtoinstructSpringcontainertocreatebeansand performDI,let’slookat
differentscopesthatyoucanspecifyforbeans.
2-5Beanscopes
Youmaywanttospecifythescopeofabeantocontrolwhetherasharedinstanceofthebeaniscreated
(singletonscope),oranewbeaninstanceiscreatedeverytimethebeanisrequested(prototypescope)
fromtheSpringcontainer.Thescopeofabeanisdefinedbythescopeattributeofthe<bean>element.If
thescopeattributeisnotspecified,itmeansthatthebeanisasingleton-scopedbean.
NOTEInwebapplicationscenarios,Springallowsyoutospecifyadditionalscopes:request,session
and globalSession. These scopes determine the lifetime of the bean instance. For instance, a request-
scoped bean’s lifetimeis limited toasingle HTTP request.Asin this chapter we’ll not be discussing
SpringWebMVCorSpringPortletMVC,we’llrestrictthediscussiontosingletonandprototypescopes.
Therequest,sessionandglobalSessionscopesaredescribedinchapter10.
IMPORTchapter2/ch02-bankapp-scopes(Thisproject shows usageof singletonandprototype bean
scopes.Toruntheapplication,executethemainmethodoftheBankAppclassofthisproject.Theproject
alsocontains2JUnittests,PrototypeTestandSingletonTestthatyoucanexecute)
Singleton
Thesingletonscopeisthedefaultscope for all the beansdefinedintheapplicationcontext XML file.
Instance of a singleton-scoped bean is created when the Spring container is created, and is destroyed
whentheSpringcontainerisdestroyed.Springcontainercreatesasingleinstanceofasingleton-scoped
bean,whichissharedbyallthebeansthatdependonit.
ThefollowingexamplelistingshowstheapplicationContext.xmlfileofch02-bankapp-scopesprojectin
whichallthebeansaresingleton-scoped:
Examplelisting2-21–applicationContext.xml-Singleton-scopedbeans
Project–ch02-bankapp-scopes
Sourcelocation-src/main/resources/META-INF/spring
<beans.....>
<beanid="controller"
class="sample.spring.chapter02.bankapp.controller.FixedDepositControllerImpl">
<propertyname=“fixedDepositService"ref="service"/>
</bean>
<beanid="service"
class="sample.spring.chapter02.bankapp.service.FixedDepositServiceImpl">
<propertyname=“fixedDepositDao"ref="dao"/>
</bean>
<beanid="dao"class="sample.spring.chapter02.bankapp.dao.FixedDepositDaoImpl"/>
.....
</beans>
IntheaboveapplicationContext.xmlfile,controller,serviceanddaobeansaresingleton-scopedbecause
no scope attribute is specified for the <bean> elements. This means that only a single instance of
FixedDepositControllerImpl,FixedDepositServiceImplandFixedDepositDaoImpl classes is createdby
theSpringcontainer.Asthesebeansaresingleton-scoped,Springcontainerreturnsthesameinstanceof
thebeaneverytimeweretrieveoneofthesebeansusingApplicationContext’sgetBeanmethod.
NOTEIfthescopeattributeisnotspecifiedorthevalueofscopeattributeissingleton,itmeansthatthe
beanissingleton-scoped.
ThefollowingexamplelistingshowsthetestInstancesmethodofSingletonTest(aJUnittestclass)classof
ch02-bankapp-scopes project. The testInstances method tests whether multiple invocation of
ApplicationContext’sgetBeanmethodreturnsthesameordifferentinstanceofthecontrollerbean:
Examplelisting2-22–SingletonTestJUnittestclass
Project–ch02-bankapp-scopes
Sourcelocation-src/test/java/sample/spring/chapter02/bankapp
packagesample.spring.chapter02.bankapp;
importstaticorg.junit.Assert.assertSame;
importorg.junit.BeforeClass;
importorg.junit.Test;
importsample.spring.chapter02.bankapp.controller.FixedDepositController;
publicclassSingletonTest{
privatestaticApplicationContextcontext;
@BeforeClass
publicstaticvoidinit(){
context=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
}
@Test
publicvoidtestInstances(){
FixedDepositControllercontroller1=(FixedDepositController)context.getBean("controller");
FixedDepositControllercontroller2=(FixedDepositController)context.getBean("controller");
assertSame("DifferentFixedDepositControllerinstances",controller1,controller2);
}
.....
}
Intheaboveexamplelisting,JUnit’s@BeforeClassannotationspecifiesthattheinitmethodisinvoked
beforeanyofthetestmethods(thatis,methodsannotatedwithJUnit’s@Testannotation)intheclass.This
means that @BeforeClass annotated method is invoked only once, and @Test annotated methods are
executedonlyaftertheexecutionof@BeforeClassannotatedmethod.Notethattheinitmethodisastatic
method. The init method creates an instance of ApplicationContext object by passing the configuration
metadata (shown in example listing 2-21) to the ClassPathXmlApplicationContext’s constructor. The
testInstancesmethodobtains2instancesofcontrollerbeanandcheckswhetherboththeinstancesarethe
samebyusingJUnit’sassertSameassertion.Asthecontrollerbeanissingleton-scoped,controller1and
controller2 bean instances are the same. For this reason, SingletonTest’s testInstances test executes
withoutanyassertionerrors.
ThefollowingfigureshowsthattheSpringcontainerreturnsthesameinstanceofcontrollerbeanwhen
youcalltheApplicationContext’sgetBeanmethodmultipletimes:
Figure2-4Multiplerequestsforasingleton-scopedbeanresultsinthesamebeaninstancereturnedbythe
Springcontainer
The above figure shows that multiple calls to obtain controller bean returns the same instance of the
controllerbean.
NOTEInfigure2-4,thecontrollerbeaninstanceisrepresentedbya2-compartmentrectangle.Thetop
compartmentshowsthenameofthebean(thatis,thevalueoftheidattributeofthe<bean>element)and
thebottomcompartmentshowsthetypeofthebean(thatis,thevalueoftheclassattributeofthe<bean>
element). In the rest of this book, we’ll use this convention to show bean instances inside a Spring
container.
Asingleton-scopedbeaninstanceissharedamongstthebeansthatdependonit.Thefollowingexample
listing shows the testReference method of SingletonTest JUnit test class that checks if the
FixedDepositDao instance referenced by the FixedDepositController instance is the same as the one
obtaineddirectlybycallinggetBeanmethodofApplicationContext:
Examplelisting2-23–testReferencemethodofSingletonTestJUnittestclass
Project–ch02-bankapp-scopes
Sourcelocation-src/test/java/sample/spring/chapter02/bankapp
packagesample.spring.chapter02.bankapp;
importstaticorg.junit.Assert.assertSame;
importorg.junit.Test;
publicclassSingletonTest{
privatestaticApplicationContextcontext;
.....
@Test
publicvoidtestReference(){
FixedDepositControllercontroller=(FixedDepositController)context.getBean("controller");
FixedDepositDaofixedDepositDao1=
controller.getFixedDepositService().getFixedDepositDao();
FixedDepositDaofixedDepositDao2=(FixedDepositDao)context.getBean("dao");
assertSame("DifferentFixedDepositDaoinstances",fixedDepositDao1,fixedDepositDao2);
}
}
Intheaboveexamplelisting,thetestReferencemethodfirstretrievestheFixedDepositDaoinstance(refer
fixedDepositDao1variableintheaboveexamplelisting)referencedbytheFixedDepositControllerbean,
followed by directly retrieving another instance of FixedDepositDao bean (refer fixedDepositDao2
variable in the above example listing) using ApplicationContext’s getBean method. If you execute the
testReference test, you’ll see that the test completes successfully because the fixedDepositDao1 and
fixedDepositDao2instancesarethesame.
Figure2-5showsthattheFixedDepositDaoinstancereferencedbyFixedDepositControllerinstanceisthe
sameastheonereturnedbyinvokinggetBean("dao")methodonApplicationContext.
Figure2-5Singleton-scopedbeaninstanceissharedbetweenbeansthatdependonit
TheabovefigureshowsthattheFixedDepositDaoinstancereferencedbyFixedDepositController bean
instance and the one retrieved directly by calling ApplicationContext’s getBean are same. If there are
multiple beans dependent on a singleton-scoped bean, then all the dependent beans share the same
singleton-scopedbeaninstance.
Let’s now look at whether or not the same singleton-scoped bean instance is shared between multiple
Springcontainerinstances.
Singleton-scopedbeansandmultipleSpringcontainerinstances
Thescopeofasingleton-scopedbeaninstanceislimitedtotheSpringcontainerinstance.Thismeansthat
if you create 2 instances of the Spring container using the same configuration metadata, each Spring
containerhasitsowninstancesofthesingleton-scopedbeans.
ThefollowingexamplelistingshowsthetestSingletonScopemethodofSingletonTestclass,whichtests
whethertheFixedDepositControllerbeaninstanceretrievedfromtwodifferentSpringcontainerinstances
aresameordifferent:
Examplelisting2-24–testSingletonScopemethodofSingletonTestJUnittestclass
Project–ch02-bankapp-scopes
Sourcelocation-src/test/java/sample/spring/chapter02/bankapp
packagesample.spring.chapter02.bankapp;
importstaticorg.junit.Assert.assertNotSame;
publicclassSingletonTest{
privatestaticApplicationContextcontext;
.....
@BeforeClass
publicstaticvoidinit(){
context=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
}
@Test
publicvoidtestSingletonScope(){
ApplicationContextanotherContext=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
FixedDepositControllerfixedDepositController1=(FixedDepositController)anotherContext
.getBean("controller");
FixedDepositControllerfixedDepositController2=
(FixedDepositController)context.getBean("controller");
assertNotSame("SameFixedDepositControllerinstances",
fixedDepositController1,fixedDepositController2);
}
}
TheSingletonTest’sinitmethod(annotatedwithJUnit’s@BeforeClassannotation)createsaninstanceof
ApplicationContext(identifiedbycontextvariable)beforeany@Testannotatedmethodisexecuted.The
testSingletonScopemethodcreates one more instance ofSpring container (identifiedbyanotherContext
variable) using the same applicationContext.xml file. An instance of FixedDepositController bean is
retrieved from both the Spring containers and checked if they are not the same. If you execute the
testSingletonScope test, you’ll find that the test completes successfully because the
FixedDepositControllerbeaninstanceretrievedfromcontextinstanceisdifferentfromtheoneretrieved
fromanotherContextinstance.
ThefollowingfiguredepictsthebehaviorexhibitedbythetestSingletonScopemethod:
Figure2-6EachSpringcontainercreatesitsowninstanceofasingleton-scopedbean
TheabovefigureshowsthateachSpringcontainercreatesitsowninstanceofcontrollerbean.Thisisthe
reasonwhycontextandanotherContextinstancesreturndifferentinstancesofcontrollerbeanwhenyou
callgetBean("controller")method.
ThetestSingletonScopemethodshowedthateachSpringcontainercreatesitsowninstanceofasingleton-
scopedbean.ItisimportanttonotethatSpringcontainercreatesaninstanceofasingleton-scopedbean
for each bean definition. The following example listing shows multiple bean definitions for the
FixedDepositDaoImplclass:
Examplelisting2-25–applicationContext.xml-Multiplebeandefinitionsforthesameclass
Project–ch02-bankapp-scopes
Sourcelocation-src/main/resources/META-INF/spring
<beanid="dao"class="sample.spring.chapter02.bankapp.dao.FixedDepositDaoImpl"/>
<beanid="anotherDao"
class="sample.spring.chapter02.bankapp.dao.FixedDepositDaoImpl"/>
ThebeandefinitionsshownintheaboveexamplelistingareforFixedDepositDaoImplclass.Asscope
attributeisnotspecified,beandefinitionsshownintheaboveexamplelistingrepresentsingleton-scoped
beans.Evenifmultiplebeandefinitionsaredefinedforaclass,Springcontainercreatesabeaninstance
corresponding to each bean definition. This means that Spring container creates distinct instances of
FixedDepositDaoImpl class corresponding to dao and anotherDao bean definitions. The following
example listing shows SingletonScope’s testSingletonScopePerBeanDef method that tests whether the
FixedDepositDaoImpl instances corresponding to dao and anotherDao bean definitions are same or
different:
Examplelisting2-26–testSingletonScopePerBeanDefmethodofSingletonTestJUnittestclass
Project–ch02-bankapp-scopes
Sourcelocation-src/test/java/sample/spring/chapter02/bankapp
packagesample.spring.chapter02.bankapp;
importstaticorg.junit.Assert.assertNotSame;
publicclassSingletonTest{
privatestaticApplicationContextcontext;
.....
@Test
publicvoidtestSingletonScopePerBeanDef(){
FixedDepositDaofixedDepositDao1=(FixedDepositDao)context.getBean("dao");
FixedDepositDaofixedDepositDao2=(FixedDepositDao)context.getBean("anotherDao");
assertNotSame("SameFixedDepositDaoinstances",fixedDepositDao1,fixedDepositDao2);
}
}
Intheaboveexamplelisting,fixedDepositDao1andfixedDepositDao2variablesrepresentinstancesof
FixedDepositDaoImplclassthatSpringcontainercreatescorrespondingtothedaoandanotherDaobean
definitions, respectively. If you execute the testSingleScopePerBeanDef test, it’ll execute without any
assertion errors because the fixedDepositDao1 instance (corresponding to dao bean definition) and
fixedDepositDao2instance(correspondingtoanotherDaobeandefinition)aredistinct.
Thefollowingfiguresummarizesthatasingleton-scopedbeaniscreatedperbeandefinition:
Figure2-7Thereisonesingleton-scopedbeaninstanceperbeandefinition
Theabovefigureshowsthatthereexistsoneinstanceofsingleton-scopedbeanperbeandefinitioninthe
Springcontainer.
We mentioned earlier that a singleton-scoped bean is pre-instantiated by default, which means an
instanceofasingleton-scopedbeaniscreatedwhenyoucreateaninstanceoftheSpringcontainer.Let’s
nowlookathowyoucanlazilyinitializeasingleton-scopedbean.
Lazilyinitializingasingleton-scopedbean
You can instruct Spring container to create an instance of a singleton-scoped bean only when it is
requested for the first time. The following lazyExample bean definition shows how to instruct Spring
containertolazyinitializelazyBeanbean:
Examplelisting2-27–Lazilyinitializingasingleton-scopedbean
<beanid="lazyBean"class="example.LazyBean"lazy-init=”true”/>
The<bean>element’slazy-initattributespecifieswhetherthebeaninstanceiscreatedlazilyoreagerly.If
thevalueistrue(asincaseofthebeandefinitionshownabove),thebeaninstanceisinitializedbythe
Springcontainerwhenitreceivestherequestforthebeanforthefirsttime.
Thefollowingsequencediagramshowshowlazy-initattributeaffectsthecreationofasingleton-scoped
beaninstance:
Figure2-8Alazily-initializedsingleton-scopedbeaninstanceiscreatedwhenitisrequestedforthefirst
timebytheapplication
In the above diagram, BeanA represents a singleton-scoped bean instance that is not set to be lazily-
initialized,andLazyBeanrepresentsasingleton-scopedbeanthatissettobelazily-initialized.Whenthe
Spring container instance is created, BeanA is also instantiated because it is not set to be lazily-
initialized. On the other hand, LazyBean is instantiated when ApplicationContext’s getBean method is
invokedforthetimefirsttimetoretrieveaninstanceofLazyBeanfromtheSpringcontainer.
NOTEYoucanuse<beans>element’sdefault-lazy-initattributetospecifydefaultinitializationstrategy
forbeansdefinesintheapplicationcontextXMLfile.Ifthe<bean>element’slazy-initattributespecifies
adifferentvaluethanthe<beans>element’sdefault-lazy-init,thevaluespecifiedbythelazy-initattribute
appliestothebean.
Asasingleton-scopedbeancanbelazily-initializedorpre-instantiatedbytheSpringcontainer,youmay
bethinkingatthistimewhetheryoushoulddefineyoursingleton-scopedbeanstobelazily-initializedor
pre-instantiated.Inmostapplicationscenarios,itisbeneficialtopre-instantiatesingleton-scopedbeansto
discover configuration issues at the time of creation of the Spring container. The following example
listingshowsaaBeansingleton-scopedbeanthatissettobelazily-initialized,andthatdependsonbBean
bean:
Examplelisting2-28–Alazily-initializedsingleton-scopedbean
publicclassABean{
privateBBeanbBean;
publicvoidsetBBean(BBeanbBean){
this.bBean=bBean;
}
.....
}
<beanid="aBean"class="ABean"lazy-init="true">
<propertyname="bBean"value="bBean"/>
</bean>
<beanid="bBean"class="BBean"/>
Intheaboveexamplelisting,ABean’sbBeanpropertyreferstotheBBeanbean.Noticethatinsteadofref
attribute, value attribute of <property> element has been used to set ABean’s bBean property. If you
createanApplicationContextinstancebypassingittheXMLfilecontainingtheabovebeandefinition,no
errors will be reported. But, when you try to fetch the aBean bean by invoking ApplicationContext’s
getBeanmethod,you’llgetthefollowingerrormessage:
Causedby:java.lang.IllegalStateException:Cannotconvertvalueoftype[java.lang.String]torequiredtype[BBean]forproperty'bBean:no
matchingeditorsorconversionstrategyfound
The above error message is shown because the Spring container fails to convert the String value of
ABean’sbBeanpropertytoBBeantype.Thishighlightsasimpleconfigurationissueinwhichinsteadof
specifying<bean>element’srefattribute,valueattributewasspecified.IftheaBeanbeanwasdefinedas
pre-instantiated(insteadoflazily-initialized),theaboveconfigurationissuecouldhavebeencaughtatthe
timewecreatedaninstanceofApplicationContext,andnotwhenwetriedtoobtainaninstanceofaBean
beanfromtheApplicationContext.
Let’snowlookatprototype-scopedbeansinSpring.
Prototype
Aprototype-scopedbeanisdifferentfromasingleton-scopedbeaninthesensethattheSpringcontainer
always returns a new instance of a prototype-scoped bean. Another distinctive feature of prototype-
scopedbeansisthattheyarealwayslazily-initialized.
The following FixedDepositDetails bean in the applicationContext.xml file of ch02-bankapp-scopes
projectrepresentsaprototype-scopedbean:
Examplelisting2-29–applicationContext.xml-Aprototype-scopedbeanexample
Project–ch02-bankapp-scopes
Sourcelocation-src/main/resources/META-INF/spring
<beanid="FixedDepositDetails"
class="sample.spring.chapter02.bankapp.domain.FixedDepositDetails"
scope="prototype"/>
Theaboveexamplelistingshowsthatthe<bean>element’sscopeattributevalueissettoprototype.This
meansthattheFixedDepositDetailsbeanisaprototype-scopedbean.
The following testInstances method of PrototypeTest JUnit test class shows that the 2 instances of
FixedDepositDetailsbeanretrievedfromtheSpringcontaineraredifferent:
Examplelisting2-30–testInstancesmethodofPrototypeTestJUnittestclass
Project–ch02-bankapp-scopes
Sourcelocation-src/test/java/sample/spring/chapter02/bankapp
packagesample.spring.chapter02.bankapp;
importstaticorg.junit.Assert.assertNotSame;
publicclassPrototypeTest{
privatestaticApplicationContextcontext;
.....
@Test
publicvoidtestInstances(){
FixedDepositDetailsfixedDepositDetails1=
(FixedDepositDetails)context.getBean("fixedDepositDetails");
FixedDepositDetailsfixedDepositDetails2=
(FixedDepositDetails)context.getBean("fixedDepositDetails");
assertNotSame("SameFixedDepositDetailsinstances",
fixedDepositDetails1,fixedDepositDetails2);
}
}
If you execute the testInstances test, it’ll complete without any assertion errors because the 2
FixedDepositDetails instances (fixedDepositDetails1 and fixedDepositDetails2) obtained from the
ApplicationContextaredifferent.
Let’snowlookathowtochoosetherightscope(singletonorprototype)forabean.
Choosingtherightscopeforyourbeans
Ifabeandoesn’tmaintainanyconversationalstate(thatis,itisstatelessinnature),itshouldbedefinedas
a singleton-scoped bean. If a bean maintains conversational state, it should be defined as a prototype-
scopedbean.FixedDepositServiceImpl,FixedDepositDaoImplandFixedDepositControllerImplbeansof
MyBank application are stateless in nature; therefore, they are defined as singleton-scoped beans.
FixedDepositDetails bean (a domain object) of MyBank application maintains conversational state;
therefore,itisdefinedasaprototype-scopedbean.
NOTEIfyouareusinganORMframework(likeHibenateoriBATIS)inyourapplication,thedomain
objectsarecreatedeitherbytheORMframeworkoryoucreatethemprogrammaticallyinyour
applicationcodeusingthenewoperator.Itisbecauseofthisreasondomainobjectsarenotdefinedinthe
applicationcontextXMLfileiftheapplicationusesanORMframeworkforpersistence.
2-6Summary
In this chapter,we discussed some ofthe basics ofSpring Framework.We looked at ‘programming to
interfaces’designapproach,differentapproachestocreatebeaninstances,constructor-basedDIandbean
scopes.Inthenextchapter,we’lllookathowtosetdifferenttypes(likeint,long,Map,Set,andsoon)of
beanpropertiesandconstructorarguments.
Chapter3-Configuringbeans
3-1Introduction
Inpreviouschapters,wetoucheduponsomeofthebasicconceptsofSpringFramework.Wesawhow
SpringbeansandtheirdependenciesarespecifiedintheapplicationcontextXMLfile.Wealsolookedat
singleton-andprototype-scopedbeans,anddiscussedtheimplicationsofassigningthesescopestobeans.
Inthischapter,we’lllookat:
§beandefinitioninheritance
§howargumentstoabeanclass’sconstructorareresolved
§howtoconfigurebeanpropertiesandconstructorargumentsofprimitivetype(likeint,float,andso
on),collectiontype(likejava.util.List,java.util.Map,andsoon),customtype(likeAddress),and
soon
§ how you can make the application context XML file less verbose by using p-namespace and c-
namespacetospecifybeanpropertiesandconstructorarguments,respectively
§Spring’sFactoryBeaninterfacethatallowsyoutowriteyourownfactoryclassfor creatingbean
instances
3-2Beandefinitioninheritance
Wesawinchapter1and2thatabeandefinitionintheapplicationcontextXMLfilespecifiesthefully-
qualifiednameofthebeanclassanditsdependencies.Insomescenarios,tomakeabeandefinitionless
verbose,youmaywantabeandefinitiontoinheritconfigurationinformationfromanotherbeandefinition.
Let’slookatonesuchscenarioinMyBankapplication.
IMPORTchapter3/ch03-bankapp-inheritance(Thisproject showstheMyBankapplicationthatuses
beandefinitioninheritance.Toruntheapplication,executethemainmethodoftheBankAppclassofthis
project)
MyBank–Beandefinitioninheritanceexample
Inthepreviouschapter,wesawthattheMyBankapplicationaccessesdatabasethroughDAOs.Let’ssay
that the MyBank application defines a DatabaseOperations class that simplifies interacting with the
database.So,alltheDAOsintheMyBankapplicationdependonDatabaseOperationsclasstoperform
databaseoperations,asshowninthefollowingfigure:
Figure 3-1 - DAO classes in MyBank application make use of DatabaseOperations class to perform
databaseinteraction
TheabovefigureshowsthattheFixedDepositDaoandPersonalBankingDaoclassesaredependentonthe
DatabaseOperations class. The following application context XML file shows the bean definitions for
theseclasses:
Examplelisting3-1–DAObeansaredependentonDatabaseOperationsbean
<beanid="databaseOperations"
class="sample.spring.chapter01.bankapp.utils.DatabaseOperations"/>
<beanid="personalBankingDao"
class="sample.spring.chapter01.bankapp.dao.PersonalBankingDaoImpl">
<propertyname="databaseOperations"ref="databaseOperations"/>
</bean>
<beanid="FixedDepositDao"
class="sample.spring.chapter01.bankapp.dao.FixedDepositDaoImpl">
<propertyname="databaseOperations"ref="databaseOperations"/>
</bean>
Both the personalBankingDao and FixedDepositDao bean definitions use the <property> element to
performdependencyinjectionoftheDatabaseOperationsinstance.Asthenameofthepropertythatrefers
totheDatabaseOperationsinstanceisdatabaseOperationsinboththebeandefinitions,itimpliesthatboth
PersonalBankingDaoImpl and FixedDepositDaoImpl classes define a setDatabaseOperations method to
allowSpringcontainertoinjectDatabaseOperationsinstance.
If multiple beans in your application share a common set of configuration (properties, constructor
arguments,andsoon),youcancreateabeandefinitionthatactsasaparentforotherbeandefinitions.In
case of personalBankingDao and fixedDepositDao bean definitions, the common configuration is the
databaseOperations property. The following example listing shows that the personalBankingDao and
fixedDepositDaobeandefinitionsmakeuseofbeandefinitioninheritance:
Examplelisting3-2–applicationContext.xml-MyBank’sapplicationcontextXMLfile
Project–ch03-bankapp-inheritance
Sourcelocation-src/main/resources/META-INF/spring
<beanid="databaseOperations"
class="sample.spring.chapter03.bankapp.utils.DatabaseOperations"/>
<beanid="daoTemplate"abstract="true">
<propertyname="databaseOperations"ref="databaseOperations"/>
</bean>
<beanid="FixedDepositDao"parent="daoTemplate"
class="sample.spring.chapter03.bankapp.dao.FixedDepositDaoImpl"/>
<beanid="personalBankingDao"parent="daoTemplate"
class="sample.spring.chapter03.bankapp.dao.PersonalBankingDaoImpl"/>
Intheaboveexamplelisting,thedaoTemplatebeandefinitiondefinesthecommonconfigurationsharedby
both the fixedDepositDao and personalBankingDao bean definitions. As both the fixedDepositDao and
personalBankingDaobeandefinitionsrequirethedatabaseOperationsdependency(referexamplelisting
3-1),thedaoTemplatebeandefinitiondefinesthedatabaseOperationsdependencyusingthe<property>
element.The<bean>element’sparentattributespecifiesthenameofthebeandefinitionfromwhichthe
configuration is inherited. As the parent attribute value is daoTemplate for fixedDepositDao and
personalBankingDao bean definitions, they inherit databaseOperations property from the daoTemplate
beandefinition.Theexamplelistings3-1and3-2aresame,exceptthattheexamplelisting3-2makesuse
ofbeandefinitioninheritance.
Ifthe<bean>element’sabstractattributevalueissettotrue,itmeansthatthebeandefinitionisabstract.
It is important to note that the Spring container doesn’t attempt to create a bean corresponding to an
abstractbeandefinition.Itisimportanttonotethatyoucan’tdefineabeantobedependentonanabstract
bean,thatis,youcan’tuse<property>or<constructor-arg>elementtorefertoanabstractbean.
In example listing 3-2, daoTemplate bean definition is abstract. You may have noticed that the
daoTemplatebeandefinitiondoesn’tspecifytheclassattribute.Ifaparentbeandefinitiondoesn’tspecify
theclassattribute,childbeandefinitions(likethefixedDepositDaoandpersonalBankingDao)specifythe
class attribute. It is important to note that if you don’t specify the class attribute, you must define the
parent bean definition as abstract so that Spring container doesn’t attempt to create a bean instance
correspondingtoit.
ToverifythatthefixedDepositDaoandpersonalBankingDaobeandefinitionsinheritdaoTemplate bean
definition’sdatabaseOperationsproperty,executethemainmethodofBankAppclass ofch03-bankapp-
inheritance project. BankApp’s main method invokes methods on the fixedDepositDao and
personalBankingDaobeans;thosebeansinturninvokemethodsontheDatabaseOperationsinstance.Ifa
DatabaseOperations instance is not injected into the fixedDepositDao and personalBankingDao beans,
java.lang.NullPointerExceptionwillbethrown.
ThefollowingdiagramsummarizeshowbeandefinitioninheritanceworksincaseofFixedDepositDao
andpersonalBankingDaobeandefinitions:
Figure3-2–BeandefinitioninheritanceinMyBankapplication
The above figure shows that the fixedDepositDaoand personalBankingDao bean definitions inherit the
databaseOperations property (shown in italics in the boxes labeled fixedDepositDao and
personalBankingDao)fromthedaoTemplatebeandefinition.TheabovefigurealsodepictsthattheSpring
container doesn’t attempt to create a bean instance corresponding to the daoTemplate bean definition
becauseitismarkedasabstract.
Let’snowlookatwhatconfigurationinformationgetsinheritedfromtheparentbeandefinition.
Whatgetsinherited?
Achildbeandefinitioninheritsthefollowingconfigurationinformationfromtheparentbeandefinition:
·properties–specifiedvia<property>elements
·constructorarguments–specifiedvia<constructor-arg>elements
·methodoverrides(discussedinsection4-5ofchapter4)
·initializationanddestroymethods(discussedinchapter5),and
·factorymethods–specifiedviafactory-methodattributeof<bean>element(refersection2-3of
chapter2toknowhowstaticandinstancefactorymethodsareusedforcreatingbeans)
IMPORTchapter3/ch03-bankapp-inheritance-example(ThisprojectshowstheMyBankapplication
thatusesbeandefinitioninheritance.Inthisproject,you’llseemultiplescenariosinwhichbeandefinition
inheritanceisused.Toruntheapplication,executethemainmethodoftheBankAppclassofthisproject)
Let’snowlookatsomeofthebeandefinitioninheritanceexamples.
Beandefinitioninheritanceexample–parentbeandefinitionisnotabstract
Thefollowingexamplelistingshowsabeaninheritanceexampleinwhichtheparentbeandefinitionis
notabstract,andthechildbeandefinitionsdefineanadditionaldependency:
Examplelisting3-3–applicationContext.xml-Beandefinitioninheritance–parentbeandefinitionisnot
abstract
Project–ch03-bankapp-inheritance-examples
Sourcelocation-src/main/resources/META-INF/spring
<beanid="serviceTemplate"
class="sample.spring.chapter03.bankapp.base.ServiceTemplate">
<propertyname="jmsMessageSender"ref="jmsMessageSender"/>
<propertyname="emailMessageSender"ref="emailMessageSender"/>
<propertyname="webServiceInvoker"ref="webServiceInvoker"/>
</bean>
<beanid="fixedDepositService"class=".....FixedDepositServiceImpl"
parent="serviceTemplate">
<propertyname=“fixedDepositDao"ref="fixedDepositDao"/>
</bean>
<beanid="personalBankingService"class=".....PersonalBankingServiceImpl"
parent="serviceTemplate">
<propertyname="personalBankingDao"ref="personalBankingDao"/>
</bean>
<beanid="userRequestController"class=".....UserRequestControllerImpl">
<propertyname="serviceTemplate"ref="serviceTemplate"/>
</bean>
A littlebackgroundbefore we delve into the details ofthe above listedconfiguration: a service inthe
MyBank application may send JMS messages to a messaging-middleware or send emails to an email
server or it may invokean external web service. Intheabove example listing, the jmsMessageSender,
emailMessageSender and webServiceInvoker beans simplify these tasks by providing a layer of
abstraction.TheserviceTemplatebeanprovidesaccesstojmsMessageSender,emailMessageSenderand
webServiceInvoker beans. This is the reason why the serviceTemplate bean is dependent on the
jmsMessageSender,emailMessageSenderandwebServiceInvokerbeans.
Example listing 3-3 shows that the serviceTemplate bean definition is the parent bean definition of
fixedDepositServiceandpersonalBankingServicebeandefinitions.NoticethattheserviceTemplatebean
definitionisnotabstract;theclassattributespecifiesServiceTemplateastheclass.Inourpreviousbean
definition inheritance example (refer example listing 3-2), child bean definitions didn’t define any
properties.Intheaboveexamplelisting,noticethatthefixedDepositServiceandpersonalBankingService
childbeandefinitionsdefinefixedDepositDaoandpersonalBankingDaoproperties,respectively.
As parent bean definition’s properties are inherited by the child bean definitions,
FixedDepositServiceImpl and PersonalBankingServiceImpl classes must define setter methods for
jmsMessageSender, emailMessageSender and webServiceInvoker properties. You have the option to
either define setter methods in FixedDepositServiceImpl and PersonalBankingServiceImpl classes or
make FixedDepositServiceImpl and PersonalBankingServiceImpl classes as subclasses of
ServiceTemplate class. In ch03-bankapp-inheritance-examples, the FixedDepositServiceImpl and
PersonalBankingServiceImplclassesaresubclassesofServiceTemplateclass.
ThefollowingexamplelistingshowsthePersonalBankingServiceImplclass:
Examplelisting3-4–PersonalBankingServiceImplclass
Project–ch03-bankapp-inheritance-examples
Sourcelocation-src/main/java/sample/spring/chapter03/bankapp/service
packagesample.spring.chapter03.bankapp.service;
publicclassPersonalBankingServiceImplextendsServiceTemplateimplements
PersonalBankingService{
privatePersonalBankingDaopersonalBankingDao;
publicvoidsetPersonalBankingDao(PersonalBankingDaopersonalBankingDao){
this.personalBankingDao=personalBankingDao;
}
@Override
publicBankStatementgetMiniStatement(){
returnpersonalBankingDao.getMiniStatement();
}
}
In example listing 3-3, we saw that the personalBankingService bean definition specifies
personalBankingDao as a dependency. In the above example listing, the setPersonalBankingDao setter
method corresponds to the personalBankingDao dependency. Also, notice that the
PersonalBankingServiceImplclassisasubclassoftheServiceTemplateclass.
Thefollowingdiagramshowsthataparentbeandefinition(likeserviceTemplate)neednotbeabstract,
child bean definitions (like fixedDepositService and personalBankingService) may define additional
properties, and classes represented by parent (like ServiceTemplate class) and child bean definitions
(like FixedDepositServiceImpl and PersonalBankingServiceImpl) may themselves be related by
inheritance:
Figure3-3–Childbeandefinitionsaddadditionalproperties,parentbeandefinitionisnotabstract,and
parent-childrelationshipexistsbetweentheclassesrepresentedbytheparentandchildbeandefinitions
Figure3-3shows:
·SpringcontainercreatesaninstanceofserviceTemplatebeanbecauseit’snotdefinedasabstract
·FixedDepositServiceImplandPersonalBankingServiceImplclasses(correspondingtothechild
bean definitions) are subclasses of ServiceTemplate class – the class corresponding to the
serviceTemplateparentbeandefinition.
· And, fixedDepositService and personalBankingService bean definitions define additional
properties,fixedDepositDaoandpersonalBankingDao,respectively.Youshouldnotethatthechild
beandefinitionscanalsodefineadditionalconstructorargumentsandmethodoverrides(discussed
insection4-5).
AsserviceTemplatebeandefinitionisnotabstract,otherbeanscandefineserviceTemplatebeanastheir
dependency. For instance, in example listing 3-3, the serviceTemplate bean is a dependency of
userRequestController bean. You can infer from this discussion that if a parent bean definition is not
abstract,thefunctionalityofferedbytheparentbeancanbeutilizednotonlybychildbeansbutalsoby
otherbeansintheapplicationcontext.
Beandefinitioninheritanceexample–inheritingfactorymethodconfiguration
Childbeandefinitionscanusebeandefinitioninheritancetoinheritfactorymethodconfigurationfromthe
parentbeandefinition.Let’slookatanexamplethatshowsfactorymethodconfigurationsareinheritedby
childbeandefinitions.
ThefollowingControllerFactoryclassdefinesagetControllerinstancefactorymethod:
Examplelisting3-5–ControllerFactoryclass
Project–ch03-bankapp-inheritance-examples
Sourcelocation-src/main/java/sample/spring/chapter03/bankapp/controller
packagesample.spring.chapter03.bankapp.controller;
publicclassControllerFactory{
publicObjectgetController(StringcontrollerName){
Objectcontroller=null;
if("fixedDepositController".equalsIgnoreCase(controllerName)){
controller=newFixedDepositControllerImpl();
}
if("personalBankingController".equalsIgnoreCase(controllerName)){
controller=newPersonalBankingControllerImpl();
}
returncontroller;
}
}
The above example listing shows that the getController factory method creates an instance of
FixedDepositControllerImpl or PersonalBankingControllerImpl class, depending upon the value of the
controllerNameargumentpassedtoit.IfthevalueofcontrollerNameargumentisfixedDepositController,
thegetController methodcreates an instance ofFixedDepositControllerImpl class. And, if the value of
controllerNameargumentispersonalBankingController,thegetControllermethodcreatesaninstanceof
PersonalBankingControllerImplclass.
The following bean definitions inthe applicationContext.xml file of ch03-bankapp-inheritance-example
project show that the child bean definitions inherit the getController instance factory method
configurationfromtheparentbeandefinition:
Example listing 3-6 – applicationContext.xml - Bean definition inheritance – inheriting the factory
methodconfiguration
Project–ch03-bankapp-inheritance-examples
Sourcelocation-src/main/resources/META-INF/spring
<beanid="controllerFactory"
class="sample.spring.chapter03.bankapp.controller.ControllerFactory"/>
<beanid="controllerTemplate"factory-bean="controllerFactory"
factory-method="getController"abstract="true">
</bean>
<beanid="fixedDepositController"parent="controllerTemplate">
<constructor-argindex="0"value="fixedDepositController"/>
<propertyname=“fixedDepositService"ref="fixedDepositService"/>
</bean>
<beanid="personalBankingController"parent="controllerTemplate">
<constructor-argindex="0"value="personalBankingController"/>
<propertyname="personalBankingService"ref="personalBankingService"/>
</bean>
In the above example listing, the ControllerFactory class represents a factory class that defines a
getController instance factory method. The controllerTemplate bean definition specifies that the
ControllerFactory’sgetController factorymethodis used forcreatingbeaninstances.ThegetController
method (refer example listing 3-5) creates an instance of FixedDepositControllerImpl or
PersonalBankingControllerImplbean,dependingontheargumentpassedtothegetControllermethod.
As the controllerTemplate bean definition has been defined as abstract, it is up to the
fixedDepositController and personalBankingController child bean definitions to use the getController
factorymethodconfiguration.ThefixedDepositControllerbeandefinitionwouldliketopassanargument
to the ControllerFactory’s getController factory method so that it creates an instance of
FixedDepositControllerImplbean.And,personalBankingControllerbeandefinitionwouldliketopassan
argument to the ControllerFactory’s getController factory method so that it creates an instance of
PersonalBankingControllerImpl bean. We saw in section 2-3 of chapter 2 that the <constructor-arg>
element is used to pass an argument to an instance factory method. In example listing 3-6, the
<constructor-arg>elementhasbeenusedbyfixedDepositControllerandpersonalBankingControllerchild
beandefinitionstopass‘fixedDepositService’and‘personalBankingService’values,respectively,tothe
getControllerfactorymethod.
It is recommended that you now run the main method of BankApp class of ch03-bankapp-inheritance-
examplesprojecttoseeusageofthebeandefinitioninheritanceexamplesdiscussedinthissection.
Let’snowlookathowconstructorargumentsarematched.
3-3Constructorargumentmatching
Inthepreviouschapter,wesawthattheconstructorargumentsarespecifiedinthebeandefinitionsusing
the<constructor-arg>element.Inthissection,we’lllookathowSpringcontainermatchesaconstructor
argumentspecifiedbya<constructor-arg>elementtothecorrespondingconstructorargumentspecifiedin
thebeanclass’sconstructor.
Beforewegointothedetailsofconstructorargumentmatching,let’slookbackathowwepassarguments
toabeanclass’sconstructor.
IMPORT chapter 3/ch03-bankapp-constructor-args-by-type (This project shows the MyBank
application in which bean class’s constructor arguments are matched by type (explained later in this
section).Toruntheapplication,executethemainmethodoftheBankAppclassofthisproject)
Passingsimplevaluesandbeanreferencesusing<constructor-arg>element
If a constructor argument is of simple Java type (like int, String, and so on), the <constructor-arg>
element’svalueattributeisusedtospecifythevalueoftheconstructorargument.Ifaconstructorargument
is a reference to a bean, you specify the name of the bean using the <constructor-arg> element’s ref
attribute.
ThefollowingexamplelistingshowstheUserRequestControllerImplclassofch03-bankapp-constructor-
args-by-typeprojectwhoseconstructoracceptsanargumentoftypeServiceTemplate:
Examplelisting3-7–UserRequestControllerImplclass
Project–ch03-bankapp-constructor-args-by-type
Sourcelocation-src/main/java/sample/spring/chapter03/bankapp/controller
packagesample.spring.chapter03.bankapp.controller;
publicclassUserRequestControllerImplimplementsUserRequestController{
privateServiceTemplateserviceTemplate;
publicUserRequestControllerImpl(ServiceTemplateserviceTemplate){
this.serviceTemplate=serviceTemplate;
}
@Override
publicvoidsubmitRequest(Requestrequest){
//--dosomethingusingServiceTemplate
serviceTemplate.getJmsMessageSender();//--Forex.,sendJMSmessage
.....
}
}
The following example listing shows that a reference to ServiceTemplate instance (represented by
serviceTemplatebeandefinition)ispassedtoUserRequestControllerImpl’sconstructorusingrefattribute
of<constructor-arg>element:
Example listing 3-8 – applicationContext.xml - Passing reference to a Spring bean as constructor
argument
Project–ch03-bankapp-constructor-args-by-type
Sourcelocation-src/main/resources/META-INF/spring
<beanid="serviceTemplate"class="sample.spring.chapter03.bankapp.base.ServiceTemplate">
.....
</bean>
<beanid="userRequestController"
class="sample.spring.chapter03.bankapp.controller.UserRequestControllerImpl">
<constructor-argindex="0"ref="serviceTemplate"/>
</bean>
With this background information on how to pass simple values and bean references as constructor
arguments,let’snowlookathowSpringcontainermatchesconstructorargumenttypestolocatethebean’s
constructortobeinvoked.
Constructorargumentmatchingbasedontype
Ifthe<constructor-arg>element’sindexattributeisnotspecified,Springcontainerlocatestheconstructor
tobeinvokedbymatchingthetypesreferencedbythe<constructor-arg>elementswiththeargumenttypes
specifiedinthebeanclass’sconstructor(s).
Let’sfirstlookathowSpringcontainermatchesconstructorargumentswhentheconstructorargumentsare
Springbeansthatarenotrelatedbyinheritance.
ConstructorargumentsrepresentingdistinctSpringbeans
The following example listing shows the ServiceTemplate class that defines a constructor that accepts
referencestoJmsMessageSender,EmailMessageSenderandWebServiceInvokerbeans:
Examplelisting3-9–ServiceTemplateclass
Project–ch03-bankapp-constructor-args-by-type
Sourcelocation-src/main/java/sample/spring/chapter03/bankapp/base
packagesample.spring.chapter03.bankapp.base;
publicclassServiceTemplate{
.....
publicServiceTemplate(JmsMessageSenderjmsMessageSender,
EmailMessageSenderemailMessageSender,
WebServiceInvokerwebServiceInvoker){
.....
}
}
The following example listing shows the bean definitions for the ServiceTemplate class and the beans
referencedbyServiceTemplate:
Examplelisting3-10–applicationContext.xml-BeandefinitionfortheServiceTemplate class and its
dependencies
Project–ch03-bankapp-constructor-args-by-type
Sourcelocation-src/main/resources/META-INF/spring
<beanid="serviceTemplate"class="sample.spring.chapter03.bankapp.base.ServiceTemplate">
<constructor-argref="emailMessageSender"/>
<constructor-argref="jmsMessageSender"/>
<constructor-argref="webServiceInvoker"/>
</bean>
<beanid="jmsMessageSender"class="sample.spring.chapter03.bankapp.base.JmsMessageSender"/>
<bean id="emailMessageSender" class="sample.spring.chapter03.bankapp.base.EmailMessageSender"
/>
<beanid="webServiceInvoker"class="sample.spring.chapter03.bankapp.base.WebServiceInvoker"/>
Intheaboveexamplelisting,the<constructor-arg>elementsofserviceTemplatebeandon’tspecifythe
index attribute. The order in which the constructor arguments are specified by the <constructor-arg>
elements is: EmailMessageSender, JmsMessageSender, WebServiceInvoker. The order in which
constructor arguments are specified in the ServiceTemplate class’s constructor is: JmsMessageSender,
EmailMessageSender,WebServiceInvoker.Asyoucansee,theorderinwhichconstructorargumentsare
definedbythe<constructor-arg>elementsisdifferentfromtheorderspecifiedbytheServiceTemplate
class’sconstructor.
If you execute the main method of BankApp class of ch03-bankapp-constructor-args-by-type project,
you’ll find that the Spring container successfully creates an instance of ServiceTemplate bean. This is
becauseJmsMessageSender,EmailMessageSenderandWebServiceInvokerclassesaredistinctinnature
(thatis,theyarenotrelatedbyinheritance),whichmakesiteasierfortheSpringcontainertoinjecttheir
instancesintotheServiceTemplateclass’sconstructorinthecorrectorder.
Iftheconstructorargumenttypesarerelatedbyinheritance,Springcontainerneedsextrainstructionsto
help resolve constructor arguments. Let’s now look at how Spring container matches constructor
argumentswhenbeansreferencedbytheconstructorargumentsarerelatedbyinheritance.
ConstructorargumentsrepresentingrelatedSpringbeans
ConsiderthefollowingSampleBeanbeanclasswhoseconstructoracceptsargumenttypesthatarerelated
byinheritance:
Examplelisting3-11–SampleBeanclass
publicclassSampleBean{
publicSampleBean(ABeanaBean,BBeanbBean){.....}
.....
}
The above example listing shows that the SampleBean class’s constructor accepts ABean and BBean
typesasarguments.ABeanandBBeanrepresentSpringbeansthatarerelatedbyinheritance;BBeanisa
subclassofABean.
The following application context XML file shows the bean definitions for SampleBean, ABean and
BBeanclasses:
Examplelisting3-12–BeandefinitionsforSampleBean,ABeanandBBeanclasses
<beanid="aBean"class="example.ABean"/>
<beanid="bBean"class="example.BBean"/>
<beanid="sampleBean"class="example.SampleBean">
<constructor-argref="bBean"/>
<constructor-argref="aBean"/>
</bean>
AsaBeanandbBeanbeansarerelatedbyinheritance,Springcontainerappliesconstructorargumentsto
the SampleBean’s constructor in the order in which <constructor-arg> elements appear in the bean
definitionfortheSampleBeanclass.IntheabovesampleBeanbeandefinition,thefirst<constructor-arg>
elementreferstobBeanbeanandthesecond<constructor-arg>elementreferstoaBeanbean.Thismeans
that bBean is passed as the first constructor argument and aBean is passed as the second constructor
argumenttotheSampleBeanconstructor.AsinstanceofABean(thesuperclass)can’t bepassedwhere
BBean(thesubclass)instanceisexpected,thesecond<constructor-arg>elementinthesampleBeanbean
definitionresultsinexceptionbeingthrownbytheSpringcontainer.Tohandlesuchscenarios,youcan
use <constructor-arg> element’s index or type attribute to identify the constructor argument to which
<constructor-arg>elementapplies.Forinstance,thefollowingsampleBeanbeandefinitionmakesuseof
type attribute to indicate the type of the constructor argument to which the <constructor-arg> element
applies:
Examplelisting3-13 –<constructor-arg> element’stype attribute identifies the type of the constructor
argument
<beanid="sampleBean"class="example.SampleBean">
<constructor-argtype="sample.spring.chapter03.bankapp.controller.BBean"ref="bBean"/>
<constructor-argtype="sample.spring.chapter03.bankapp.controller.ABean"ref="aBean"/>
</bean>
The<constructor-arg>element’stypeattributespecifiesthefully-qualifiednameofthetypetowhichthe
<constructor-arg>elementapplies.Intheaboveexamplelisting,thefirst<constructor-arg>appliestothe
constructorargumentoftypeBBean,andthesecond<constructor-arg>elementappliestotheconstructor
argument of type ABean. Specifying the type attribute takes away the ambiguity that arises when
constructorargumentsarerelatedbyinheritance.
NOTEIftwoormoreconstructorargumentsareofthesametype,theonlyoptionistouseindex
attributetoidentifytheconstructorargumenttowhicheach<constructor-arg>elementapplies.
Sofarwehavelookedatconstructorargumenttypematchingscenariosinwhichconstructorarguments
represented distinct or related Spring beans. We’ll now look at how constructor argument types are
matchedforstandardJavatypes(likeint,long,boolean,String,Date,andsoon)andcustomtypes.
ConstructorargumentsrepresentingstandardJavatypesandcustomtypes
Ifthetypeofaconstructorargumentisaprimitivetype(likeint,long,boolean,andsoon)oraStringtype
or a custom type (like Address), the <constructor-arg> element’s value attribute is used to specify the
value. If there are 2 or more constructor arguments into which the string value specified by the value
attributecanbeconverted,it’llnotbepossiblefortheSpringcontainertoderivethetype(forexample,
whetherthevaluerepresentsanintorlongorString)oftheconstructorargument.Insuchscenarios,you
needtoexplicitlyspecifythetypeoftheconstructorargumentusingthetypeattribute.
ThefollowingexamplelistingshowstheTransferFundsServiceImplclassthatdefinesaconstructorwhich
acceptsargumentsoftypesString,boolean,longandint:
Examplelisting3-14–TransferFundsServiceImplclass
Project–ch03-bankapp-constructor-args-by-type
Sourcelocation-src/main/java/sample/spring/chapter03/bankapp/service
packagesample.spring.chapter03.bankapp.service;
publicclassTransferFundsServiceImplimplementsTransferFundsService{
publicTransferFundsServiceImpl(StringwebServiceUrl,booleanactive,longtimeout,
intnumberOfRetrialAttempts){.....}
.....
}
As the above example listing shows, TransferFundsServiceImpl constructor accepts the following
arguments:webServiceUrl,active,timeoutandnumberOfRetrialAttempts.Thefollowingbeandefinition
for the TransferFundsServiceImpl class shows how constructor argument values can be passed to the
TransferFundsServiceImpl’sconstructor:
Examplelisting3-15–BeandefinitionfortheTransferFundsServiceImplclass
<beanid="transferFundsService"
class="sample.spring.chapter03.bankapp.service.TransferFundsServiceImpl">
<constructor-argvalue="http://someUrl.com/xyz"/>
<constructor-argvalue="true"/>
<constructor-argvalue="5"/>
<constructor-argvalue="200"/>
</bean>
Let’sassumethatthe3rd<constructor-arg>element(valueattribute’svalueis‘5’)issupposedtosupply
valueforthenumberOfRetrialAttemptsconstructorargument,andthe4th<constructor-arg>element(value
attribute’s value is ‘200’) is supposed to supply value for the timeout constructor argument. Spring
containerapplies<constructor-arg>elementstotheTransferFundsServiceImpl’sconstructorintheorder
inwhich<constructor-arg>elementsappearinthetransferFundsServicebeandefinition.Thismeansthat
the 3rd <constructor-arg> element applies to timeout argument, and the 4th <constructor-arg> element
appliestonumberOfRetrialAttemptsargument.Tohandlesuchambiguities,youcanspecifythetypeofa
constructorargumentvia<constructor-arg>element’stypeattribute,asshowninthefollowingexample
listing:
Examplelisting3-16–applicationContext.xml-<constructor-arg>element’stypeattribute
Project–ch03-bankapp-constructor-args-by-type
Sourcelocation-src/main/resources/META-INF/spring
<beanid="transferFundsService"
class="sample.spring.chapter03.bankapp.service.TransferFundsServiceImpl">
<constructor-argtype="java.lang.String"value="http://someUrl.com/xyz"/>
<constructor-argtype="boolean"value="true"/>
<constructor-argtype="int"value="5"/>
<constructor-argtype="long"value="200"/>
</bean>
IntheabovebeandefinitionfortheTransferFundsServiceImplclass,typeattributeisusedtospecifythe
constructor argument type. Spring container can now use type matching to correctly apply constructor
arguments.
NOTEIftwoormoreconstructorargumentsareofthesametype,theonlyoptionistouseindexattribute
foridentifyingtheconstructorargumenttowhicheach<constructor-arg>elementapplies.
Inthissection,wesawhowtypematchingisperformedbySpringtoresolveconstructorarguments.Let’s
nowlookathowyoucaninstructSpringtoperformconstructorargumentmatchingbasedonconstructor
argument’sname.
IMPORT chapter 3/ch03-bankapp-constructor-args-by-name (This project shows the MyBank
application in which bean class’s constructor arguments are matched byname.To run the application,
executethemainmethodoftheBankAppclassofthisproject)
Constructorargumentmatchingbasedonname
The <constructor-arg> element’s name attribute is used for specifying the name of the constructor
argument to which the <constructor-arg> element applies. The following example listing shows once
againtheTransferFundsServiceImplclasswhoseconstructoracceptsmultiplearguments:
Examplelisting3-17–TransferFundsServiceImplclass
Project–ch03-bankapp-constructor-args-by-name
Sourcelocation-src/main/java/sample/spring/chapter03/bankapp/service
packagesample.spring.chapter03.bankapp.service;
publicclassTransferFundsServiceImplimplementsTransferFundsService{
.....
publicTransferFundsServiceImpl(StringwebServiceUrl,booleanactive,longtimeout,
intnumberOfRetrialAttempts){.....}
}
The above example listing shows that the names of the constructor arguments defined by
TransferFundsServiceImpl’s constructor are: webServiceUrl, active, timeout and
numberOfRetrialAttempts.
NOTETheTransferFundsServiceImplclass’sconstructoracceptsargumentsthataresimpleJavatypes
(like,int,long,boolean,String,andsoon),buttheconceptexplainedinthissectionalsoappliesto
scenariosinwhichconstructorargumentsarereferencestoSpringbeans.
ThefollowingbeandefinitionfortheTransferFundsServiceImplclassuses<constructor-arg>element’s
name attribute to specify the name of the constructor argument to which the <constructor-arg> element
applies:
Examplelisting3-18–applicationContext.xml-<constructor-arg>element’snameattribute
Project–ch03-bankapp-constructor-args-by-name
Sourcelocation-src/main/resources/META-INF/spring
<beanid="transferFundsService"
class="sample.spring.chapter03.bankapp.service.TransferFundsServiceImpl">
<constructor-argname="webServiceUrl"value="http://someUrl.com/xyz"/>
<constructor-argname="active"value="true"/>
<constructor-argname="numberOfRetrialAttempts"value="5"/>
<constructor-argname="timeout"value="200"/>
</bean>
TheaboveconfigurationwillworkonlyifTransferFundsServiceImplclassiscompiledwithdebugflag
enabled(referto-goptionofjavac).Whenthedebugflagisenabled,namesofconstructorargumentsare
preserved in the generated .class file. If you don’t compile your classes with debug flag enabled, the
constructorargumentnamesarelostduringcompilation,andSpringhasnowaytolocatetheconstructor
argument corresponding to the constructor argument name specified by the <constructor-arg> element’s
nameattribute.
Ifyoudon’twanttocompileyourclassesusingdebugflagenabled,youcanuse@ConstructorProperties
annotation(introducedinJavaSE6)toclearlyspelloutnamesoftheconstructorarguments,asshown
hereforTransferFundsServiceImplclass:
Examplelisting3-19–@ConstructorPropertiesannotation
Project–ch03-bankapp-constructor-args-by-name
Sourcelocation-src/main/java/sample/spring/chapter03/bankapp/service
packagesample.spring.chapter03.bankapp.service;
importjava.beans.ConstructorProperties;
publicclassTransferFundsServiceImplimplementsTransferFundsService{
@ConstructorProperties({"webServiceUrl","active","timeout","numberOfRetrialAttempts"})
publicTransferFundsServiceImpl(StringwebServiceUrl,booleanactive,longtimeout,
intnumberOfRetrialAttempts){.....}
}
In the above example listing, @ConstructorProperties annotation specifies the names of constructor
argumentsintheorderinwhichtheyappearinthebeanclass’sconstructor.Youmustensurethatyouuse
thesameconstructorargumentnamesinthe<constructor-arg>elements.
Let’snowlookathowthe@ConstructorPropertiesannotationaffectsbeandefinitioninheritance.
@ConstructorPropertiesannotationandbeandefinitioninheritance
If the constructor of the class corresponding to the parent bean definition is annotated with
@ConstructorPropertiesannotation,thebeanclasscorrespondingtothechildbeandefinitionmustalso
beannotatedwith@ConstructorPropertiesannotation.
The following example listing shows the serviceTemplate (parent bean definition) and
FixedDepositService(childbeandefinition)beandefinitions:
Examplelisting3-20–applicationContext.xml-Parentandchildbeandefinitions
Project–ch03-bankapp-constructor-args-by-name
Sourcelocation-src/main/resources/META-INF/spring
<beanid="serviceTemplate"
class="sample.spring.chapter03.bankapp.base.ServiceTemplate">
<constructor-argname="emailMessageSender"ref="emailMessageSender"/>
<constructor-argname="jmsMessageSender"ref="jmsMessageSender"/>
<constructor-argname="webServiceInvoker"ref="webServiceInvoker"/>
</bean>
<beanid="FixedDepositService"
class="sample.spring.chapter03.bankapp.service.FixedDepositServiceImpl"
parent="serviceTemplate">
<propertyname=“fixedDepositDao"ref="FixedDepositDao"/>
</bean>
TheaboveexamplelistingshowsthattheserviceTemplatebeandefinitionisnotabstract,whichmeans
that the Spring container will create an instance of serviceTemplate bean. The serviceTemplate bean
definition specifies 3 <constructor-arg> elements, corresponding to the 3 arguments defined by the
ServiceTemplateclass(referexamplelisting3-21).Aswehavespecifiedconstructorargumentsbyname
in the serviceTemplate bean definition, the ServiceTemplate class’s constructor is annotated with the
@ConstructorPropertiesannotationtoensurethatconstructorargumentnamesareavailabletoSpringat
runtime,asshownhere:
Examplelisting3-21–ServiceTemplateclass
Project–ch03-bankapp-constructor-args-by-name
Sourcelocation-src/main/java/sample/spring/chapter03/bankapp/base
packagesample.spring.chapter03.bankapp.base;
importjava.beans.ConstructorProperties;
publicclassServiceTemplate{
.....
@ConstructorProperties({"jmsMessageSender","emailMessageSender","webServiceInvoker"})
publicServiceTemplate(JmsMessageSenderjmsMessageSender,
EmailMessageSenderemailMessageSender,
WebServiceInvokerwebServiceInvoker){.....}
}
As FixedDepositService is a child bean definition of serviceTemplate, the <constructor-arg>
configurationinserviceTemplatebeandefinitionisinheritedbytheFixedDepositServicebeandefinition.
ThismeansthattheFixedDepositServiceImplclassmustdefineaconstructorthatacceptsthesamesetof
arguments as defined by the ServiceTemplate class, and it must also be annotated with
@ConstructorProperties annotation. If you don’t annotate FixedDepositServiceImpl’s constructor with
@ConstructorPropertiesannotation,Springcontainerwillnotbeabletomatchtheinherited<constructor-
arg>elementswiththeconstructorargumentsspecifiedintheFixedDepositServiceImpl’sconstructor.
Youcan’tuse@ConstructorPropertiesannotationforpassingargumentsbynametoastaticorinstance
factorymethod,asexplainednext.
@ConstructorPropertiesannotationandfactorymethods
We saw in section 2-3 of chapter 2 that the <constructor-arg> elements are also used for passing
argumentstostaticandinstancefactorymethods.Youmightthinkthatyoucanpassargumentsbynameto
static and instance factory methods by specifying the <constructor-arg> element’s name attribute and
annotating the factory method with @ConstructorProperties annotation. You should note that
@ConstructorProperties annotation is meant only for constructors; you can’t annotate methods with
@ConstructorProperties annotation. So, if you want to pass arguments by name to a static or instance
factorymethod,theonlyoptionyouhaveistocompileclasseswithdebugflagenabled.
NOTEIfyoucompileclasseswithdebugflagenabled,itresultsin.classfilesthatarelargerinsize,but
hasnoimpactontheruntimeperformanceoftheapplication.Itonlyresultsinincreasedloadingtimefor
theclasses.
Let’snowlookathowtoenableordisabledebugflaginEclipseIDE.
Enabling(ordisabling)thedebugflaginEclipseIDE
InEclipseIDE,followthesestepstoenablethedebugflagforprojects:
1.GotoWindowsàPreferencesandselecttheoptionJavaàCompiler
2.You’llnowseeasectiontitled‘ClassfileGeneration’.Inthissection,ifyoucheckthecheckbox
labeled‘Addvariableattributestogeneratedclassfiles(usedbythedebugger)’,thedebugflagis
enabled.Uncheckingthischeckboxwilldisablethedebugflag.
Sofarwehavemostlyseenbeandefinitionexamplesinwhichbeanpropertiesandconstructorarguments
werereferencestootherbeans.We’llnowlookatbeandefinitionexamplesinwhichbeanpropertiesand
constructorargumentsareofprimitivetype,collectiontype,java.util.Date,java.util.Properties,andsoon.
3-4 Configuring different types of bean properties and constructor
arguments
Inrealworldapplicationdevelopmentscenarios,propertiesandconstructorargumentsofaSpringbean
could range from a String type to reference to another bean to any other standard (like java.util.Date,
java.util.Map)orcustom(likeAddress)type.Sofarwehaveseenexamplesofhowtosupplyvaluefor
String type bean properties (using value attribute of <property> element) and String type constructor
arguments (using value attribute of <constructor-arg> element). We also looked at how to inject
dependenciesviabeanproperties(usingrefattributeof<property>element)andconstructorarguments
(usingrefattributeof<constructor-arg>elements).
Inthissection,we’lllookatbuilt-inPropertyEditorimplementationsinSpringthatsimplifypassingbean
properties and constructor arguments of types java.util.Date, java.util.Currency, primitive type, and so
on.We’llalsolookathowtospecifyvaluesforcollectiontypes(likejava.util.Listandjava.util.Map)in
the application context XML file, and how to register a custom PropertyEditor implementation with
Spring.
Let’s now look at bean definition examples that demonstrate use of built-in PropertyEditor
implementations.
IMPORT chapter 3/ch03-simple-types-examples (This project shows a Spring application in which
bean properties and constructor arguments are of primitive type, java.util.Date, java.util.List,
java.util.Map, and so on. This project also shows how to register a custom PropertyEditor
implementationwithSpringcontainer.Toruntheapplication,executethemainmethodoftheSampleApp
classofthisproject)
Built-inpropertyeditorsinSpring
JavaBeansPropertyEditorsprovidethenecessarylogicforconvertingaJavatypetoastringvalue,and
viceversa.Springprovidesacoupleofbuilt-inPropertyEditorsthatareusedforconvertingstringvalue
of a bean property or a constructor argument (specified via value attribute of <property> and
<constructor-arg>elements)totheactualJavatypeofthepropertyorconstructorargument.
Beforewelookat examples involvingbuilt-inPropertyEditors,let’s firstunderstand the importance of
PropertyEditorsinsettingvaluesofbeanpropertiesorconstructorarguments.
ConsiderthefollowingBankDetailsclassthatwewanttoconfigureasasingleton-scopedbeanwithpre-
definedvaluesforitsattributes:
Examplelisting3-22–BankDetailsclass
publicclassBankDetails{
privateStringbankName;
publicvoidsetBankName(StringbankName){
this.bankName=bankName;
}
}
Intheaboveexamplelisting,bankNameisanattributeoftheBankDetailsclass,andisoftypeString.The
followingbeandefinitionfortheBankDetailsclassshowshowtosetthevalueofbankNameattributeto
‘MyPersonalBank’:
Examplelisting3-23–BeandefinitionfortheBankDetailsclass
<beanid="bankDetails"class="BankDetails">
<propertyname="bankName"value="MyPersonalBank"/>
</bean>
In the above bean definition, the <property> element’s value attribute specifies a string value for the
bankNameproperty.Asyoucansee,ifabeanpropertyisoftypeString,youcansimplysetthatproperty
valueusing<property> element’s value attribute. Similarly, if a constructor argument is of type String,
youcansettheconstructorargumentvalueusing<constructor-arg>element’svalueattribute.
Let’ssaythatthefollowingattributes(alongwiththeirsettermethods)areaddedtotheBankDetailsclass:
a bankPrimaryBusiness attribute of type byte[], a headOfficeAddress attribute of type char[], a
privateBank attribute of type char, a primaryCurrency attribute of type java.util.Currency, a
dateOfInception attribute of type java.util.Date, and a branchAddresses attribute of type
java.util.Properties.ThefollowingexamplelistingshowsthemodifiedBankDetailsclass:
Examplelisting3-24–BankDetailsclasscontainingdifferenttypesofproperties
Project–ch03-simple-types-examples
Sourcelocation-src/main/java/sample/spring/chapter03/beans
packagesample.spring.chapter03.beans;
.....
publicclassBankDetails{
privateStringbankName;
privatebyte[]bankPrimaryBusiness;
privatechar[]headOfficeAddress;
privatecharprivateBank;
privateCurrencyprimaryCurrency;
privateDatedateOfInception;
privatePropertiesbranchAddresses;
.....
publicvoidsetBankName(StringbankName){
this.bankName=bankName;
}
//--moresettermethods
}
YoucanconfiguretheBankDetailsclassasaSpringbeanbyspecifyingstringvaluesfortheproperties,
and letting the Spring container convert these string values into the corresponding Java types of the
propertiesbyusingregisteredJavaBeansPropertyEditorimplementations.
ThefollowingbeandefinitionfortheBankDetailsclassshowsthatsimplestringvaluesarespecifiedfor
differentpropertytypes:
Examplelisting3-25–applicationContext.xml-BeandefinitionfortheBankDetailsclass
Project–ch03-simple-types-examples
Sourcelocation-src/main/resources/META-INF/spring
<beanid="bankDetails"class="sample.spring.chapter03.beans.BankDetails">
<propertyname="bankName"value="MyPersonalBank"/>
<propertyname="bankPrimaryBusiness"value="Retailbanking"/>
<propertyname="headOfficeAddress"value="Addressofheadoffice"/>
<propertyname="privateBank"value="Y"/>
<propertyname="primaryCurrency"value="INR"/>
<propertyname="dateOfInception"value="30-01-2012"></property>
<propertyname="branchAddresses">
<value>
x=BranchX'saddress
y=BranchY'saddress
</value>
</property>
</bean>
Theaboveexamplelistingshows thatstring valuesarespecifiedforpropertiesoftypesjava.util.Date,
java.util.Currency, char[], byte[], char and java.util.Properties. Spring container uses registered
PropertyEditors for converting the string value of the property or constructor argument to the
correspondingJavatypeofthepropertyorconstructorargument.Forinstance,Springcontainerconverts
the value ‘30-01-2012’ of dateOfInception property to java.util.Date type using CustomDateEditor (a
built-inPropertyEditorimplementationforjava.util.Datetype).
If you look at how branchAddresses property (of type java.util.Properties) is configured in example
listing 3-25, you’ll notice that instead of <property> element’s value attribute, <value> sub-element of
<property> element has been used to specify the value for the property. In case of single-valued
properties,theuseof<property>element’svalueattributeispreferredover<value>sub-element.But,if
youneedtospecifymultiplevaluesforapropertyorthevaluesneedtobespecifiedonseparatelines(as
inthecaseofbranchAddressesproperty),the<value>sub-elementispreferredovervalueattribute.In
the next section, you’ll see that values for properties (or constructor arguments) of type
java.util.Properties can also be specified using <props> sub-element of <property> ( or <constructor-
arg>)element.
Springcomeswithcoupleofbuilt-inPropertyEditorimplementationsthatperformthetaskofconverting
valuesspecifiedintheapplicationcontextXMLfiletotheJavatypeofthebeanpropertyorconstructor
argument.Thefollowingtabledescribessomeofthebuilt-inPropertyEditorimplementationsinSpring:
Built-in PropertyEditor
implementation Description
CustomBooleanEditor convertsstringvaluetoBooleanorbooleantype
CustomNumberEditor convertsstringvaluetoanumber(likeint,long,andsoon)
ChracterEditor convertsstringvaluetochartype
ByteArrayPropertyEditor convertsstringvaluetobyte[]
CustomDateEditor convertsstringvaluetojava.util.Datetype
PropertiesEditor convertsstringvaluetojava.util.Propertiestype
Theabovetableshowsonlyasubsetofbuilt-inPropertyEditorimplementationsinSpring.Foracomplete
list,refertotheorg.springframework.beans.propertyeditorspackageofSpring.Itisimportanttonotethat
not all built-in PropertyEditor implementations in Spring are registered with the Spring container by
default. For instance, you need to explicitly register CustomDateEditor to allow Spring container to
performconversionfromastringvaluetoajava.util.Datetype.Laterinthissection,we’lllookathow
youcanregisterpropertyeditorswithSpringcontainer.
Let’s now look at how to specify values for bean properties (or constructor arguments) of types
java.util.List,java.util.Setandjava.util.Map.
Specifyingvaluesfordifferentcollectiontypes
The <list>, <map> and <set> sub-elements (defined in Spring’s beans schema) of <property> and
<constructor-arg> elements are used to set properties and constructor arguments of type java.util.List,
java.util.Mapandjava.util.Set,respectively.
NOTESpring’sutilschemaalsoprovides<list>,<set>and<map>elementsthatsimplifysetting
propertiesandconstructorargumentsofdifferentcollectiontypes.Laterinthischapter,we’lllookat
Spring’sutilschemaelementsindetail.
ThefollowingDataTypesExampleclassshowsthatitsconstructoracceptsargumentsofdifferenttypes:
Examplelisting3-26–DataTypesExampleclass
Project–ch03-simple-types-examples
Sourcelocation-src/main/java/sample/spring/chapter03/beans
packagesample.spring.chapter03.beans;
importjava.beans.ConstructorProperties;
.....
publicclassDataTypesExample{
privatestaticLoggerlogger=Logger.getLogger(DataTypesExample.class);
@SuppressWarnings("rawtypes")
@ConstructorProperties({"byteArrayType","charType","charArray",
"classType","currencyType","booleanType","dateType","longType",
"doubleType","propertiesType","listType","mapType","setType",
"anotherPropertiesType"})
publicDataTypesExample(byte[]byteArrayType,charcharType,
char[]charArray,ClassclassType,CurrencycurrencyType,
booleanbooleanType,DatedateType,longlongType,
doubledoubleType,PropertiespropertiesType,List<Integer>listType,
MapmapType,SetsetType,PropertiesanotherPropertiesType){
.....
logger.info("classType"+classType.getName());
logger.info("listType"+listType);
logger.info("mapType"+mapType);
logger.info("setType"+setType);
logger.info("anotherPropertiesType"+anotherPropertiesType);
}
}
The above example listing shows that the DataTypesExample class’s constructor accepts arguments of
typesjava.util.List,java.util.Map,java.util.Setandjava.util.Properties,andsoon,andlogsthevalueof
eachconstructorargument.
ThefollowingexamplelistingshowsthebeandefinitionfortheDataTypesExampleclass:
Examplelisting3-27–applicationContext.xml-BeandefinitionforDataTypesExampleclass
Project–ch03-simple-types-examples
Sourcelocation-src/main/resources/META-INF/spring
<beanid="dataTypes"class="sample.spring.chapter03.beans.DataTypesExample">
.....
<constructor-argname="anotherPropertiesType">
<props>
<propkey="book">GettingstartedwiththeSpringFramework</prop>
</props>
</constructor-arg>
<constructor-argname="listType"value-type="java.lang.Integer">
<list>
<value>1</value>
<value>2</value>
</list>
</constructor-arg>
<constructor-argname="mapType">
<map>
<entry>
<key>
<value>mapkey1</value>
</key>
<value>mapkey1’svalue</value>
</entry>
</map>
</constructor-arg>
<constructor-argname="setType">
<set>
<value>Element1</value>
<value>Element2</value>
</set>
</constructor-arg>
</bean>
Theaboveexamplelistingshows:
· the value of anotherPropertiesType (of type java.util.Properties) is specified using the
<props>sub-elementof<constructor-arg>element.Each<prop>elementspecifiesakey-value
pair;thekeyattributespecifiesthekeyvalueandthecontentof<prop>elementisthevaluefor
thekey.Insteadofusing<props>element,youcanuse<value>sub-elementof<constructor-arg>
elementtospecifythevalueforanotherPropertiesTypeargument.
·thevalueoflistTypeconstructorargument(oftypejava.util.List)isspecifiedusingthe<list>
sub-element of <constructor-arg>. The <value> sub-elements of <list> element specify items
contained in the list. The <list> element’s value-type attribute specifies the Java type of the
elements that the java.util.List type constructor argument accepts. As the listType constructor
argumentisoftypeList<Integer>(referexamplelisting3-26),thevalue-typeattribute’svalueis
specifiedasjava.lang.Integer.Thevalue-typeattributeisoptional,andisparticularlyusefulif
you are using a parameterized List type, like List<Integer>. If you specify the value-type
attribute,Springcontainerusestheregisteredpropertyeditorstoperformconversionofvalues
tothetypespecifiedbythevalue-typeattribute,followedbyconverting(ifrequired)thevalues
tothetypeacceptedbytheparameterizedListtype.Ifyoudon’tspecifythevalue-typeattribute,
Springcontainersimplyusestheregisteredpropertyeditorstoperformconversionofvaluesto
thetypeacceptedbytheparameterizedListtype.
·thevalueofmapTypeconstructorargument(oftypejava.util.Map) is specified usingthe
<map>sub-elementof<constructor-arg>.The <entry>sub-elementof <map> specifies a key-
valuepaircontainedintheMap;the<key>elementspecifiesthekeyandthe<value>element
specifiesthevalueforthekey.Thekey-typeandvalue-typeattributesof<map>elementspecify
the Java type of keys and values that java.util.Map accepts. The key-type and value-type
attributes are optional, and especially useful if you are using parameterized Map type, like
Map<Integer,Integer>.Springcontainerusesregisteredpropertyeditorstoperformconversion
of keys and values to the types specified by the key-type and value-type attributes, and to the
typesacceptedbytheparameterizedMaptype.
·thevalueofthesetTypeconstructorargument(oftypejava.util.Set)isspecifiedusingthe
<set> sub-element of <constructor-arg>. Each <value> sub-element of <set> specifies an
elementcontainedintheSet.Thevalue-typeattributeof<set>elementspecifiestheJavatypeof
elementsthatjava.util.Setaccepts.Thevalue-typeattributeisoptional,andisusefulifyouare
using parameterized Set type, like Set<Integer>. Spring container uses registered property
editorstoperformconversionofvaluestothetypespecifiedbythevalue-typeattribute,andto
thetypeacceptedbytheparameterizedSettype.
InDataTypesExample class (refer example listing 3-26 and 3-27), constructor arguments of type List,
Map and Set contained elements of type String or Integer. In an application, a collection may contain
elements of type Map, Set, Class, Properties, or any other Java type. The elements contained in the
collectioncanalsobebeanreferences.Toaddresssuchscenarios,Springallowsyoutouseelementslike
<map>,<set>,<list>,<props>,<ref>,andsoon,assub-elementsof<list>,<map>and<set>elements.
Let’snowlookatexamplesthatdemonstratehowtoadddifferenttypesofelementstoMap,ListandSet
typeconstructorargumentsandbeanproperties.
AddingelementsoftypeList,Map,SetandPropertiestocollectiontypes
IfabeanpropertyorconstructorargumentisoftypeList<List>,simplyuseanested<list>element,as
shownhere:
Examplelisting3-28–Configurationexample:ListinsideaList
<constructor-argname="nestedList">
<list>
<list>
<value>AsimpleStringvalueinthenestedlist</value>
<value>AnothersimpleStringvalueinnestedlist</value>
</list>
</list>
</constructor-arg>
The <constructor-arg> element shown in the above example listing supplies value for a constructor
argumentnamednestedListwhichisoftypeList<List>.Thenested<list>elementrepresentsanelement
oftypeList.Similarly, you can use <map>,<set>and<props>elements inside a<list> element to set
value of properties or constructor arguments of type List<Map>, List<Set> and List<Properties>,
respectively.Aswiththe<list>element,a<set>elementcancontain<set>,<list>,<map>or<props>
element.Incaseofa<map>element,youcanuse<map>,<set>,<list>or<props>elementtospecifykey
andvalueofanentry.
ThefollowingexamplelistingshowshowyoucanspecifyvaluesforaMap<List,Set>typeconstructor
argument:
Examplelisting3-29–Configurationexample:MapcontainingListtypeaskeyandSettypeasvalue
<constructor-argname="nestedListAndSetMap">
<map>
<entry>
<key>
<list>
<value>aListelement</value>
</list>
</key>
<set>
<value>aSetelement</value>
</set>
</entry>
</map>
</constructor-arg>
The above example listing shows that the nestedListAndSetMap constructor argument is of Map type
whosekeyisoftypeListandvalueisoftypeSet.The<key>elementcanhaveeitherofthefollowing
elements as its sub-element: <map>,<set>,<list> and <props>. The value for the key can be defined
using<map>,<set>,<list>or<props>element.
Addingbeanreferencestocollectiontypes
Youcanuse<ref>elementsinside<list>and<set>elementstoaddreferencestobeansintoproperties
andconstructorargumentsoftypeListandSet,respectively.
The following example listing shows how references to beans are added to a List type constructor
argument:
Examplelisting3-30–Configurationexample:Listcontainingreferencetobeans
<bean.....>
<constructor-argname="myList">
<list>
<refbean="aBean"/>
<refbean="bBean"/>
</list>
</constructor-arg>
</bean>
<beanid="aBean"class="somepackage.ABean"/>
<beanid="bBean"class="somepackage.BBean"/>
Theaboveexamplelistingshows that the myList constructorargumentis of typeListand it contains 2
elements-areferencetoaBeanbeanandareferencetobBeanbean.The<ref>element’sbeanattribute
specifiesthenameofthebeanreferencedbythe<ref>element.
Aswiththe<list>element,youcanuse<ref>elementsinside<set>elementtoaddbeanreferencestoa
Set type constructor argument or bean property. In case of <map> element, you can use <ref> element
insidea<key>elementtospecifyabeanreferenceasakey,andusethe<ref>elementtospecifyabean
referenceasavalueforthekey.ThefollowingexamplelistingshowsaMaptypeconstructorargument
thatcontainsasinglekey-valuepairinwhichbothkeyandvaluearereferencestobeans:
Examplelisting3-31–Configurationexample:Mapcontainingbeanreferencesaskeysandvalues
<bean.....>
<constructor-argname="myMapWithBeanRef">
<map>
<entry>
<key>
<refbean="aBean"/>
</key>
<refbean="bBean"/>
</entry>
</map>
</constructor-arg>
</bean>
<beanid="aBean"class="somepackage.ABean"/>
<beanid="bBean"class="somepackage.BBean"/>
The above example listing shows that myMapWithBeanRef constructor argument is of type Map and it
contains a key-value pair in which the key is a reference to aBean bean and corresponding value is a
referencetobBeanbean.
Addingbeannamestocollectiontypes
Ifyouwanttoaddabeanname(asspecifiedbytheidattributeof<bean>element)toaList,MaporSet
type constructor argument or bean property, you can use the <idref>element inside <map>, <set> and
<list> elements. The following example listing shows a Map type constructor argument that contains a
singlekey-valuepair,wherebeannameisthekeyandbeanreferenceisthevalue:
Examplelisting3-32–Configurationexample:Mapcontainingbeannameaskeyandbeanreferenceas
value
<constructor-argname="myExample">
<map>
<entry>
<key>
<idrefbean="sampleBean"/>
</key>
<refbean="sampleBean"/>
</entry>
</map>
</constructor-arg>
<beanid="sampleBean"class="somepackage.SampleBean"/>
TheaboveexamplelistingshowsthatthemyExampleconstructorargumentisoftypeMapwhosekeyis
thestringvalue‘sampleBean’andvalueisthesampleBeanbean.Wecouldhaveused<value>elementto
set‘sampleBean’stringvalueasthekey,but<idref>elementisusedbecauseSpringcontainerverifies
existenceofthesampleBeanbeanwhentheapplicationisdeployed.
NOTEYoucanusethe<idref>elementinsidea<property>or<constructor-arg>elementtosetabean
nameasthevalueofabeanpropertyorconstructorargument.
Addingnullvaluestocollectiontypes
YoucanaddanullvaluetocollectionsoftypeSetandListusing<null>element.Thefollowingexample
listingshowshowtoaddanullvaluetoaSettypeconstructorargumentusing<null>element:
Examplelisting3-33–Configurationexample:Setcontaininganullelement
<constructor-argname="setWithNullElement">
<set>
<value>Element1</value>
<value>Element2</value>
<null/>
</set>
</constructor-arg>
Intheaboveexamplelisting,setWithNullElementconstructorargumentcontains3elements:Element1,
Element2andnull.
ToaddanullkeytoaMaptypeconstructorargumentorproperty,youcanuse<null>elementinsidethe
<key>element.And,toaddanullvalue,youcanadda<null>elementinsidethe<entry>element.The
following example listing shows a Map type constructor argument that contains a null key and a null
value:
Examplelisting3-34–Configurationexample:Mapcontaininganullkeyandanullvalue
<constructor-argname="mapType">
<map>
<entry>
<key>
<null/>
</key>
<null/>
</entry>
</map>
</constructor-arg>
TheaboveexamplelistingshowsthatanelementwithnullkeyandnullvalueisaddedtothemapType
constructorargumentusing<null>element.
NOTEYoucanalsouse<null>elementinside<property>and<constructor-arg>elementstosetnull
valuesforpropertiesandconstructorarguments,respectively.
Let’snowlookathowtospecifyvaluesforarraytypepropertiesandconstructorarguments.
Specifyingvaluesforarrays
If a bean class defines an array type property, you can set its value using the <array> sub-element of
<property> element. Similarly, you can set an array type constructor argument using the <array> sub-
elementof<constructor-arg>element.
Thefollowingexamplelistingshowshowyoucansetabeanpropertyoftypeint[]:
Examplelisting3-35–Configurationexample:Settingvalueofabeanpropertyoftypeint[]
<propertyname="numbersProperty">
<array>
<value>1</value>
<value>2</value>
</array>
</property>
Intheaboveexamplelisting,each<value>sub-elementofthe<array>elementrepresentsanelementin
thenumbersPropertyarray.ThepropertyeditorsregisteredwiththeSpringcontainerareusedtoconvert
thestringvaluespecifiedbyeachofthe<value>elementtointtype.Youcanuse<array>elementinside
<list>,<set>and<map>elements.Youcanalsouse<list>,<set>,<map>,<props>and<ref>elements
insidean<array>elementtocreatearraysofList,Set,Map,Propertiesandbeanreferences,respectively.
Ifyouwanttocreateanarrayofarrays,youcanuse<array>elementsinsidean<array>element.
Wediscussedthat<list>,<map>and<set>elementsareusedtosetpropertiesorconstructorarguments
of type List, Map andSet, respectively. Let’s now look at the default collection implementation that is
createdbySpringforeachoftheseelements.
Defaultcollectionimplementationfor<list>,<set>and<map>elements
The following table shows the default collection implementation that is created by Spring for <list>,
<set>and<map>elements:
Collectionelement DefaultcollectionimplementationcreatedbyS pring
<list> java.util.ArrayList
<set> java.util.LinkedHashSet
<map> java.util.LinkedHashMap
Theabovetablesuggests:
· if aproperty’s(or aconstructor argument’s) value is specified using <list> element, Spring
createsaninstanceofArrayListandassignsittotheproperty(ortheconstructorargument).
· if a property’s (or a constructor argument’s) value is specified using <set> element, Spring
createsaninstanceofLinkedHashSetandassignsittotheproperty(ortheconstructorargument).
·ifaproperty’s(oraconstructorargument’s)valueisspecifiedusing<map>element,Spring
createsaninstanceofLinkedHashMapandassignsittotheproperty(ortheconstructorargument).
It is likely that you may want to substitute a different implementation of List, Set or Map to a bean
propertyoraconstructorargument.Forinstance,insteadofjava.util.ArrayList,youmaywanttoassignan
instanceofjava.util.LinkedListtoabeanpropertyoftypeList.Insuchscenarios,itisrecommendedto
use <list>, <map> and <set> elements of Spring’s util schema (explained in section 3-8). The <list>,
<set>and<map>elementsofSpring’sutilschemaprovidetheoptiontospecifythefully-qualifiedname
oftheconcretecollectionclassthatyouwanttoassigntothepropertyorconstructorargumentofthebean.
Let’snowlookatsomeofthebuilt-inpropertyeditorsprovidedbySpring.
3-5Built-inpropertyeditors
Spring provides a couple of built-in property editors that are useful when setting bean properties and
constructor arguments. Let’s take a quick look at CustomCollectionEditor, CustomMapEditor and
CustomDateEditorbuilt-inpropertyeditors.Toviewthecompletelistofbuilt-inpropertyeditors,referto
org.springframework.beans.propertyeditorspackage.
CustomCollectionEditor
CustomCollectionEditor property editor is responsible for converting a source Collection (like,
java.util.LinkedList) type to the target Collection (like, java.util.ArrayList) type. By default,
CustomCollectionEditorisregisteredforSet,SortedSetandListtypes.
Consider the following CollectionTypesExampleclass that defines attributes (and corresponding setter
methods)oftypeSetandList:
Examplelisting3-36–CollectionTypesExampleclass
Project–ch03-simple-types-examples
Sourcelocation-src/main/java/sample/spring/chapter03/beans
packagesample.spring.chapter03.beans;
importjava.util.List;
importjava.util.Set;
publicclassCollectionTypesExample{
privateSetsetType;
privateListlistType;
.....
//--settermethodsforattributes
publicvoidsetSetType(SetsetType){
this.setType=setType;
}
.....
}
CollectionTypesExampleclassdefinessetTypeandlistTypeattributesoftypeSetandList,respectively.
ThefollowingexamplelistingshowsthebeandefinitionforCollectionTypesExampleclass:
Examplelisting3-37–applicationContext.xml-BeandefinitionforCollectionTypesExampleclass
Project–ch03-simple-types-examples
Sourcelocation-src/main/resources/META-INF/spring
<beanclass="sample.spring.chapter03.beans.CollectionTypesExample">
<propertyname="listType">
<set>
<value>setelement1</value>
<value>setelement2</value>
</set>
</property>
<propertyname="setType">
<list>
<value>listelement1</value>
<value>listelement2</value>
</list>
</property>
.....
</bean>
Youmightthinkthattheaboveconfigurationisincorrectbecause<set>elementhasbeenusedtosetthe
valueoflistType property(of type List), and <list> element has been used to set the value of setType
property(oftypeSet).
Theaboveconfigurationiscompletelylegal,andtheSpringcontainerdoesnotcomplain.Thisisbecause
CustomCollectionEditor converts the ArrayList instance (created corresponding to the <list> type
element)toLinkedHashSettype(animplementationofSettype)beforesettingthesetTypeproperty.Also,
CustomCollectionEditorconverts the LinkedHashSet instance (created corresponding to the <set> type
element)toArrayListtype(animplementationofListtype)beforesettingthelistTypeproperty.
Figure3-4–CustomCollectionEditorconvertstheLinkedHashSettoArrayListtype
Figure3-4showsthattheCustomCollectionEditorconvertstheLinkedHashSettypetoArrayListtosetthe
value of CollectionTypesExample’slistType property. The figure shows the sequence of steps that are
performed by Spring to set the value of listType property. First, Spring creates an instance of
LinkedHashSetcorrespondingtothe<set>element.AsthelistTypepropertyisoftypeList(referexample
listing3-36),theCustomCollectionEditorcomesintopictureforsettingthelistTypeproperty’svalue.If
the type of the bean property is List, CustomCollectionEditor creates an instance of ArrayList and
populatesitwiththeelementsfromtheLinkedHashSet.Intheend,thevalueofthelistTypevariableisset
totheArrayListimplementationcreatedbyCustomCollectionEditor.
Itisimportanttonotethatifapropertyorconstructorargumenttypeisaconcretecollectionclass(like
LinkedList),CustomCollectionEditorsimplycreatesaninstanceoftheconcretecollectionclassandadds
elements to it from the source collection. The following figure shows a scenario in which the bean
propertyisoftypejava.util.Vector(aconcretecollectionclass):
Figure3-5CustomCollectionEditorconvertstheArrayListtoVectortype
The above figure shows that the CustomCollectionEditor creates an instance of Vector (a concrete
collectionclass)andaddselementstoitfromthesourcecollection,ArrayList.
Let’snowlookatCustomMapEditorpropertyeditor.
CustomMapEditor
CustomMapEditorpropertyeditordealswithconvertingasourceMaptype(likeHashMap) toa target
Maptype(likeTreeMap).Bydefault,CustomMapEditorisregisteredonlyforSortedMaptype.
Figure3-6showsascenarioinwhichCustomMapEditorconvertsLinkedHashMap(thesourceMaptype)
toTreeMap(animplementationofSortedMaptype).
Figure3-6showsthesequenceofstepsperformedbySpringtosetthevalueofmapTypeproperty.First,
Spring creates an instance of LinkedHashMap corresponding to the <map> element. As the mapType
propertyisoftypeSortedMap,CustomMapEditorcomesintopicturewhilesettingthevalueofmapType
property. CustomMapEditor creates an instance of TreeMap (a concrete implementation of SortedSet
interface),addskey-valuepairsfromLinkedHashMaptothenewlycreatedTreeMapinstanceandassigns
theTreeMapinstancetothemapTypeproperty.
Figure3-6CustomMapEditorconvertstheLinkedHashMap(thesourceMaptype)toTreeMap(thetarget
Maptype)type
CustomDateEditor
CustomDateEditorisapropertyeditorforjava.util.Datetypebeanpropertiesandconstructorarguments.
CustomDateEditorsupportsacustomjava.text.DateFormatthatisusedforformattingadate/timestringto
a java.util.Date type object, and parsing a java.util.Date type object to a date/time string. In the next
section,we’llseehowCustomDateEditorisusedforsettingbeanpropertiesandconstructorargumentsof
typejava.util.Date.In ch03-simple-types-examples project,CustomDateEditor converts the string value
ofabeanproperty(referdateOfInceptionattributeofBankDetailsclass)orconstructorargument(refer
dateTypeconstructorargumentofDataTypesExampleclass)tojava.util.Datetype.
Inch03-simple-types-examples project, some of the other built-in property editors that are utilized by
beans include: ByteArrayPropertyEditor - for converting a string value to byte[] (refer
bankPrimaryBusinessattributeofBankDetailsclass),CurrencyEditor–forconvertingacurrencycodeto
a java.util.Currency object (refer primaryCurrency attribute of BankDetails class),
CharacterArrayPropertyEditor – for converting a string value to a char[] (refer headOfficeAddress
attributeofBankDetailsclass),andsoon.
Let’snowlookathowtoregisterpropertyeditorswiththeSpringcontainer.
3-6RegisteringpropertyeditorswiththeSpringcontainer
Spring’sBeanWrapperImplclassregistersacoupleofbuilt-inpropertyeditorswiththeSpringcontainer.
Forinstance,CustomCollectionEditor,CustomMapEditor,CurrencyEditor,ByteArrayPropertyEditorand
CharacterArrayEditor property editors are registered by default with the Spring container. But,
CustomDateEditor property editor is not registered by default with the Spring container. To register
propertyeditorswith the Springcontainer,youcanuseSpring’s CustomEditorConfigurerspecial bean.
CustomEditorConfigurer class implements Spring’s BeanFactoryPostProcessor interface (explained in
detailinsection5-4ofchapter5),anditisautomaticallydetectedandexecutedbytheSpringcontainer.
In ch03-simple-types-examples project, BankDetails class (refer example listing 3-24) defines a
dateOfInceptionpropertyoftypejava.util.Date.ThevaluespecifiedforthedateOfInceptionpropertyis
‘30-01-2012’ (refer example listing 3-25). To convert the string value ‘30-01-2012’ to java.util.Date
type,youmustregisteracustompropertyeditorforjava.util.DatetypeoryoucanregisterSpring’sbuilt-
inCustomDateEditorpropertyeditorwiththeSpringcontainer.
ToregisterpropertyeditorswiththeSpringcontainer,youneedtodothefollowing:
1. Create a class that implements Spring’s PropertyEditorRegistrar interface. This class is
responsibleforregisteringpropertyeditorswiththeSpringcontainer.
2.ConfigurethePropertyEditorRegistrarimplementationasaSpringbeanintheapplicationcontext
XMLfile.
3.ConfigureSpring’sCustomEditorConfigurerspecialbeanintheapplicationcontextXMLfile,and
provideitwithreferencetothePropertyEditorRegistrarimplementation(thatyoucreatedinstep1
andconfiguredinstep2).
Let’s now see how CustomDateEditor is registered with the Spring container in ch03-simple-types-
examplesproject.
CreatingaPropertyEditorRegistrarimplementation
The following example listing shows the MyPropertyEditorRegistrar class that implements
PropertyEditorRegistrarinterface:
Examplelisting3-38–MyPropertyEditorRegistrarclass
Project–ch03-simple-types-examples
Sourcelocation-src/main/java/sample/spring/chapter03/beans
packagesample.spring.chapter03.beans;
importjava.text.SimpleDateFormat;
importjava.util.Date;
importorg.springframework.beans.PropertyEditorRegistrar;
importorg.springframework.beans.PropertyEditorRegistry;
importorg.springframework.beans.propertyeditors.CustomDateEditor;
publicclassMyPropertyEditorRegistrarimplementsPropertyEditorRegistrar{
@Override
publicvoidregisterCustomEditors(PropertyEditorRegistryregistry){
registry.registerCustomEditor(Date.class,newCustomDateEditor(
newSimpleDateFormat("dd-MM-yyyy"),false));
}
}
The above example listing shows that the MyPropertyEditorRegistrar class implements Spring’s
PropertyEditorRegistrar interface, and provides implementation for registerCustomEditors method
defined in the PropertyEditorRegistrar interface. The PropertyEditorRegistry instance passed to the
registerCustomEditors method is used for registering property editors. PropertyEditorRegistry’s
registerCustomEditor method is used for registering a PropertyEditor implementation with the Spring
container. In the above example listing, PropertyEditorRegistry’s registerCustomEditor is used for
registeringaCustomDateEditorpropertyeditorwiththeSpringcontainer.
ConfiguringtheCustomEditorConfigurerclass
The following example listing shows how the CustomEditorConfigurer class is configured in the
applicationcontextXMLfile:
Examplelisting3-39–applicationContext.xml-CustomEditorConfigurerconfiguration
Project–ch03-simple-types-examples
Sourcelocation-src/main/resources/META-INF/spring
<beanid="myPropertyEditorRegistrar"
class="sample.spring.chapter03.beans.MyPropertyEditorRegistrar"/>
<beanid="editorConfigurer"
class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<propertyname="propertyEditorRegistrars">
<list>
<refbean="myPropertyEditorRegistrar"/>
</list>
</property>
</bean>
In the above example listing, myPropertyEditorRegistrar bean definition configures
MyPropertyEditorRegistrarclassasaSpringbean.MyPropertyEditorRegistrarclassimplementsSpring’s
PropertyEditorRegistrar interface, and is responsible for registering additional property editors with
Spring container. CustomEditorConfigurer’s propertyEditorRegistrars property specifies a list of
PropertyEditorRegistrar implementations. In the above example listing, myPropertyEditorRegistrar is
specified as one of the values of propertyEditorRegistrars property. CustomEditorConfigurer bean is
automaticallydetectedandexecutedbytheSpringcontainer,resultinginregistrationofpropertyeditors
bytheMyPropertyEditorRegistrarinstance.
Let’s now look at how to use p-namespace (for bean properties) and c-namespace (for constructor
arguments)towriteconcisebeandefinitionsinapplicationcontextXMLfiles.
3-7Concisebeandefinitionswithpandcnamespaces
To make bean definitions less verbose in application context XML files, Spring provides p and c
namespaces tospecify values for bean properties andconstructor arguments, respectively. Thep and c
namespacesarealternativestousing<property>and<constructor-arg>elements,respectively.
Let’sfirstlookatp-namespace.
IMPORTchapter3/ch03-namespaces-example(ThisprojectshowsaSpringapplicationinwhichbean
properties and constructor arguments are set using p- and c-namespaces, respectively. To run the
application,executethemainmethodoftheSampleAppclassofthisproject)
p-namespace
Tousep-namespacetosetbeanproperties,specifybeanpropertiesasattributesofthe<bean>element,
andspecifyeachbeanpropertytobeinthep-namespace.
Thefollowingbeandefinitionshowshowtousep-namespacetosetbeanproperties:
Examplelisting3-40–applicationContext.xml-p-namespaceexample
Project–ch03-namespaces-example
Sourcelocation-src/main/resources/META-INF/spring
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation=".....">
<beanid="bankDetails"class="sample.spring.chapter03.beans.BankDetails"
p:bankName="MyPersonalBank"p:bankPrimaryBusiness="Retailbanking"
p:headOfficeAddress="Addressofheadoffice"p:privateBank="Y"
p:primaryCurrency="INR"p:dateOfInception="30-01-2012"
p:branchAddresses-ref="branchAddresses"/>
.....
</beans>
In the application context XML file shown above, p-namespace is specified via xmlns attribute. The
bankDetailsbeandefinitionmakesuseofthepprefixforthep-namespacetospecifybeanproperties.If
you compare the above example listing with the example listing 3-25, you’ll notice that the above
examplelistingislessverbose.Eventhoughitispossibletouseamixof<property>elementsand p-
namespace to specify bean properties, it’s recommended that you choose one style for specifying bean
propertiesanduseitconsistentlyinbeandefinitions.
NOTE As p-namespace is implemented as part of Spring, there is no schema corresponding to p-
namespace. For this reason, you don’t see any schema reference corresponding to p-namespace in
example listing 3-40. If you want your IDE to autocomplete bean property names when using p-
namespace,considerusingIntelliJIDEAorSpringSourceToolSuite(STS).
Ifabeanpropertyisnotareferencetoanotherbean,itisspecifiedusingthefollowingsyntax:
p:<property-name>="<property-value>"
here,<property-name>isthenameofthebeanproperty,and<property-value>isthevalueofthebean
property.
Ifabeanpropertyisareferencetoanotherbean,itisspecifiedusingthefollowingsyntax:
p:<property-name>-ref="<bean-reference>"
here,<property-name>isthenameofthebeanproperty,and<bean-reference>istheid(orname)of
thereferencedbean.Itisimportanttonotethatthenameofthebeanpropertyisfollowedby--ref.Asthe
branchAddressespropertyofBankDetailsbeanrepresentsareferencetothebranchAddressesbean,the
branchAddressespropertyisspecifiedasp:branchAddresses-refinexamplelisting3-40.
Let’snowlookathowc-namespaceisusedforsettingconstructorarguments.
c-namespace
To use c-namespace to supply values for constructor arguments, specify constructor arguments as
attributesofthe<bean>element,andspecifyeachconstructorargumenttobeinthec-namespace.
ThefollowingexamplelistingshowstheBankStatementclassthatwe’llconfigureasaSpringbeanusing
c-namespace.
Examplelisting3-41–BankStatementclass
Project–ch03-namespaces-example
Sourcelocation-src/main/java/sample/spring/chapter03/beans
packagesample.spring.chapter03.beans;
importjava.beans.ConstructorProperties;
publicclassBankStatement{
.....
@ConstructorProperties({"transactionDate","amount","transactionType",
"referenceNumber"})
publicBankStatement(DatetransactionDate,doubleamount,
StringtransactionType,StringreferenceNumber){
this.transactionDate=transactionDate;
this.amount=amount;
.....
}
.....
}
ThefollowingbeandefinitionfortheBankStatementclassshowsusageofc-namespaceforsettingvalues
ofconstructorarguments:
Examplelisting3-42–applicationContext.xml-c-namespaceexample
Project–ch03-namespaces-example
Sourcelocation-src/main/resources/META-INF/spring
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation=".....">
.....
<beanid="bankStatement"class="sample.spring.chapter03.beans.BankStatement"
c:transactionDate="30-01-2012"
c:amount="1000"
c:transactionType="Credit"
c:referenceNumber="1110202"/>
.....
</beans>
In the above example listing, c-namespace is specified via xmlns attribute. The bankStatement bean
definition makes use of the c prefix for the c-namespace to specify constructor arguments. The syntax
followedforspecifyingconstructorargumentsusingc-namespaceissimilartowhatwesawincaseofp-
namespace.
NOTE As c-namespace is implemented as part of Spring, there is no schema corresponding to c-
namespace. For this reason, you don’t see any schema reference corresponding to c-namespace in
examplelisting 3-42.If youwantyour IDEtoautocompleteconstructorargumentnames whenusingc-
namespace,considerusingIntelliJIDEAorSpringSourceToolSuite(STS).
Ifaconstructorargumentisnotareferencetoanotherbean,itisspecifiedusingthefollowingsyntax:
c:<constructor-argument-name>="<constructor-argument-value>"
here, <constructor-argument-name> is the name of the constructor argument, and <constructor-
argument-value>isthevalueoftheconstructorargument.
Ifaconstructorargumentisareferencetoanotherbean,itisspecifiedusingthefollowingsyntax:
c:<constructor-argument-name>-ref="<bean-reference>"
here,<constructor-argument-name>isthenameoftheconstructorargument,and<bean-reference>is
theid(orname)ofthereferencedbean.Itisimportanttonotethatthenameoftheconstructorargumentis
followedby--ref.Forinstance,ifaconstructorargumentnamedmyargumentrepresentsareferencetoa
beanwithid‘x’,youspecifymyargumentconstructorargumentas:
c:myargument-ref="x"
As mentioned earlier, if a class is compiled with debug flag enabled, constructor argument names are
preserved in the generated .class file. If the BankStatement class is not compiled with the debug flag
enabled,theconfigurationshowninexamplelisting3-42willnotwork.Insuchcases,yousupplyvalues
forconstructorargumentsusingtheirindex,asshownhere:
Examplelisting3-43–Supplyingvaluesforconstructorargumentsusingtheirindex
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation=".....">
.....
<beanid="bankStatement"class="sample.spring.chapter03.beans.BankStatement"
c:_0="30-01-2012"
c:_1="1000"
c:_2="Credit"
c:_3="1110202"/>
.....
</beans>
The above example listing shows bean definition for the BankStatement class, which uses constructor
argument index instead of constructor arguments name to supply values. It is important to note that the
indexoftheconstructorargumentisprefixedwithanunderscorebecauseattributenamesinXMLcannot
beginwithanumericvalue.Ifaconstructorargumentisareferencetoanotherbean,-refmustbeaddedto
the index of the constructor argument. For instance, if the constructor argument at index 0 represents
referencetoanotherbean,itisspecifiedasc:_0-ref.Eventhoughit’spossibletouseacombinationof
<constructor-arg>elementsandc-namespacetospecifyconstructorarguments,it’srecommendedthatyou
chooseonestyleofspecifyingconstructorargumentsanduseitconsistentlyinbeandefinitions.
Wesawearlierhow<list>,<map>and<set>elementsareusedtosetpropertiesorconstructorarguments
oftypeList,Map andSet, respectively. Let’s now look at Spring’s util schema that simplifies creating
collectiontypes,Propertiestype,constants,andsoon,andexposingthemasaSpringbeans.
3-8Spring’sutilschema
Spring’s util schema simplifies configuring beans by providing a concise way to perform common
configurationtasks.Thefollowingtabledescribesthevariouselementsofutilschema:
Element Description
<list> Createsajava.util.Listtype,andexposesitasabean
<map> Createsajava.util.Maptype,andexposesitasabean
<set> Createsajava.util.Settype,andexposesitasabean
<constant> Exposesapublicstaticfieldonatypeasabean
<property-path> Exposesabeanpropertyasabean
<properties> Createsajava.util.Propertiesfromapropertiesfile,andexposesitasabean
NOTE All the elements of Spring’s util schema accept a scope attribute that identifies whether the
exposedbeanisasingleton-orprototype-scoped.
SpringprovidesaFactoryBeaninterfacethatcanbeimplementedtocreateafactoryobjectresponsible
forcreatingbeaninstances.Insteadofusingutilschema’selementsmentionedintheabovetable,youcan
useanout-of-the-boxFactoryBeanimplementationprovidedbySpringtoperformthesamefunctionality.
Inthissection,we’lllookattheutilschema’selementsandthebuilt-inFactoryBeanimplementationsthat
youcanuseinsteadofutilschema’selements.
IMPORTchapter3/ch03-util-schema-examples(This project shows a Spring application that makes
useofSpring’sutilschemaelementstocreatesharedinstancesofList,Set,Map,andsoon.Torunthe
application,executethemainmethodoftheSampleAppclassofthisproject)
Let’sfirstlookatthe<list>element.
<list>
The<list> element ofSpring’s util schema is used for creating objects of type java.util.List, as shown
here:
Examplelisting3-44–applicationContext.xml-utilschema’s<list>element
Project–ch03-util-schema-examples
Sourcelocation-src/main/resources/META-INF/spring
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation=".....http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<beanid="dataTypes"class="sample.spring.chapter03.beans.DataTypesExample">
.....
<constructor-argname="listType"ref="listType"/>
.....
</bean>
<util:listid="listType"list-class="java.util.ArrayList">
<value>AsimpleStringvalueinlist</value>
<value>AnothersimpleStringvalueinlist</value>
</util:list>
</beans>
First,youneedtoincludeSpring’sutilschematoaccessitselements.Intheaboveexamplelisting,the
<list>elementofutilschemacreatesaninstanceofjava.util.ArrayListandexposesitasabean.Theid
attribute specifies the bean id with which the java.util.ArrayList instance is exposed, and list-class
attribute specifies the concrete implementation of java.util.List that you want to create. If you don’t
specify the list-class attribute, an instance of java.util.ArrayList is created by default. The <value>
elementofSpring’sbeansschemaisusedtospecifyindividualelementsofthelist.
As util schema’s <list> element exposes a List instance as a bean, you can refer to the exposed List
instancefromotherbeans.Forinstance,intheaboveexamplelisting,thelistTypeconstructorargument
(oftypejava.util.List) of DataTypesExamplebeanspecifies listType as the value of the ref attribute to
refertotheListinstancecreatedbytheutilschema’s<list>element.
If you compare the util schema’s <list> element shown in the above example listing with the beans
schema’s<list>element(referexamplelisting3-27),you’llnoticethattheutilschema’s<list>element
gives youcontrol over the List implementation to create. For instance, if you want to create a Vector
insteadofanArrayListinstance,specifyjava.util.Vectorasthevalueofthelist-classattribute.
Let’snowlookatSpring’sListFactoryBeanwhichyoucanuseinsteadofutilschema’s<list>element.
ListFactoryBean
Analternativetousingutilschema’s<list>elementisSpring’sListFactoryBean–afactorythatisused
forcreatinginstancesofjava.util.ListandmakingthemavailableasSpringbeans.
ThefollowingexamplelistingshowshowtheListFactoryBeancanbeusedinsteadoftheutilschema’s
<list>element:
Examplelisting3-45–ListFactoryBeanexample
<beans.....>
<beanid="dataTypes"class="sample.spring.chapter03.beans.DataTypesExample">
.....
<constructor-argname="listType"ref="listType"/>
.....
</bean>
<beanid="listType"class="org.springframework.beans.factory.config.ListFactoryBean">
<propertyname="sourceList">
<list>
<value>AsimpleStringvalueinlist</value>
<value>AnothersimpleStringvalueinlist</value>
</list>
</property>
</bean>
</beans>
Intheaboveexamplelisting,thesourceListpropertyofListFactoryBeanspecifiestheelementsinthelist.
Bydefault,ListFactoryBeancreatesaninstanceofjava.util.ArrayList.IfyouwanttheListFactoryBeanto
createaninstanceofanyotherListimplementation(likeVector),settheListFactoryBean’stargetListClass
property.ThetargetListClasspropertyspecifiesthefully-qualifiednameoftheconcreteimplementation
classofjava.util.ListinterfacethatshouldbecreatedbytheListFactoryBean.
Ifyoucompareexamplelistings3-44and3-45,you’llnoticethatusingutilschema’s<list>elementisa
lotsimplerthanusingtheListFactoryBeantocreateaListinstanceandexposeitasabean.
<map>
The <map> element of Spring’s util schema is used for creating an object of type java.util.Map and
exposingitasabean,asshownhere:
Examplelisting3-46–applicationContext.xml-utilschema’s<map>element
Project–ch03-util-schema-examples
Sourcelocation-src/main/resources/META-INF/spring
<beans.....
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation=".....http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<beanid="dataTypes"class="sample.spring.chapter03.beans.DataTypesExample">
.....
<constructor-argname="mapType"ref="mapType"/>
.....
</bean>
<util:mapid="mapType"map-class="java.util.TreeMap">
<entrykey="mapkey1"value="mapkey1’svalue"/>
</util:map>
.....
</beans>
Intheaboveexamplelisting,utilschema’s<map>elementcreatesaninstanceofjava.util.TreeMapand
exposes it as a bean. The id attribute specifies the id with which the bean is made available to other
beans,andmap-classattributespecifiesthefully-qualifiednameoftheconcreteimplementationclassof
java.util.Map interface that should be created by the <map> element. The <entry> element of Spring’s
beansschemaspecifiesakey-valuepairinthecreatedMapinstance.
Asthe<map>elementexposesaMapinstanceasabean,theexposedMapinstancecanbereferenced
fromotherbeans.Forinstance,intheaboveexamplelisting,DataTypesExample’smapTypeconstructor
argument (of type java.util.Map) specifies value of ref attribute as mapType to refer to the TreeMap
instancecreatedbythe<map>element.
NOTEWesawearlierinthischapterthat<key>and<value>sub-elementsof<entry>areusedtospecify
akey-valuepaircontainedintheMapinstance.Theexamplelisting3-46showsthatyoucanalsospecify
akey-valuepaircontainedintheMapinstancebyusing<entry>element’skeyandvalueattributes.
If you compare the util schema’s <map> element shown in the above example listing with the beans
schema’s <map> element in example listing 3-27, you’ll notice that the util schema’s <map> element
gives you control over the Map implementation to create. For instance, if you want to use
LinkedHashMap instead of TreeMap, specify java.util.LinkedHashMap as the value of map-class
attribute. If you don’t specify the map-class attribute, Spring container creates an instance of
java.util.LinkedHashMapbydefault.
Let’snowlookatSpring’sMapFactoryBeanthatyoucanuseinsteadofutilschema’s<map>element.
MapFactoryBean
Insteadofusingutilschema’s<map>element,youcanuseSpring’sMapFactoryBean–afactorythatis
usedforcreatinginstancesofjava.util.MapandmakingthemavailableasSpringbeans.
ThefollowingexamplelistingshowshowMapFactoryBeanisused:
Examplelisting3-47–MapFactoryBeanexample
<beans.....>
<beanid="dataTypes"class="sample.spring.chapter03.beans.DataTypesExample">
.....
<constructor-argname="mapType"ref="mapType"/>
.....
</bean>
<beanid="mapType"class="org.springframework.beans.factory.config.MapFactoryBean">
<propertyname="sourceMap">
<map>
<entrykey="mapkey1"value="mapkey1’svalue"/>
</map>
</property>
</bean>
.....
</beans>
In the above example listing, MapFactoryBean’s sourceMap property specifies the key-value pairs
containedintheMapinstancecreatedbytheMapFactoryBean.Bydefault,MapFactoryBeancreatesan
instanceofjava.util.LinkedHashMap.YoucancontroltheMapinstancecreatedbyMapFactoryBeanby
setting the targetMapClass property. The targetMapClass specifies the fully-qualified name of the
concreteimplementationclassofjava.util.Mapinterface.Forinstance,ifyouspecifyjava.util.HashMap
asthevalueoftargetMapClass,MapFactoryBeancreatesaninstanceofjava.util.HashMap.
If you compare example listings 3-46 and 3-47, you’ll notice that using util schema’s <map> element
resultsinamoreconciseconfigurationthanMapFactoryBeanforcreatingMapinstances.
<set>
The<set>elementofSpring’sutilschemaisusedforcreatinganobjectoftypejava.util.Setandexposing
itasabean,asshownhere:
Examplelisting3-48–applicationContext.xml-utilschema’s<set>element
Project–ch03-util-schema-examples
Sourcelocation-src/main/resources/META-INF/spring
<beans.....
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation=".....http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<beanid="dataTypes"class="sample.spring.chapter03.beans.DataTypesExample">
.....
<constructor-argname="setType"ref="setType"/>
</bean>
<util:setid="setType"set-class="java.util.HashSet">
<value>Element1</value>
<value>Element2</value>
</util:set>
.....
</beans>
Intheaboveexamplelisting,utilschema’s<set>elementcreatesaninstanceofHashSetandexposesitas
aSpringbeanwithidassetType.Theidattributespecifiestheidwithwhichthebeanismadeavailable
to other beans, and the set-class attribute specifies the concrete implementation class of java.util.Set
interface that should be created by the <set> element. The <value> element of Spring’s beans schema
specifiesanelementinthecreatedSetinstance.
TheSetinstancecreatedbythe<set>elementcanbereferencedfromotherbeans.Forinstance,inthe
aboveexamplelisting,DataTypesExample’ssetTypeconstructorargument(oftypejava.util.Set)refersto
theHashSetinstancecreatedbythe<set>element.
Insteadofusingutilschema’s<set>element,youcanuseSpring’sSetFactoryBeantocreateaSetinstance
andexposeitasaSpringbean.
SetFactoryBean
Spring’sSetFactoryBeanisafactoryobjectforcreatinginstancesofjava.util.Settype.
ThefollowingexamplelistingshowshowyoucanuseSetFactoryBeantoperformthesamefunctionasthe
utilschema’s<set>element:
Examplelisting3-49–SetFactoryBeanexample
<beans.....>
<beanid="dataTypes"class="sample.spring.chapter03.beans.DataTypesExample">
.....
<constructor-argname="setType"ref="setType"/>
.....
</bean>
<beanid="setType"class="org.springframework.beans.factory.config.SetFactoryBean">
<propertyname="sourceSet">
<set>
<value>Element1</value>
<value>Element2</value>
</set>
</property>
</bean>
.....
</beans>
Intheaboveexamplelisting,SetFactoryBean’ssourceSetpropertyspecifiestheelementscontainedinthe
SetinstancecreatedbytheSetFactoryBean.SetFactoryBean’stargetSetClasspropertyspecifiesthefully-
qualified name of the class that implements java.util.Set interface. If the targetSetClass property is
specified,SetFactoryBeancreatesaninstance of the class specified bythe targetSetClass property and
makes it available as a Spring bean. For instance, if you specify java.util.HashSet as the value of
targetSetClass,SetFactoryBeancreatesaninstanceofjava.util.HashSet.IfthetargetSetClasspropertyis
unspecified,SetFactoryBeancreatesaninstanceofjava.util.LinkedHashSet.
The above example listing shows that using util schema’s <set> element results in a more concise
configurationthanusingSetFactoryBeanforcreatingSetinstances.
<properties>
Theutilschema’s<properties>elementisusefulifyouwanttocreateaninstanceofjava.util.Properties
objectfromapropertiesfile,andexposethejava.util.Propertiesobjectasabean.
Thefollowingexamplelistingshowshowthe<properties>elementisused:
Examplelisting3-50–applicationContext.xml-utilschema’s<properties>element
Project–ch03-util-schema-examples
Sourcelocation-src/main/resources/META-INF/spring
<beans.....
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation=".....http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<beanid="bankDetails"class="sample.spring.chapter03.beans.BankDetails">
.....
<propertyname="branchAddresses"ref="branchAddresses"/>
</bean>
.....
<util:propertiesid="branchAddresses"
location="classpath:META-INF/addresses.properties"/>
</beans>
Intheaboveexamplelisting,<properties>elementcreatesaninstanceofjava.util.Propertiescontaining
propertiesloadedfromtheaddresses.propertiesfile(specifiedbythelocationattribute),andexposesthe
java.util.PropertiesinstanceasabeanwithbranchAddressesastheid(specifiedbytheidattribute).The
above example listing also shows that the branchAddresses property (of type java.util.Properties) of
BankDetailsbeanreferstothebranchAddressesbeancreatedbytheutilschema’s<properties>element.
Analternativetousingthe<properties>elementisSpring’sPropertiesFactoryBean.
PropertiesFactoryBean
Spring’sPropertiesFactoryBeanisafactoryforcreatinginstancesofjava.util.Properties.
The following example listing shows how you can use PropertiesFactoryBean to perform the same
functionastheutilschema’s<properties>element:
Examplelisting3-51–PropertiesFactoryBeanexample
<beans.....>
<beanid="bankDetails"class="sample.spring.chapter03.beans.BankDetails">
.....
<propertyname="branchAddresses"ref="branchAddresses"/>
</bean>
<beanid="branchAddresses"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<propertyname="location"value="classpath:META-INF/addresses.properties"/>
</bean>
.....
</beans>
Intheaboveexamplelisting,beandefinitionforSpring’sPropertiesFactoryBeancreates an instance of
java.util.Properties from the properties loaded from addresses.properties file (specified by location
property),andexposesthejava.util.PropertiesinstanceasabeanwithbranchAddressesastheid.
<constant>
Theutilschema’s<constant>elementisusedforexposinganobject’spublicstaticfieldasaSpringbean.
Thefollowingexamplelistingshowsanexampleusageof<constant>element:
Examplelisting3-52–applicationContext.xml-utilschema’s<constant>element
Project–ch03-util-schema-examples
Sourcelocation-src/main/resources/META-INF/spring
<beans.....xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation=".....http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<beanid="dataTypes"class="sample.spring.chapter03.beans.DataTypesExample">
.....
<constructor-argname="booleanType"ref="booleanTrue"/>
.....
</bean>
<util:constantid="booleanTrue"static-field="java.lang.Boolean.TRUE"/>
.....
</beans>
Theutilschema’s<constant>elementexposesthevaluespecifiedbyitsstatic-fieldattributeasaSpring
bean. In the above example listing, <constant> element exposes a bean whose value is
java.lang.Boolean.TRUEandidisbooleanTrue.Youcanspecifyanypublicstaticfieldasthevalueofthe
static-fieldattributeand refertoitfromotherbeansintheSpringcontainer.Forinstance,intheabove
example listing, booleanType bean is referenced by DataTypesExample’s booleanType constructor
argumentoftypeboolean.
A rather less concise way to expose public static fields as Spring beans is to use Spring’s
FieldRetrievingFactoryBean.
FieldRetrievingFactoryBean
Spring’sFieldRetrievingFactoryBeanisafactoryforretrievingvalueofapublicstaticfieldspecifiedby
the FieldRetrievingFactoryBean’s staticField property. The value retrieved by the
FieldRetrievingFactoryBeanisexposedasabean.YoucanalsousetheFieldRetrievingFactoryBeanto
retrieveanon-staticfieldvalue.
ThefollowingexamplelistingshowsanexampleusageofFieldRetrievingFactoryBean:
Examplelisting3-53–FieldRetrievingFactoryBeanexample
<beans.....>
<beanid="dataTypes"class="sample.spring.chapter03.beans.DataTypesExample">
.....
<constructor-argname="booleanType"ref="booleanTrue"/>
.....
</bean>
<beanid="booleanTrue"
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<propertyname="staticField"value="java.lang.Boolean.TRUE"/>
</bean>
.....
</beans>
Intheaboveexamplelisting,FieldRetrievingFactoryBeanretrievesthevalueofjava.lang.Boolean.TRUE
field and exposes it as a bean. The bean exposed by the FieldRetrievingFactoryBean is referenced by
DataTypesExample’sbooleanTypeconstructorargumentoftypeboolean.
<property-path>
Theutilschema’s<property-path>elementisusedtoexposeabeanpropertyvalueasabean.
Thefollowingexamplelistingshowsanexampleusageof<property-path>element:
Examplelisting3-54–applicationContext.xml-utilschema’s<property-path>element
Project–ch03-util-schema-examples
Sourcelocation-src/main/resources/META-INF/spring
<beans.....
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation=".....http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<beanid="bankDetails"class="sample.spring.chapter03.beans.BankDetails">
.....
<propertyname="dateOfInception"ref="dateType"/>
.....
</bean>
<util:property-pathid="dateType"path="dataTypes.dateType"/>
<beanid="dataTypes"class="sample.spring.chapter03.beans.DataTypesExample">
.....
<propertyname="dateType"value="30-01-2012"/>
.....
</bean>
</beans>
In the above example listing, DataTypesExample’s dateType property (of type java.util.Date) value is
specified as ‘30-01-2012’. The <property-path> element retrieves the DataTypesExample’s dateType
propertyandexposesitasabeanwithidasdateType.Thepathattributeof<property-path>elementhas
thefollowingsyntax:
<bean-name>.<bean-property>
Here,<bean-name>istheidornameofthebean,and<bean-property>isthenameoftheproperty.
As<property-path>elementexposesa bean,theexposedbean canbereferencedbyother beansinthe
Spring container. For instance in the above example listing, dateType bean is referenced by
dateOfInceptionpropertyofBankDetailsbean.
Instead of using <property-path> element, you can use Spring’s PropertyPathFactoryBean to expose a
beanpropertyvalueasabean.
PropertyPathFactoryBean
PropertyPathFactoryBean is a factory used for creating bean instances that represent a bean property
value.
ThefollowingexamplelistingshowshowtousePropertyPathFactoryBean:
Examplelisting3-55–PropertyPathFactoryBeanexample
<beans.....
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation=".....http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<beanid="bankDetails"class="sample.spring.chapter03.beans.BankDetails">
.....
<propertyname="dateOfInception"ref="dateType"/>
.....
</bean>
<beanid="dataType"
class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
<propertyname="targetBeanName"value="dataTypes"/>
<propertyname="propertyPath"value="dateType"/>
</bean>
<beanid="dataTypes"class="sample.spring.chapter03.beans.DataTypesExample">
.....
<propertyname="dateType"value="30-01-2012"/>
.....
</bean>
</beans>
In the above example listing, PropertyPathFactoryBean is used to create an instance of a bean that
representsthevalueofdateTypepropertyofdataTypesbean.PropertyPathFactoryBean’stargetBeanName
attributespecifiestheidornameofthebeanthatcontainstheproperty,andPropertyPathFactoryBean’s
propertyPath attribute specifies thename ofthe property whose valueis tobeexposed as a bean. The
bean instance created by PropertyPathFactoryBean can be accessed by other beans in the Spring
container. In the above example listing, the dataType bean created by PropertyPathFactoryBean is
referencedbydateOfInceptionproperty(oftypejava.util.Date)ofBankDetailsbean.
Now, that we have taken an in-depth look at util schema elements, let’s look at Spring’s FactoryBean
interface.
3-9FactoryBeaninterface
Spring’sFactoryBeaninterfaceisimplementedbyclassesthatactasafactoryforcreatingbeaninstances.
Intheprevioussection,wesawthattheclassesthatimplementtheFactoryBeaninterfaceareconfigured
intheapplicationcontextXMLfilelikeanyotherbean.FactoryBeanisparticularlyusefulifyouwantto
performcomplicatedconditionalcheckstodecideonwhichbeantypetocreate,andtoexecutecomplex
beaninitializationlogic.
Let’snowlookatanapplicationscenarioinwhichwe’lluseFactoryBeanforselectingabeantype,and
thencreatingit.
MyBankapplication–Storingeventsinthedatabase
In MyBank application, important events, like credit and debit transactions, open and liquidate fixed
deposits,andsoon,aresavedinthedatabase.MyBankmaydirectlysavetheseeventsinthedatabaseor
indirectlybyfirstsendingtheeventstoamessagingmiddlewareorawebservice.Thefollowingtable
describestheclassesthataredefinedbytheMyBankapplicationfordirectlyorindirectlysavingevents:
Class Description
DatabaseEventSender
Classthatcontainsthefunctionalityforsavingeventsinthedatabase
MessagingEventSender Classthatcontainsthefunctionalityforsendingeventstoamessagingmiddleware
WebServiceEventSender Classthatcontainsthefunctionalityforsendingeventstoaremotewebservice
Thedecisiontodirectlysavetheeventsinthedatabaseortosendthemtoamessagingmiddlewareora
web service is based on configuration. For instance, if MyBank finds that there exists a
database.properties file, MyBank reads the configuration information (like database url, username and
password)fromthedatabase.propertiesfileandcreatestheDatabaseEventSenderinstance.Similarly,ifa
messging.propertiesfileexists,MyBankcreatesaninstanceofMessagingEventSenderinstance,andifa
webservice.propertiesfileexists,aninstanceofWebServiceEventSenderiscreated.
Initializing DatabaseEventSender, MessagingEventSender and WebServiceEventSender instances may
require executing complex initialization logic. For instance, you need to create (or obtain from JNDI)
javax.jms.ConnectionFactory and javax.jms.Destination instances and set them on the
MessagingEventSender instance so that the MessagingEventSender can send JMS messages to the
messagingmiddleware.
The following class diagram shows that the FixedDepositServiceImpl class of MyBank uses either
DatabaseEventSender or MessagingEventSender or WebServiceEventSender instance to directly or
indirectlysaveeventsrelatedtofixeddepositsinthedatabase:
Figure3-7FixedDepositServiceImplclassusesoneoftheimplementationsofEventSenderinterface.
Intheaboveclassdiagram,sendEventmethodofEventSenderinterfacedefinesthecontractfordirectly
or indirectly saving events in the database. DatabaseEventSender, MessagingEventSender and
WebServiceEventSender classes implement the EventSender interface and provide an appropriate
implementationforthesendEventmethod.
Let’snowlookathowFactoryBeansimplifieschoosingtherightimplementationofEventSenderinterface
andinitializingit.
IMPORTchapter3/ch03-bankapp-factorybean(ThisprojectshowstheMyBankapplicationthatusesa
FactoryBean implementation to create objects of type EventSender. To run the application, execute the
mainmethodoftheBankAppclassofthisproject)
MyBank–FactoryBeanexample
In MyBank, selecting the right EventSender implementation and initializing it is an involved task;
therefore,itrepresentsanidealscenarioforusingaFactoryBeanimplementation.FactoryBeaninterface
definesthefollowingmethodsthatyouneedtoimplement:
·getObjectType:returnsthetypeoftheobjectmanagedbytheFactoryBeanimplementation.In
caseofMyBank,theFactoryBeanimplementationcreatesandreturnsobjectsoftypeEventSender.
·getObject:returnstheobjectmanagedbytheFactoryBeanimplementation.IncaseofMyBank,
the getObject method returns an instance of DatabaseEventSender or MessagingEventSender or
WebServiceEventSender.
· isSingleton:returnstrueiftheFactoryBean implementation is afactoryfor singleton-scoped
objects.IftheisSingletonmethodreturnstrue,theobjectreturnedbythegetObjectmethodiscached
bytheSpringcontainerandthesameinstanceisreturnedonsubsequentrequests.IftheFactoryBean
implementationisafactoryforprototype-scopedobjects,returnfalsefromtheisSingletonmethod.
IftheisSingletonmethod returns false, a fresh instance is created by getObject method on every
request. In case of MyBank, FactoryBean implementation returns an instance of
DatabaseEventSender or MessagingEventSender or WebServiceEventSender class. Once created,
the same instance is used throughout the lifetime of the MyBank application; therefore, the
isSingletonmethodreturnstrueincaseofMyBank.
ThefollowingexamplelistingshowstheEventSenderFactoryBean–theFactoryBeanimplementationthat
createsandreturnsobjectsoftypeEventSender:
Examplelisting3-56–EventSenderFactoryBeanclass
Project–ch03-bankapp-factorybean
Sourcelocation-src/main/java/sample/spring/chapter03/bankapp/event
packagesample.spring.chapter03.bankapp.event;
importorg.springframework.beans.factory.FactoryBean;
importorg.springframework.beans.factory.FactoryBeanNotInitializedException;
importorg.springframework.core.io.ClassPathResource;
.....
publicclassEventSenderFactoryBeanimplementsFactoryBean<EventSender>{
privateStringdatabasePropertiesFile;
privateStringwebServicePropertiesFile;
privateStringmessagingPropertiesFile;
.....
publicEventSendergetObject()throwsException{
EventSendereventSender=null;
Propertiesproperties=newProperties();
ClassPathResourcedatabaseProperties=null;
if(databasePropertiesFile!=null){
databaseProperties=newClassPathResource(databasePropertiesFile);
}
.....
if(databaseProperties!=null&&databaseProperties.exists()){
InputStreaminStream=databaseProperties.getInputStream();
properties.load(inStream);
eventSender=newDatabaseEventSender(properties);
}
elseif(webServiceProperties!=null&&webServiceProperties.exists()){.....}
elseif(messagingProperties!=null&&messagingProperties.exists()){.....}
returneventSender;
}
publicClass<?>getObjectType(){
returnEventSender.class;
}
publicbooleanisSingleton(){
returntrue;
}
}
The above example listing shows that the EventSenderFactoryBean implements FactoryBean interface.
The EventSender parameter in FactoryBean<EventSender> indicates that the FactoryBean’s getObject
returns objects of type EventSender. The databasePropertiesFile, webServicePropertiesFile and
messagingPropertiesFile are properties of the EventSenderFactoryBean class, and they represent the
locationofdatabase.properties,webservice.propertiesandmessaging.propertiesfilesintheclasspath.
ThegetObjectmethodusesSpring’sClassPathResourceclasstoverifywhetherthespecifiedproperties
file exists in the classpath or not. If the properties file exists, properties from that file are loaded and
passed as to the EventSender implementation class’s constructor. For instance, in the above example
listing,ifdatabase.propertiesfile(representedbydatabasePropertiesFileproperty)exists,propertiesare
loaded from the database.properties file and passed as an argument to the DatabaseEventSender’s
constructor.ThegetObjectTypemethodreturnsEventSendertypebecausetheEventSenderFactoryBean’s
getObjectmethodreturnsobjectsoftypeEventSender.TheisSingletonmethodreturnstrue,whichmeans
thattheobjectreturnedbygetObjectmethodiscachedbySpringandthesameinstanceisreturnedevery
timeEventSenderFactoryBean’sgetObjectmethodisinvoked.
Now, that you have seen how EventSenderFactoryBean class is implemented in the MyBank, you can
guesshowSpring’sbuilt-inFactoryBeanimplementations,likeListFactoryBean(forcreatinginstancesof
Listtype),MapFactoryBean(forcreatinginstancesofMaptype),SetFactoryBean(forcreatinginstances
ofSettype),andsoon,areimplemented.
The following example listing shows how EventSenderFactoryBean is configured in the application
contextXMLfile:
Examplelisting3-57–applicationContext.xml-EventSenderFactoryBeanconfiguration
Project–ch03-bankapp-factorybean
Sourcelocation-src/main/resources/META-INF/spring
<beans.....>
<beanid="service"
class="sample.spring.chapter03.bankapp.service.FixedDepositServiceImpl">
.....
<propertyname="eventSender"ref="eventSenderFactory"/>
</bean>
.....
<beanid="eventSenderFactory"
class="sample.spring.chapter03.bankapp.event.EventSenderFactoryBean">
<propertyname="databasePropertiesFile"value="META-INF/config/database.properties"/>
</bean>
</beans>
The above example listing shows thattheEventSenderFactoryBean is configured likeanyother Spring
bean.EventhoughaFactoryBeanimplementationisconfiguredlikeanyotherSpringbean,itistreated
differentlybytheSpringcontainer.Oneofthemostimportantdifferencesisthatifabeanisdependenton
a FactoryBean implementation, the Spring container invokes the getObject method of the FactoryBean
implementationandinjectsthereturnedobjectintothedependentbean.
NOTEYoushouldnotethatFactoryBean’sgetObjectmethodisinvokedonlyoncebytheSpring
containeriftheisSingletonmethodreturnstrue.
In the above example listing, bean definition for the FixedDepositServiceImpl class shows that it is
dependent on the EventSenderFactoryBean – a FactoryBean implementation. So, the Spring container
invokestheEventSenderFactoryBean’sgetObjectmethodandinjectsthereturnedEventSenderobjectinto
theFixedDepositServiceImplinstance.
The following example listing shows the FixedDepositServiceImpl class that requires EventSender
instancecreatedbyEventSenderFactoryBean:
Examplelisting3-58–FixedDepositServiceImplclass
Project–ch03-bankapp-factorybean
Sourcelocation-src/main/java/sample/spring/chapter03/bankapp/service
packagesample.spring.chapter03.bankapp.service;
importsample.spring.chapter03.bankapp.event.EventSender;
publicclassFixedDepositServiceImplimplementsFixedDepositService{
.....
privateEventSendereventSender;
publicvoidsetEventSender(EventSendereventSender){
this.eventSender=eventSender;
}
.....
publicvoidcreateFixedDeposit(FixedDepositDetailsfixedDepositDetails){
.....
eventSender.sendEvent(event);
}
}
The above example listing shows that the FixedDepositServiceImpl class depends on an EventSender
instanceandnotontheEventSenderFactoryBeaninstance.TheSpringcontainerobtainstheEventSender
instancebyinvokingEventSenderFactoryBean’sgetObjectmethod,andinjectstheobtainedEventSender
instanceintotheFixedDepositServiceImplinstance.
Let’snow lookathowto access theFactoryBean itself and not the bean it creates and returns via the
getObjectmethod.
AccessingtheFactoryBeaninstance
If you want to obtain the FactoryBean itself from the Spring container, prefix the name (or id) of the
factorybeanwithampersand‘&’.
Let’ssaythattheFixedDepositServiceImplclassrequiresaccesstotheEventSenderFactoryBeanitself,
asshownhere:
Example listing 3-59 – FixedDepositServiceImpl class that depends on the EventSenderFactoryBean
itself
packagesample.spring.chapter03.bankapp.service;
importsample.spring.chapter03.bankapp.event.EventSenderFactoryBean;
importsample.spring.chapter03.bankapp.event.EventSender;
publicclassFixedDepositServiceImplimplementsFixedDepositService{
.....
privateEventSenderFactoryBeaneventSenderFactoryBean;
publicvoidsetEventSenderFactoryBean(EventSenderFactoryBeaneventSenderFactoryBean){
this.eventSenderFactoryBean=eventSenderFactoryBean;
}
.....
publicvoidcreateFixedDeposit(FixedDepositDetailsfixedDepositDetails){
.....
EventSendereventSender=eventSenderFactoryBean.getObject();
evenSender.sendEvent(event);
}
}
Intheaboveexamplelisting,theFixedDepositServiceImplclassdependsontheEventSenderFactoryBean
itself,andusesitsgetObjectmethodtoobtainaninstanceofEventSenderobject.
Wesawinexamplelisting3-57thatwhenyoudefinetheEventSenderFactoryBeanbeanasadependency
of FixedDepositServiceImpl bean, the Spring container invokes the getObject method of
EventSenderFactoryBeanandinjectsthereturnedEventSenderobjectintotheFixedDepositServiceImpl
bean. To instruct the Spring container to inject the EventSenderFactoryBean itself, add ampersand ‘&’
prefixtotheid(orname)ofthebeanspecifiedbytherefattribute,asshowninthefollowingexample
listing:
Examplelisting3-60–InjectingtheEventSenderFactoryBeaninstanceintotheFixedDepositServiceImpl
bean
<beans.....>
<beanid="service"class="sample.spring.chapter03.bankapp.service.FixedDepositServiceImpl">
.....
<propertyname="eventSenderFactoryBean"ref="&eventSenderFactory"/>
</bean>
.....
<beanid="eventSenderFactory"
class="sample.spring.chapter03.bankapp.event.EventSenderFactoryBean">
<propertyname="databasePropertiesFile"value="META-INF/config/database.properties"/>
</bean>
</beans>
In the above example listing, the following <property> element specifies that the
FixedDepositServiceImplbeanisdependentonEventSenderFactoryBean:
<propertyname="eventSenderFactoryBean"ref="&eventSenderFactory"/>
Noticethattherefattribute’svalueis"&eventSenderFactory".The&prefixinstructstheSpring
containertoinjecttheEventSenderFactoryBeaninstanceitselfintotheFixedDepositServiceImplbean.
The use of ampersand ‘&’ is also required when you want to retrieve the FactoryBean instance itself
usingApplicationContext’sgetBeanmethod.ThefollowingexamplelistingshowstheBankAppclassof
MyBankapplicationthatretrievestheEventSenderobjectcreatedbytheEventSenderFactoryBean, and
theEventSenderFactoryBeaninstanceitself:
Examplelisting3-61–BankAppclass
Project–ch03-bankapp-factorybean
Sourcelocation-src/main/java/sample/spring/chapter03/bankapp
packagesample.spring.chapter03.bankapp;
.....
publicclassBankApp{
privatestaticLoggerlogger=Logger.getLogger(BankApp.class);
publicstaticvoidmain(Stringargs[]){
ApplicationContextcontext=newClassPathXmlApplicationContext(
.....
logger.info("InvokinggetBean(\"eventFactory\")returns:"+
context.getBean("eventSenderFactory"));
logger.info("InvokinggetBean(\"&eventFactory\")returns:"+
context.getBean("&eventSenderFactory"));
}
}
If you execute the main method of the BankApp class shown above, you’ll find that calling
getBean("eventSenderFactory") returns an instance of DatabaseEventSender class, and
getBean("&eventSenderFactory")returnsEventSenderFactoryBeaninstance.
3-10Summary
In this chapter, we saw how you can use bean definition inheritance to create less verbose and easily
manageablebeandefinitions.Themajorityofthischapterfocusedonhowtosetdifferenttypesofbean
properties andconstructorargumentsusingbuilt-inFactoryBeanimplementations,Spring’sutil schema,
and p- and c-namespaces. We also looked at some of the built-in PropertyEditor implementations in
SpringandhowtoregisteradditionalpropertyeditorswiththeSpringcontainer.Inthenextchapter,we’ll
takeanin-depthlookatdependencyinjectionfeatureofSpring.
Chapter4-Dependencyinjection
4-1Introduction
In the previous chapter, we looked at how to configure beans using Spring’s util schema, p- and c-
namespaces,FactoryBeanimplementations,andsoon.Inthischapterwefocusondifferentdependency
injectionscenarios which we typically come across inreal world application development efforts and
howSpringaddressesthesescenarios.
We’llbeginthischapterwithalookatinnerbeans-analternativetousingtherefattributeof<property>
and<constructor-arg> elements. We’ll then look at depends-on attribute of the <bean> element. In the
second half of this chapter, we’ll look at issues that may arise when singleton- and prototype-scoped
beans collaborate to provide application behavior. We’ll wrap this chapter with an in-depth look at
Spring’sautowiringfeature.
IMPORTchapter4/ch04-bankapp-dependencies(Thisprojectshowsusageofinnerbeansand<bean>
element’sdepends-onattribute.Thisprojectalsoshowsimplicationsofdefiningdependenceofsingleton-
scopedbeansonprototype-scopedbeans,andviceversa.Toruntheapplication,executethemainmethod
oftheBankAppclassofthisproject)
4-2Innerbeans
Ifadependencyofabeanisnotsharedbymultiplebeans,youcanconsiderdefiningthedependencyasan
inner bean. An inner bean is defined inside a <property> or <constructor-arg> element by using the
<bean>elementofSpring’sbeansschema.Youshouldnotethataninnerbeanisonlyaccessibletothe
beandefinitionenclosingit,andnottootherbeansregisteredwiththeSpringcontainer.
Thefollowingexamplelistingshowshowwegenerallyrepresentbeandependencies:
Examplelisting4-1–Dependencyspecifiedusing<property>element’srefattribute
<beanid="service"
class="sample.spring.chapter04.bankapp.service.FixedDepositServiceImpl">
<propertyname=“fixedDepositDao"ref="dao"/>
</bean>
<beanid="dao"class="sample.spring.chapter04.bankapp.dao.FixedDepositDaoImpl"/>
Theaboveexamplelistingshowsthattheservicebeanisdependentondaobean.Ifservicebeanisthe
onlybeanthatisdependentonthedaobean,thenyoucandefinethedaobeanasaninnerbeanofservice
bean.
Examplelisting4-2–applicationContext.xml-Innerbeanexample
Project–ch04-bankapp-dependencies
Sourcelocation-src/main/resources/META-INF/spring
<beanid="service"
class="sample.spring.chapter04.bankapp.service.FixedDepositServiceImpl">
<propertyname=“fixedDepositDao">
<beanclass="sample.spring.chapter04.bankapp.dao.FixedDepositDaoImpl"/>
</property>
</bean>
In the above example listing, the bean definition for the FixedDepositDaoImpl class is inside the
<property>elementofservicebean.Ifyoucomparetheaboveexamplelistingwith4-1,you’llnoticethat
the<property> element no longer specifies the ref attribute, and the <bean> element corresponding to
FixedDepositDaoImplclassdoesn’thavetheidattributeanymore.
The<bean>elementcorrespondingtoaninnerbeandefinitiondoesn’tspecifyanidattributebecausean
inner bean is not registered with the Spring container. If you specify an id attribute for an inner bean
definition,itisignoredbytheSpringcontainer.Aninnerbeanisalwaysprototype-scoped;therefore,if
the <bean> element corresponding to an inner bean definition specifies the scope attribute, then it is
ignoredbytheSpringcontainer.Itisimportanttonotethataninnerbeanisanonymousinnature,andit’s
not accessible to other beans (except the bean that contains the inner bean definition) in the Spring
container.
NOTEAsincaseofnormalbeandefinition,youcanuse<property>,<constructor-arg>,andsoon,
elementsinsidethe<bean>elementoftheinnerbeandefinition.
Inthepreviouschapter,wesawthatSpring’sutilschemaelementsareusedtocreatebeansthatrepresent
a List, Set, Map, and so on. We saw that the beans created by Spring’s util schema elements are
referenced by other beans. The concept of inner beans makes it possible to use Spring’s util schema
elements inside <property> and <constructor-arg> elements also, as shown in the following example
listing:
Examplelisting4-3–utilschema’s<list>elementdefinesaninnerbean
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation=".....http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<beanid="someBean"class="com.sample.SomeBean">
.....
<constructor-argname="listType">
<util:listlist-class="java.util.ArrayList">
<value>AsimpleStringvalueinlist</value>
<value>AnothersimpleStringvalueinlist</value>
</util:list>
</constructor-arg>
.....
</bean>
</beans>
Intheaboveexamplelisting,thelistTypeconstructorargumentisoftypejava.util.List.Thevaluepassed
tothelistTypeconstructorargumentisspecifiedbytheutilschema’s<list>element.Notethatwedidn’t
specifytheidattributeofthe<list>elementbecauseSpringcontainerignoresidsofinnerbeans.
Let’snowlookatdepends-onattributeof<bean>element.
4-3Explicitlycontrollingthebeaninitializationorderwithdepends-on
attribute
Insection1-4ofchapter1,wediscussedthatbeansarecreatedintheorderinwhichtheyaredefinedin
theapplicationcontextXMLfile.Theorderinwhichbeansarecreatedisalsodecidedbasedontheinter-
dependenciesofbeans.Forinstance,ifbeanAacceptsaninstanceofbeanBasaconstructorargument,
theSpringcontainerwillcreatebeanBbeforebeanAirrespectiveoftheorderinwhichtheyaredefined
intheapplicationcontextXMLfile.ThisbehavioroftheSpringcontainerensuresthatthedependencies
ofabean(beanBisadependencyinourexample)arecompletelyconfiguredbeforetheyareinjectedinto
thedependentbean(beanAisadependentbeaninourexample).
In some application scenarios, bean dependencies are not explicitly specified via <property> and
<constructor-arg> elements. If the bean dependencies are not explicit, you can use <bean> element’s
depends-on attribute to explicitly specify dependencies of a bean. Spring container ensures that bean
dependencies specified by the depends-on attribute are initialized before the bean that specifies the
depends-onattribute.
Let’snowlookatanexamplescenarioinwhichdepends-onattributeisusedtocontroltheinitialization
orderofbeans.
MyBank–implieddependenciesbetweenbeans
IntheMyBankapplicationofthepreviouschapter,aFactoryBeanimplementationcreatedanEventSender
objectthatwasusedbytheFixedDepositServiceImplinstancetodirectlyorindirectlystoreeventsinthe
database (refer section 3-9 of chapter 3 for details). Let’s say that instead of using a FactoryBean
implementation for creating an EventSender implementation, the approach shown in the following
diagramisadopted:
Figure4-1–EventSenderSelectorServiceImplclasswritesthenameoftheEventSenderimplementation
intheappConfig.propertiesfile,whichislaterreadbytheFixedDepositServiceImplinstance
Theabovediagramshowsthat:
·anEventSenderSelectorServiceImplclassisusedtodecideontheEventSenderimplementation
(DatabaseEventSender or WebServiceEventSender or MessagingEventSender) to be used by the
FixedDepositServiceImplclass
· EventSenderSelectorServiceImpl class stores the fully-qualified name of the EventSender
implementationintheappConfig.propertiesfile
· FixedDepositServiceImpl class reads the fully-qualified name of the EventSender
implementationfromtheappConfig.propertiesfile,createstheEventSenderobjectandusesitfor
storingfixeddepositeventsinthedatabase
The above approach suggests that the FixedDepositServiceImpl instance won’t work correctly if
EventSenderSelectorServiceImpl fails to save the fully-qualified name of the EventSender
implementation in the appConfig.properties file. This means that the FixedDepositServiceImpl class is
implicitlydependentontheEventSenderSelectorServiceImplclass.
Let’s now look at the implication of implicit dependence of FixedDepositServiceImpl instance on the
EventSenderSelectorServiceImplinstance.
Implicitdependencyproblem
Consider the following application context XML file that contains bean definitions for
FixedDepositServiceImplandEventSenderSelectorServiceImplclasses:
Examplelisting4-4–applicationContext.xml-Implicitdependencyexample
Project–ch04-bankapp-dependencies
Sourcelocation-src/main/resources/META-INF/spring
<beans.....>
<beanid="service"
class="sample.spring.chapter04.bankapp.service.FixedDepositServiceImpl">
.....
<constructor-argindex="0"value="META-INF/config/appConfig.properties"/>
</bean>
<beanid="eventSenderSelectorService"
class="sample.spring.chapter04.bankapp.service.EventSenderSelectorServiceImpl">
<constructor-argindex="0"value="META-INF/config/appConfig.properties"/>
</bean>
</beans>
The above application context XML file shows that both FixedDepositServiceImpl and
EventSenderSelectorServiceImplclass’sconstructoracceptlocationoftheappConfig.propertiesfile.The
EventSenderSelectorServiceImplinstanceusestheappConfig.propertiesfileforcommunicatingthefully-
qualifiednameoftheEventSenderimplementationclasstotheFixedDepositServiceImplinstance.Asan
explicit dependence doesn’t exist between service and eventSenderSelectorService beans, Spring
containercreates theirinstancesintheorder inwhich theyare defined intheapplicationcontextXML
file. As the service bean is defined before the eventSenderSelectorService bean,
FixedDepositServiceImplinstance is created before EventSenderSelectorServiceImpl instance. We’ll
soon see that if FixedDepositServiceImplinstance is created before EventSenderSelectorServiceImpl
instance,theFixedDepositServiceImplinstancewillnotbeabletoreadthenameofthefully-qualified
EventSenderimplementationclassfromtheappConfig.propertiesfile.
Let’s now take an in-depth look at the EventSenderSelectorServiceImpl and FixedDepositServiceImpl
classes,andtheappConfig.propertiesfile.
EventSenderSelectorServiceImpl–thewriter
ThefollowingexamplelistingshowstheEventSenderSelectorServiceImplclass:
Examplelisting4-5–EventSenderSelectorServiceImplclass
Project–ch04-bankapp-dependencies
Sourcelocation-src/main/java/sample/spring/chapter04/bankapp/service
packagesample.spring.chapter04.bankapp.service;
importorg.springframework.core.io.ClassPathResource;
importsample.spring.chapter04.bankapp.Constants;
publicclassEventSenderSelectorServiceImpl{
publicEventSenderSelectorServiceImpl(StringconfigFile)throwsException{
ClassPathResourceresource=newClassPathResource(configFile);
OutputStreamos=newFileOutputStream(resource.getFile());
Propertiesproperties=newProperties();
properties
.setProperty(Constants.EVENT_SENDER_CLASS_PROPERTY,
"sample.spring.chapter04.bankapp.event.DatabaseEventSender");
properties.store(os,null);
.....
}
}
TheaboveexamplelistingshowsthatthelocationofappConfig.propertiesfileispassedasaconstructor
argument to the EventSenderSelectorServiceImpl class’s constructor. The
EventSenderSelectorServiceImpl class’sconstructorwritesa property namedeventSenderClass (which
is the value of EVENT_SENDER_CLASS_PROPERTYconstant defined in the Constants class) to the
appConfig.properties file. The eventSenderClass property specifies the fully-qualified name of the
EventSender implementation to be used by the FixedDepositServiceImpl instance for directly or
indirectly saving events in the database. For the sake of simplicity, EventSenderSelectorServiceImpl
class’s constructor sets the fully-qualified name of the DatabaseEventSender class as the value of
eventSenderClassproperty.
appConfig.properties
The following is the entry that gets added to the appConfig.propertiesfile by
EventSenderSelectorServiceImplclass:
eventSenderClass=sample.spring.chapter04.bankapp.event.DatabaseEventSender
FixedDepositServiceImpl–thereader
The eventSenderClass property written by the EventSenderSelectorServiceImpl instance is read by the
FixedDepositServiceImplinstance,asshowninthefollowingexamplelisting:
Examplelisting4-6–FixedDepositServiceImplclass
Project–ch04-bankapp-dependencies
Sourcelocation-src/main/java/sample/spring/chapter04/bankapp/service
packagesample.spring.chapter04.bankapp.service;
importorg.springframework.core.io.ClassPathResource;
importsample.spring.chapter04.bankapp.Constants;
publicclassFixedDepositServiceImplimplementsFixedDepositService{
privateFixedDepositDaofixedDepositDao;
privateEventSendereventSender;
publicFixedDepositServiceImpl(StringconfigFile)throwsException{
ClassPathResourceconfigProperties=newClassPathResource(configFile);
if(configProperties.exists()){
InputStreaminStream=configProperties.getInputStream();
Propertiesproperties=newProperties();
properties.load(inStream);
StringeventSenderClassString=
properties.getProperty(Constants.EVENT_SENDER_CLASS_PROPERTY);
if(eventSenderClassString!=null){
Class<?>eventSenderClass=Class.forName(eventSenderClassString);
eventSender=(EventSender)eventSenderClass.newInstance();
logger.info("CreatedEventSenderclass");
}else{
logger.info("appConfig.propertiesfiledoesn'tcontaintheinformation"+
"aboutEventSenderclass");
}
}
}
publicvoidcreateFixedDeposit(FixedDepositDetailsfixedDepositDetails)throwsException{
.....
eventSender.sendEvent(event);
}
}
The above example listing shows following sequence of actions are performed by the constructor of
FixedDepositServiceImplclass:
· loads properties from the appConfig.properties file. The configFile constructor argument
representsthelocationoftheappConfig.propertiesfile.
· obtains property named eventSenderClass (represented by
EVENT_SENDER_CLASS_PROPERTY constant defined in the Constants class) from the
properties loaded fromtheappConfig.propertiesfile. The value of eventSenderClass property is
the fully-qualified name of the EventSender implementation class that FixedDepositServiceImpl
needstouse.ThevalueofeventSenderClasspropertyisstoredintheeventSenderClassStringlocal
variable.
· creates an instance of the EventSender implementation class whose fully-qualified name is
stored in the eventSenderClassString variable, and stores the newly created instance into an
instance variable named eventSender. The eventSender variable is later used by the
FixedDepositServiceImpl’screateFixedDepositmethod(refertothecreateFixedDepositmethodin
theaboveexamplelisting)todirectlyorindirectlystoreeventsinthedatabase.
YoushouldnotethatifapropertynamedeventSenderClassisnotfoundintheappConfig.propertiesfile,
theeventSenderClassStringvariableisnot set. In this case, the FixedDepositServiceImpl’s constructor
printsthefollowingmessageontheconsole:‘appConfig.propertiesfiledoesn'tcontaintheinformation
aboutEventSenderclass’.
In example listing 4-4, we looked at bean definitions for EventSenderSelectorServiceImpl and
FixedDepositServiceImplclasses, and concluded that the FixedDepositServiceImpl instance is created
beforeEventSenderSelectorServiceImplinstancebecauseSpringcontainerinitializesbeansintheorder
inwhichtheyappearintheapplicationcontextXMLfile.Wesawinexamplelisting4-5thatthecreation
of EventSenderSelectorServiceImpl instance results in writing an eventSenderClass property to the
appConfig.properties file. So, if the FixedDepositServiceImpl instance is created before the
EventSenderSelectorServiceImpl instance, the FixedDepositServiceImpl instance will not find any
eventSenderClasspropertyintheappConfig.propertiesfile.ThisshowsthattheFixedDepositServiceImpl
class is implicitly dependent on the EventSenderSelectorServiceImpl class; therefore, the
EventSenderSelectorServiceImplinstancemustbecreatedbeforetheFixedDepositServiceImplinstance.
Howtoaddressimplicitdependencyproblem?
Wecansolvetheimplicitdependencyproblemintwoways:
· we change the order in which bean definitions for EventSenderSelectorServiceImpl and
FixedDepositServiceImpl classes are defined in the application context XML file. If the bean
definitionfortheEventSenderSelectorServiceImplclassappearsbeforethebeandefinitionforthe
FixedDepositServiceImpl class, the EventSenderSelectorServiceImpl instance will be created
beforetheFixedDepositServiceImplinstance.
· use <bean> element’s depends-on attribute to explicitly specify that the service bean
(corresponding to the FixedDepositServiceImpl class) is dependent on the
eventSenderSelectorServicebean(correspondingtotheEventSenderSelectorServiceImplclass).
Thefollowingexamplelistingshowstheusageof<bean>element’sdepends-onattribute:
Examplelisting4-7–<bean>element’sdepends-onattribute
<beans.....>
<beanid="service"
class="sample.spring.chapter04.bankapp.service.FixedDepositServiceImpl"
depends-on="eventSenderSelectorService">
.....
</bean>
<beanid="eventSenderSelectorService"
class="sample.spring.chapter04.bankapp.service.EventSenderSelectorServiceImpl">
.....
</bean>
</beans>
In the above example listing, the service bean uses depends-on attribute to explicitly specify that it is
dependentontheeventSenderSelectorServicebean.Thedepends-onattributespecifiestheidsornames
of the beans on which the bean is dependent. As the service bean specifies that it is dependent on the
eventSenderSelectorService bean, Spring container creates eventSenderSelectorService bean
(corresponding to the EventSenderSelectorServiceImpl class) instance before service bean
(correspondingtotheFixedDepositServiceImplclass)instance.
NOTE If you execute the main method of the BankApp class of ch04-bankapp-dependencies project,
you’ll find that the FixedDepositServiceImpl instance is created before EventSenderSelectServiceImpl
instance. For this reason, the following message is printed on the console: ‘appConfig.properties file
doesn'tcontaintheinformationaboutEventSenderclass’.
Multipleimplicitdependencies
Ifabeanhasmultipleimplicitdependencies,youcanspecifyidsornamesofallthosedependenciesas
thevalueofdepends-onattribute,asshownhere:
Examplelisting4-8–depends-onattributeexample-multipleimplicitdependencies
<beans.....>
<beanid="abean".....depends-on="bBean,cBean">
.....
</bean>
.....
</beans>
Theaboveexamplelistingshowsthatyoucanspecifymultiplebeanidsornamesasthevalueofdepends-
onattribute.
depends-onattributeandbeandefinitioninheritance
It is important to note that the depends-on attribute is not inherited by child bean definitions. The
following example listing shows an abstract serviceTemplate parent bean definition that uses the
depends-onattributetospecifybaseServicebeanasadependency:
Examplelisting4-9–depends-onattribute–beandefinitioninheritance
<beanid="serviceTemplate"class=".....ServiceTemplate"depends-on="baseService"
abstract="true"/>
<beanid="someService"class=".....SomeServiceImpl"parent="serviceTemplate"/>
<beanid="someOtherService"class=".....SomeOtherServiceImpl"parent="serviceTemplate"/>
<beanid="baseService"class=".....BaseServiceImpl"/>
Intheaboveexamplelisting,someServiceandsomeOtherServicechildbeandefinitionsdon’tinheritthe
depends-on attribute from the serviceTemplate parent bean definition. As the Spring container creates
beansintheorderinwhichtheyaredefinedintheapplicationcontextXMLfile,thebaseServicebeanis
createdafterthecreationofsomeServiceandsomeOtherServicebeans.
Let’s now look at how the Spring container manages dependencies of singleton- and prototype-scoped
beans.
4-4Singleton-andprototype-scopedbean’sdependencies
Asingleton-scopedbean(anditssingleton-scopeddependencies)iscreatedwhentheApplicationContext
instance is created. And, a prototype-scoped bean (and its prototype-scoped dependencies) is created
eachtimeApplicationContext’sgetBeanmethodisinvokedtoobtaintheprototype-scopedbean.
If a singleton-scoped bean is dependent on a prototype-scoped bean, or vice versa, things get a bit
complicated.Forinstance,ifasingleton-scopedbeanisdependentonaprototype-scopedbean,youmight
ask the question whether the Spring container will create the prototype-scoped bean (the dependency)
beforethesingleton-scopedbean(thedependentbean)?ortheSpringcontainerwillcreateandinjectthe
prototype-scopedbeaninstanceonlywhenyoucalltheApplicationContext’sgetBeanmethodtoretrieve
the singleton-scoped bean instance? The answers to these questions lies in the way singleton- and
prototype-scopeddependenciesofabeanaremanagedbytheSpringcontainer,asexplainednext.
Singleton-scopedbean’sdependencies
The following example listing shows the singleton-scoped customerRequestService bean of MyBank
application,anditsdependencies:
Examplelisting4-10–applicationContext.xml-DependenciesofcustomerRequestServicebean
Project–ch04-bankapp-dependencies
Sourcelocation-src/main/resources/META-INF/spring
<beanid="customerRequestService"
class="sample.spring.chapter04.bankapp.service.CustomerRequestServiceImpl">
<constructor-argname="customerRequestDetails"ref="customerRequestDetails"/>
<constructor-argname="customerRequestDao"ref="customerRequestDao"/>
</bean>
<beanid="customerRequestDetails"
class="sample.spring.chapter04.bankapp.domain.CustomerRequestDetails"
scope="prototype"/>
<beanid="customerRequestDao"
class="sample.spring.chapter04.bankapp.dao.CustomerRequestDaoImpl"/>
TheaboveexamplelistingshowsthatthecustomerRequestService (singleton-scoped)beandepends on
customerRequestDetails (prototype-scoped) and customerRequestDao (singleton-scoped) beans.
CustomerRequestServiceobject(representedbythecustomerRequestServicebean)representsaservice
that is invoked when a bank customer creates a new request, like a cheque book request.
CustomerRequestServiceputsthedetailsofthecustomerrequestintoaCustomerRequestDetails object
(represented by the customerRequestDetails bean) and saves it in the data store using
CustomerRequestDaoobject(representedbythecustomerRequestDaobean).
ThefollowingexamplelistingshowsthemainmethodofBankAppclassthatloadsthebeandefinitions
showninexamplelisting4-10:
Examplelisting4-11–BankAppclass
Project–ch04-bankapp-dependencies
Sourcelocation-src/main/java/sample/spring/chapter04/bankapp
packagesample.spring.chapter04.bankapp;
importorg.springframework.context.ApplicationContext;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
publicclassBankApp{
privatestaticLoggerlogger=Logger.getLogger(BankApp.class);
publicstaticvoidmain(Stringargs[])throwsException{
ApplicationContextcontext=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
.....
logger.info("BeginningwithaccessingCustomerRequestService");
CustomerRequestServicecustomerRequestService_1
=context.getBean(CustomerRequestService.class);
.....
CustomerRequestServicecustomerRequestService_2
=context.getBean(CustomerRequestService.class);
.....
logger.info("DonewithaccessingCustomerRequestService");
}
}
The above example listing shows that after the ApplicationContext instance is created,
ApplicationContext’sgetBeanmethodisinvokedtwicetoobtainreferencetothecustomerRequestService
bean.
IfyouexecutethemainmethodoftheBankAppclass,you’llseethefollowingoutput:
CreatedCustomerRequestDetailsinstance
CreatedCustomerRequestDaoImplinstance
CreatedCustomerRequestServiceImplinstance
.....
BeginningwithaccessingCustomerRequestService
DonewithaccessingCustomerRequestService
The‘Created.....’messagesshownintheaboveoutputareprintedbytheconstructorsoftherespective
bean classes. The above output shows that the customerRequestDetails (prototype-scoped) and
customerRequestDao(singleton-scoped)dependenciesofthecustomerRequestService(singleton-scoped)
bean are created and injected into the customerRequestService instance when the Spring container is
created.Asno‘Created.....’message was printed on the console between‘Beginning.....’ and ‘Done
.....’ messages, no bean instances were created by the Spring container when ApplicationContext’s
getBeanmethodwasinvokedtoretrievethecustomerRequestServicebean.
Figure4-2showsthesequencediagramthatdepictsthesequenceofeventsthatoccurwhenBankApp’s
main method (refer example listing 4-11) is executed. Figure 4-2 shows that when Spring container is
created, the customerRequestDetails (prototype-scoped) and customerRequestDao (singleton-scoped)
beansarefirstcreated,followedbycreationofcustomerRequestService(singleton-scoped).Constructor-
based DI is used to inject the customerRequestDetails and customerRequestDao beans into the
customerRequestServicebean.Asasingleton-scopedbeaniscreatedonlyoncebytheSpringcontainer,
theSpringcontainerhasonlyoneopportunitytoinjectcustomerRequestServicebean’sdependencies.For
thisreason,theSpringcontainerinjectsprototype-scopedcustomerRequestDetailsbeaninstanceintothe
customerRequestService bean only once. The implication of this behavior is that the
customerRequestServicebeanendsupholdingreferencetothesamecustomerRequestDetailsbeanduring
itslifetime.
Figure 4-2 - The sequence of events that occur when the Spring container is created and the
customerRequestServicebeanisretrievedfromtheSpringcontainer
It is important to note that even if setter-based DI was used to inject the prototype-scoped
customerRequestDetails dependency of the customerRequestService bean, the Spring container would
have called the setter method onlyonce during the lifetime of the customerRequestService bean. This
meansthatirrespectiveofwhethersetter-orconstructor-basedDIisused,asingletonbeaniscreatedand
configuredonlyonceduringit’slifetime.
Now,oncetheSpringcontaineriscreated,anyrequestforthesingleton-scopedcustomerRequestService
beanreturnsthesamecachedinstanceofthecustomerRequestServicebean.Forthisreason,no‘Created
.....’messagewaswrittenouttotheconsolebetween‘Beginning.....’and‘Done.....’messageswhenwe
executedBankApp’smainmethod(referexamplelisting4-11).
As the singleton-scoped customerRequestService bean always holds reference to the same prototype-
scopedcustomerRequestDetailsbean, itmay adversely affectthe behavior ofMyBank application.For
instance, if multiple customers simultaneously submit request to the CustomerRequestServiceImpl
instance,alltherequestswillresultinmodifyingthesameinstanceoftheCustomerRequestDetailsobject
heldbytheCustomerRequestService.Ideally,CustomerRequestServiceImplshouldcreateanewinstance
ofCustomerRequestDetailsobjectoneveryrequest.Insection4-5,we’llseewhatmodificationsweneed
tomaketothebeanclassofasingleton-scopedbeansothatitcanretrieveanewinstanceofaprototype-
scopedbeanoneverymethodcall.
Let’snowlookathowtheSpringcontainermanagesprototype-andsingleton-scopeddependenciesofa
prototype-scopedbean.
Prototype-scopedbean’sdependencies
In MyBank, a customer registers with the MyBank application by following a sequence of steps. For
instance, a customer first enters personal information and his account details, and if the MyBank
application finds a matching record, the customer is asked for his debit card details. The
CustomerRegistrationServiceImplclassofMyBankapplicationcontainsthenecessarybusinesslogicto
registercustomers.AsthecustomersfollowasequenceofstepstoregisterwiththeMyBankapplication,
theCustomerRegistrationServiceImplobjectmaintainsconversationalstatebetweenmethodcalls.
The following example listing shows the prototype-scoped customerRegistrationService bean
(representingtheCustomerRegistrationServiceImplclass)ofMyBankapplication,anditsdependencies:
Examplelisting4-12–applicationContext.xml-customerRegistrationServicebeananditsdependencies
Project–ch04-bankapp-dependencies
Sourcelocation-src/main/resources/META-INF/spring
<beanid="customerRegistrationService"
class="sample.spring.chapter04.bankapp.service.CustomerRegistrationServiceImpl"
scope="prototype">
<constructor-argname="customerRegistrationDetails"ref="customerRegistrationDetails"/>
<constructor-argname="customerRegistrationDao"ref="customerRegistrationDao"/>
</bean>
<beanid="customerRegistrationDetails"
class="sample.spring.chapter04.bankapp.domain.CustomerRegistrationDetails"
scope="prototype"/>
<beanid="customerRegistrationDao"
class="sample.spring.chapter04.bankapp.dao.CustomerRegistrationDaoImpl"/>
TheaboveexamplelistingshowsthatthecustomerRegistrationService(prototype-scoped)beandepends
on customerRegistrationDetails (prototype-scoped) and customerRegistrationDao (singleton-scoped)
beans.
CustomerRegistrationServiceImpl instance maintains progress of the registration process, and stores
information provided by the customer during the registration process in a CustomerRegistrationDetails
object(representedbythecustomerRegistrationDetailsbean).AsbothCustomerRegistrationServiceImpl
and CustomerRegistrationDetails objects are stateful in nature, both customerRegistrationService and
customerRegistrationDetailsbeansaredefinedasprototype-scopedbeans.
ThefollowingexamplelistingshowsthemainmethodofBankAppclassthatloadscustomerregistration
relatedbeans(referexamplelisting4-12)andperformsregistrationsfor2customers:
Examplelisting4-13–BankAppclass
Project–ch04-bankapp-dependencies
Sourcelocation-src/main/java/sample/spring/chapter04/bankapp
packagesample.spring.chapter04.bankapp;
importorg.springframework.context.ApplicationContext;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
publicclassBankApp{
privatestaticLoggerlogger=Logger.getLogger(BankApp.class);
publicstaticvoidmain(Stringargs[])throwsException{
ApplicationContextcontext=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
.....
logger.info("BeginningwithaccessingCustomerRegistrationService");
CustomerRegistrationServicecustomerRegistrationService_1=context
.getBean(CustomerRegistrationService.class);
customerRegistrationService_1.setAccountNumber("account_1");
customerRegistrationService_1.setAddress("address_1");
customerRegistrationService_1.setDebitCardNumber("debitCardNumber_1");
customerRegistrationService_1.register();
logger.info("registeredcustomerwithidaccount_1");
CustomerRegistrationServicecustomerRegistrationService_2=context
.getBean(CustomerRegistrationService.class);
.....
logger.info("registeredcustomerwithidaccount_2");
logger.info("DonewithaccessingCustomerRegistrationService");
}
}
The above example listing shows that the BankApp’smain method calls ApplicationContext’s getBean
method twice to obtain reference to customerRegistrationService bean. Once the
customerRegistrationService bean instance is retrieved, the setAccountNumber, setAddress,
setDebitCardNumber and register methods are invoked on it. If you execute BankApp’s main method,
you’llseethefollowingoutputontheconsole:
CreatedCustomerRegistrationDaoImplinstance
.....
BeginningwithaccessingCustomerRegistrationService
CreatedCustomerRegistrationDetailsinstance
CreatedCustomerRegistrationServiceImplinstance
registeredcustomerwithidaccount_1
CreatedCustomerRegistrationDetailsinstance
CreatedCustomerRegistrationServiceImplinstance
registeredcustomerwithidaccount_2
DonewithaccessingCustomerRegistrationService
The‘Created.....’messagesshownintheaboveoutputareprintedbytheconstructorsoftherespective
bean classes. The above output shows that the singleton-scoped customerRegistrationDao bean
(representingtheCustomerRegistrationDaoImplclass)iscreatedonlyoncewhentheApplicationContext
instance is created. The ‘Created.....’ messages between ‘Beginning.....’ and ‘Done.....’ messages
indicatethateachtimeApplicationContext’sgetBeanmethod isinvokedto obtaintheprototype-scoped
customerRegistrationService bean, a new instance of the customerRegistrationService bean and its
prototype-scopeddependency(thecustomerRegistrationDetailsbean)iscreatedbytheSpringcontainer.
Figure4-3showsthesequencediagramthatdepictsthesequenceofeventsthatoccurwhenBankApp’s
main method (refer example listing 4-13) is executed. The figure shows that the singleton-scoped
customerRegistrationDaobeaniscreatedonlyoncewhenApplicationContextinstanceiscreated.When
theprototype-scopedcustomerRegistrationServicebeanisrequestedfromtheSpringcontainer,theSpring
container first creates an instance of customerRegistrationDetails bean (which is the prototype-scoped
dependency of the customerRegistrationService bean), followed by the creation of the
customerRegistrationServicebean.Thisshowsthatifaprototype-scopedbeanXisdependentonanother
prototype-scopedbeanY,SpringcontainerwillcreateanewinstanceofXandYeachtimeyourequest
beanXfromtheSpringcontainer.
Figure 4-3 – The sequence of events that occur when the Spring container is created and the
customerRegistrationServicebeanisretrievedfromtheSpringcontainer
Earlierinthissection,wesawthatifasingleton-scopedbeanisdependentonaprototype-scopedbean,
then throughout its lifetime the singleton-scoped bean is associated with the same instance of the
prototype-scopedbean.Let’snowlookatdifferentwaysinwhichasingleton-scopedbeancanretrievea
newinstanceofaprototype-scopedbeanfromtheSpringcontainer.
4-5Obtainingnewinstancesofprototypebeansinsidesingletonbeans
In the previous section, we saw that the prototype-scoped dependency of a singleton-scoped bean is
injectedatthetimeofcreationofthesingleton-scopedbean(referfigure4-2).Springcontainercreates
instanceofasingleton-scopedbeanonlyonce;therefore,thesingleton-scopedbeanholdsreferencetothe
sameprototype-scopedbeaninstanceduringitslifetime.Asingleton-scopedbean’smethodscanretrieve
a new instance of their prototype-scoped dependency from the Spring container using any one of the
followingapproaches:
·makethesingleton-scopedbean’sclassimplementSpring’sApplicationContextAwareinterface
·usethe<lookup-method>elementofSpring’sbeansschema
·usethe<replaced-method>elementofSpring’sbeansschema
NOTEItispossibletousethenewkeywordtocreateaninstanceoftheprototype-scopedbean’sclassin
asingleton-scopedbean’smethodanduseit.Astheresponsibilityofcreatingabeaninstanceiswiththe
Springcontainer,weshouldnotattempttodirectlycreateabeaninstanceusingthenewkeyword.
IMPORTchapter4/ch04-bankapp-context-aware(Thisprojectshowsascenarioinwhichasingleton-
scopedbeanimplementsSpring’sApplicationContextAwareinterfacetoobtaininstancesofaprototype-
scopedbeanfromtheSpringcontainer.Toruntheapplication,executethemainmethodoftheBankApp
classofthisproject)
Let’sfirstbeginbylookingattheApplicationContextAwareinterface.
ApplicationContextAwareinterface
Spring’s ApplicationContextAware interface is implemented by beans that require access to the
ApplicationContext instance in which they are running. ApplicationContextAware interface defines a
single method, setApplicationContext, which provides the implementing beans with an instance of the
ApplicationContextobject.
ApplicationContextAwareinterfaceisalifecycleinterface,whichmeansthattheSpringcontainercalls
thebeansimplementingtheApplicationContextAwareinterfaceatappropriatetimesduringtheirlifetime.
Forinstance,ApplicationContextAware’ssetApplicationContextmethodiscalledbytheSpringcontainer
afterthebeaninstanceiscreatedbutbeforethebeaninstanceiscompletelyinitialized.Abeaninstanceis
consideredcompletelyinitializedonlyafteritsinitializationmethod(refersection5-2ofchapter5)is
calledbytheSpringcontainer.Itisimportanttonotethatafterabeaninstanceiscompletelyinitialized,it
is injected into the dependent bean instances by the Spring container. In chapter 5, we’ll look at some
morelifecycleinterfacesinSpring.
AbeanthatimplementstheApplicationContextAwareinterfacecanaccessotherbeansregisteredwiththe
ApplicationContextinstancebycallingApplicationContext’sgetBeanmethod.Thismeansthatifthebean
class of a singleton-scoped bean implements ApplicationContextAware interface, it can fetch a new
instanceofaprototype-scopedbeanfromtheSpringcontainerbycallingApplicationContext’sgetBean
method.Asthesingleton-scopedbeanexplicitlyobtainsitsprototype-scopeddependencyfromtheSpring
containerbycallingApplicationContext’sgetBeanmethod,youdon’tneedtodefinetheprototype-scoped
beanasadependencyofthesingleton-scopedbeanintheapplicationcontextXMLfile.
ThefollowingexamplelistingshowstheCustomerRequestServiceImplclassthatneedsanewinstanceof
CustomerRequestDetails object each time CustomerRequestServiceImpl’s submitRequest method is
called:
Examplelisting4-14–CustomerRequestServiceImplclass
Project–ch04-bankapp-context-aware
Sourcelocation-src/main/java/sample/spring/chapter04/bankapp/service
packagesample.spring.chapter04.bankapp.service;
importsample.spring.chapter04.bankapp.dao.CustomerRequestDao;
importsample.spring.chapter04.bankapp.domain.CustomerRequestDetails;
publicclassCustomerRequestServiceImplimplementsCustomerRequestService{
privateCustomerRequestDetailscustomerRequestDetails;
privateCustomerRequestDaocustomerRequestDao;
@ConstructorProperties({"customerRequestDetails","customerRequestDao"})
publicCustomerRequestServiceImpl(CustomerRequestDetailscustomerRequestDetails,
CustomerRequestDaocustomerRequestDao){
this.customerRequestDetails=customerRequestDetails;
this.customerRequestDao=customerRequestDao;
}
publicvoidsubmitRequest(StringrequestType,StringrequestDescription){
//--populateCustomerRequestDetailsobjectandsaveit
customerRequestDetails.setType(requestType);
customerRequestDetails.setDescription(requestDescription);
customerRequestDao.submitRequest(customerRequestDetails);
}
}
TheaboveexamplelistingshowsthattheCustomerRequestDetailsandCustomerRequestDaoobjectsare
passedasargumentstotheCustomerRequestServiceImplclass’sconstructor.ThesubmitRequestmethod
populates the CustomerRequestDetails instance and saves it into the database by calling
CustomerRequestDao’ssubmitRequest method.Ifmultiplecustomers simultaneouslysubmitrequest, the
submitRequest method will end up modifying the same instance of the CustomerRequestDetails object,
resulting in undesired behavior of MyBank application. To address this issue, the submitRequest must
obtainanewinstanceoftheCustomerRequestDetailsobjectfromtheSpringcontaineroneachinvocation.
The following example listing shows the CustomerRequestServiceContextAwareImpl class (a modified
versionofCustomerRequestServiceImplclassthatwesawinexamplelisting4-14)thatimplementsthe
ApplicationContextAwareinterface:
Example listing 4-15 – CustomerRequestServiceContextAwareImpl class that implements Spring’s
ApplicationContextAwareinterface
Project–ch04-bankapp-context-aware
Sourcelocation-src/main/java/sample/spring/chapter04/bankapp/service
packagesample.spring.chapter04.bankapp.service;
importorg.springframework.context.ApplicationContext;
importorg.springframework.context.ApplicationContextAware;
publicclassCustomerRequestServiceContextAwareImplimplements
CustomerRequestService,ApplicationContextAware{
privateCustomerRequestDaocustomerRequestDao;
privateApplicationContextapplicationContext;
@ConstructorProperties({"customerRequestDao"})
publicCustomerRequestServiceContextAwareImpl(CustomerRequestDaocustomerRequestDao)
{
this.customerRequestDao=customerRequestDao;
}
publicvoidsetApplicationContext(ApplicationContextapplicationContext)
throwsBeansException{
this.applicationContext=applicationContext;
}
publicvoidsubmitRequest(StringrequestType,StringrequestDescription){
CustomerRequestDetailscustomerRequestDetails=applicationContext
.getBean(CustomerRequestDetails.class);
customerRequestDetails.setType(requestType);
customerRequestDetails.setDescription(requestDescription);
customerRequestDao.submitRequest(customerRequestDetails);
}
}
In the above example listing, setApplicationContext method provides
CustomerRequestServiceContextAwareImpl with an instance of ApplicationContext object. The
ApplicationContext instance is later used by the submitRequest method to obtain an instance of
CustomerRequestDetailsobjectfromtheSpringcontainer.
As the CustomerRequestServiceContextAwareImpl class explicitly obtains CustomerRequestDetails
object from the Spring container, you don’t need to use Spring’s DI mechanism to inject
CustomerRequestDetails instance intotheCustomerRequestServiceContextAwareImpl instance. For this
reason, CustomerRequestServiceContextAwareImpl class’s constructor (refer example listing 4-15)
doesn’tspecifyCustomerRequestDetailsobjectasanargument.Ifyounowgotoch04-bankapp-context-
awareprojectandexecuteBankApp’smainmethod,you’llfindthatoneachinvocationofsubmitRequest
methodanewinstanceofCustomerRequestDetailsobjectisfetchedfromtheSpringcontainer.
InthecontextofMyBank,wesawthattheApplicationContextAwareinterfaceisusefulifabeanrequires
access to other beans. The downside of implementing the ApplicationContextAware interface is that it
couples your bean class to Spring Framework. You can avoid coupling your bean classes with Spring
FrameworkandstillaccessotherbeansfromtheSpringcontainerbyusingmethodinjectiontechniques
offeredby<lookup-method>and<replaced-method>elementsofSpring’sbeansschema.
Let’sfirstlookatthe<lookup-method>element.
IMPORT chapter 4/ch04-bankapp-lookup-method (This project shows the MyBank application that
uses<lookup-method>elementofSpring’sbeansschema.Toruntheapplication,executethemainmethod
oftheBankAppclassofthisproject)
<lookup-method>element
Ifabeanclassdefinesabeanlookupmethodwhosereturntyperepresentsabean,the<lookup-method>
element instructs the Spring container to provide implementation for this method. The method
implementationprovidedbytheSpringcontainerisresponsibleforretrievingthebeaninstancefromthe
Springcontainerandreturningit.
The <lookup-method> element’s bean attribute specifies the name of the bean to be looked-up and
returnedbythemethodimplementation,andthenameattribute specifies the nameof themethodwhose
implementation is to be provided by the Spring container. It is important to note that the bean lookup
methoddefinedbythebeanclasscanbeanabstractoraconcretemethod.
NOTETheuseof<lookup-method>elementtoinstructtheSpringcontainertoprovideimplementation
forabeanlookupmethodisreferredtoasa‘MethodInjectiontechinique’becausethe<lookup-method>
elementinjectsabeanlookupmethodimplementationintothebeanclass.
The following example listing shows CustomerRequestServiceImpl’s getCustomerRequestDetails
abstractmethodthatreturnsaninstanceofCustomerRequestDetailsinstance:
Examplelisting4-16–CustomerRequestServiceImplclass–definingabeanlookupmethod
Project–ch04-bankapp-lookup-method
Sourcelocation-src/main/java/sample/spring/chapter04/bankapp/service
packagesample.spring.chapter04.bankapp.service;
publicabstractclassCustomerRequestServiceImplimplementsCustomerRequestService{
privateCustomerRequestDaocustomerRequestDao;
@ConstructorProperties({"customerRequestDao"})
publicCustomerRequestServiceImpl(CustomerRequestDaocustomerRequestDao){
this.customerRequestDao=customerRequestDao;
}
publicabstractCustomerRequestDetailsgetCustomerRequestDetails();
@Override
publicvoidsubmitRequest(StringrequestType,StringrequestDescription){
//--populateCustomerRequestDetailsobjectandsaveit
CustomerRequestDetailscustomerRequestDetails=getCustomerRequestDetails();
.....
}
}
The above example listing shows that the CustomerRequestServiceImpl class is defined as abstract
becauseitcontainsanabstractbeanlookupmethod,getCustomerRequestDetails.Insteadofabstract,we
could have very well defined the getCustomerRequestDetails method as a concrete method. The
submitRequest method invokes the getCustomerRequestDetails method to access a
CustomerRequestDetailsinstance.
The following example listing shows bean definitions for CustomerRequestServiceImpl and
CustomerRequestDetailsclasses:
Examplelisting4-17–applicationContext.xml-<lookup-method>elementusage
Project–ch04-bankapp-lookup-method
Sourcelocation-src/main/resources/META-INF/spring
<beanid="customerRequestService"
class="sample.spring.chapter04.bankapp.service.CustomerRequestServiceImpl">
<constructor-argname="customerRequestDao"ref="customerRequestDao"/>
<lookup-methodbean="customerRequestDetails"name="getCustomerRequestDetails"/>
</bean>
<beanid="customerRequestDetails"
class="sample.spring.chapter04.bankapp.domain.CustomerRequestDetails"
scope="prototype"/>
The above example listing shows that the bean definition for the CustomerRequestServiceImpl class
contains a <lookup-method> element. The value of <lookup-method> element’s name attribute is
getCustomerRequestDetails, which instructs the Spring container to provide implementation for the
getCustomerRequestDetailslookupmethod(referexamplelisting4-16)ofCustomerRequestServiceImpl
class.Thevalueof<lookup-method> element’s beanattributeiscustomerRequestDetails, which means
that the implementation of getCustomerRequestDetails method retrieves a bean with id (or name) as
customerRequestDetails from the Spring container and returns it to the calling method. As the
customerRequestDetails bean represents a CustomerRequestDetails object (refer to the
customerRequestDetails bean definition in example listing 4-17), the implementation of
getCustomerRequestDetailsmethodreturnsaCustomerRequestDetailsobject.
In example listing 4-16, the CustomerRequestService’s submitRequest method invokes the
getCustomerRequestDetails bean lookup method to obtain a CustomerRequestDetails instance. As
CustomerRequestDetailsclassisrepresentedasaprototype-scopedbeanintheapplicationcontextXML
file (refer example listing4-17), each invocation of thesubmitRequest methodresultsin retrieval ofa
newinstanceofCustomerRequestDetailsobjectfromtheSpringcontainer.
To check that the <lookup-method> element provides correct implementation for the
CustomerRequestService’s getCustomerRequestDetails bean lookup method, the main method of
BankAppclassobtainsaninstanceofCustomerRequestServicefromtheSpringcontainerandinvokesits
submitRequestmethodmultipletimes.IfeachinvocationofthesubmitRequestmethodresultsinretrieval
of a fresh instance of CustomerRequestDetails object from the Spring container, then it means that the
<lookup-method> element provides correct implementation for the CustomerRequestService’s
getCustomerRequestDetailsmethod.
ThefollowingexamplelistingshowstheBankApp’smainmethodthatinvokesCustomerRequestService’s
submitRequestmethodmultipletimes:
Examplelisting4-18–BankAppclass
Project–ch04-bankapp-lookup-method
Sourcelocation-src/main/java/sample/spring/chapter04/bankapp
packagesample.spring.chapter04.bankapp;
.....
publicclassBankApp{
privatestaticLoggerlogger=Logger.getLogger(BankApp.class);
publicstaticvoidmain(Stringargs[])throwsException{
ApplicationContextcontext=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
.....
logger.info("BeginningwithaccessingCustomerRequestService");
CustomerRequestServicecustomerRequestService_1=context
.getBean(CustomerRequestService.class);
customerRequestService_1.submitRequest("checkBookRequest",
"Requesttosenda50-leafcheckbook");
customerRequestService_1.submitRequest("checkBookRequest",
"Requesttosenda100-leafcheckbook");
.....
logger.info("DonewithaccessingCustomerRequestService");
}
}
IfyouexecutetheBankApp’smainmethod,you’llseethefollowingoutputontheconsole:
BeginningwithaccessingCustomerRequestService
CreatedCustomerRequestDetailsinstance
CreatedCustomerRequestDetailsinstance
.....
DonewithaccessingCustomerRequestService
The‘Created.....’messagesshownintheaboveoutputareprintedbytheconstructorsoftherespective
beanclasses.TheaboveoutputshowsthateachinvocationofCustomerRequestService’ssubmitRequest
methodresultedinretrievalofanewCustomerRequestDetailsinstancefromtheSpringcontainer.
AstheimplementationofthebeanlookupmethodisprovidedbytheSpringcontainer,somerestrictions
applytothesignatureofthebeanlookupmethods.Forinstance,thebeanlookupmethodmustbedefined
aspublicorprotected,anditmustnotacceptanyarguments.Asthebeanclasscontainingthebeanlookup
methodissubclassedatruntimebytheSpringcontainertoprovidetheimplementationforthebeanlookup
method,thebeanclassandthebeanlookupmethodmustnotbedefinedasfinal.
NOTE As the bean class containing the bean lookup method needs to be subclassed at runtime by the
Springcontainertoprovideimplementationforthebeanlookupmethod,theSpringcontainerusesCGLIB
(http://cglib.sourceforge.net/)librarytoperformsubclassingofthebeanclass.StartingwithSpring3.2,
the CGLIB classes are packaged within the spring-core JAR file itself; therefore, you don’t need to
explicitlyspecifythatyourprojectisdependentonCGLIBJARfile.
The<lookup-method> element provides a method injection technique in which a bean class defines a
beanlookupmethodwhoseimplementationisprovidedbytheSpringcontainer.Insteadofusing<lookup-
method> element, you can consider using <replaced-method> element of Spring’s beans schema to
performmethodinjection.
IMPORTchapter4/ch04-bankapp-replaced-method(ThisprojectshowstheMyBankapplicationthat
uses <replaced-method> element of Spring’s beans schema. To run the application, execute the main
methodoftheBankAppclassofthisproject)
<replaced-method>element
The<replaced-method>elementallowsyoutoreplaceanyarbitrarymethodinabeanclass
with a different implementation. The following example listing shows the
CustomerRequestServiceImpl class that we’ll be using as an example to demonstrate use of
<replaced-method>element:
Examplelisting4-19–CustomerRequestServiceImplclass
Project–ch04-bankapp-replaced-method
Sourcelocation-src/main/java/sample/spring/chapter04/bankapp/service
packagesample.spring.chapter04.bankapp.service;
.....
publicclassCustomerRequestServiceImplimplementsCustomerRequestService{
privateCustomerRequestDaocustomerRequestDao;
.....
publicObjectgetMyBean(StringbeanName){
returnnull;
}
@Override
publicvoidsubmitRequest(StringrequestType,StringrequestDescription){
//--populateCustomerRequestDetailsobjectandsaveit
CustomerRequestDetailscustomerRequestDetails=
(CustomerRequestDetails)getMyBean("customerRequestDetails");
customerRequestDetails.setType(requestType);
customerRequestDetails.setDescription(requestDescription);
customerRequestDao.submitRequest(customerRequestDetails);
}
}
The above example listing shows that the CustomerRequestServiceImpl class defines a getMyBean
method.ThegetMyBeanmethodacceptsnameofabeanasanargument,andinsteadofreturningthebean
instance corresponding to the bean name argument, the getMyBean method returns null. The
submitRequestmethodpassescustomerRequestDetailsstringasargumenttothegetMyBeanmethodand
assumes that the getMyBean method returns an instance of customerRequestDetails bean. Using
<replaced-method>element,youcanoverridethegetMyBeanmethodwithamethodthatreturnsthebean
instancecorrespondingtothebeannameargument.
The <replaced-method> element needs information about the overridden method (which is
CustomerRequestServiceImpl getMyBean method in our example scenario) and the overriding method.
TheoverridingmethodisprovidedbytheclassthatimplementsSpring’sMethodReplacerinterface.The
following example listing shows MyMethodReplacer class that implements the MethodReplacer
interface:
Examplelisting4-20–MyMethodReplacerclass
Project–ch04-bankapp-replaced-method
Sourcelocation-src/main/java/sample/spring/chapter04/bankapp/service
packagesample.spring.chapter04.bankapp.service;
importorg.springframework.beans.factory.support.MethodReplacer;
importorg.springframework.context.ApplicationContextAware;
publicclassMyMethodReplacerimplementsMethodReplacer,ApplicationContextAware{
privateApplicationContextapplicationContext;
@Override
publicObjectreimplement(Objectobj,Methodmethod,Object[]args)throwsThrowable{
returnapplicationContext.getBean((String)args[0]);
}
@Override
publicvoidsetApplicationContext(ApplicationContextapplicationContext)
throwsBeansException{
this.applicationContext=applicationContext;
}
}
Spring’sMethodReplacerinterfacedefinesareimplementmethodwhoseimplementationisprovidedby
the MyMethodReplacer class. The reimplement method represents the overriding method.
MyMethodReplacer class also implements Spring’s ApplicationContextAware interface so that the
reimplement method can access the ApplicationContext instance. The reimplement method uses the
ApplicationContext’sgetBeanmethodtoretrievebeansfromtheSpringcontainer.
Thereimplementmethodacceptsthefollowingarguments:
·Objectobj–identifiestheobjectwhosemethodweareoverriding.Inourexamplescenario,the
objobjectistheCustomerRequestServiceImplobject.
· Methodmethod – identifies the bean class’s method that is overridden by the reimplement
method.Inourexamplescenario,thisisCustomerRequestServiceImpl’sgetMyBeanmethod.
·Object[]args–identifiesargumentspassedtothemethodthatweareoverriding.Inourexample
scenario,args represents the arguments passed to the CustomerRequestServiceImpl’s getMyBean
method.Inexamplelisting4-20,args[0]inthereimplementmethodrefersthebeannameargument
passedtotheCustomerRequestServiceImpl’sgetMyBeanmethod.
IfyounowlookatMyMethodReplacer’sreimplementmethodinexamplelisting4-20,youcaninferthatit
usesargs argument to first obtain bean name passed to the CustomerRequestServiceImpl’s getMyBean
method,andthencallsApplicationContext’sgetBeanmethodtoobtainthecorrespondingbeaninstance.
As MyMethodReplacer’s reimplement method overrides CustomerRequestServiceImpl’s getMyBean
method,calltogetMyBeanmethod at runtime returns thebeaninstance whose name was passed tothe
getMyBeanmethod.
The <replaced-method> element informs the Spring container that MyMethodReplacer’s reimplement
methodoverridesCustomerRequestServiceImpl’sgetMyBeanmethod,asshowninthefollowingexample
listing:
Examplelisting4-21–applicationContext.xml-<replaced-method>elementusage
Project–ch04-bankapp-replaced-method
Sourcelocation-src/main/resources/META-INF/spring
<beanid="customerRequestService"
class="sample.spring.chapter04.bankapp.service.CustomerRequestServiceImpl">
<constructor-argname="customerRequestDao"ref="customerRequestDao"/>
<replaced-methodname="getMyBean"replacer="methodReplacer"/>
</bean>
<beanid="methodReplacer"
class="sample.spring.chapter04.bankapp.service.MyMethodReplacer"/>
The above example listing shows bean definitions for MyMethodReplacer and
CustomerRequestServiceImplclasses.The<replace-method>element’snameattributespecifiesnameof
the method that you want to override, and the replacer attribute specifies reference to the bean that
implementstheMethodReplacerinterface.Themethodspecifiedbythenameattributeisoverriddenby
thereimplementmethodofthebeanreferencedbythereplacerattribute.
As in case of <lookup-method> element, the main method of the BankApp class of ch04-bankapp-
replaced-methodproject validates whether or not the <replaced-method> element overrides the
CustomerRequestService’s getMyBean method with the MyMethodReplacer’s reimplement method.
BankAppclassofch04-bankapp-replaced-methodprojectissameastheonewesawinexamplelisting
4-18 for ch04-bankapp-lookup-methodproject. If you execute the main method of the BankApp class,
you’llfindthat<replaced-method>elementoverridesCustomerRequestServiceImpl’sgetMyBeanmethod
withMyMethodReplacer’sreimplement method; therefore, a fresh instance of CustomerRequestDetails
instanceisretrievedfromtheSpringcontainereachtimeCustomerRequestServiceImpl’ssubmitRequest
method(referexamplelisting4-19)isinvoked.
It is important to note that you can use <replaced-method> element to replace an abstract or concrete
method of a bean class with a different method implementation. For instance, we could have defined
getMyBeanmethodasanabstractmethodandusedthe<replaced-method>elementinthesamewayas
describedinthissection.
NOTEAsthebeanclassneedstobesubclassedatruntimebytheSpringcontainertoreplaceabean
methodwithadifferentmethod,theSpringcontainerusesCGLIB(http://cglib.sourceforge.net/)libraryto
performsubclassingofthebeanclass.StartingwithSpring3.2,theCGLIBclassesarepackagedwithin
thespring-coreJARfileitself;therefore,youdon’tneedtoexplicitlyspecifythatyourprojectis
dependentonCGLIBJARfile.
Let’snowlookathow<replaced-method>elementuniquelyidentifiesthebeanmethodtobeoverridden.
Uniquelyidentifyingthebeanmethod
You may come across scenarios in which the bean method that you want to replace using <replaced-
method>elementcan’tbeuniquelyidentifiedbyname.Forinstance,thefollowingexamplelistingshows
abeanclassthatcontainsoverloadedperformmethods:
Examplelisting4-22–Overloadedmethodsinabeanclass
publicclassMyBean{
publicvoidperform(Stringtask1,Stringtask2){.....}
publicvoidperform(Stringtask){.....}
publicvoidperform(my.Tasktask){.....}
}
In theabove examplelisting, theMyBean class contains multiplemethods named perform. To uniquely
identifythebeanmethodtobeoverridden,the<replaced-method>elementuses<arg-type>sub-elements
to specify method argument types. For instance, the following example listing shows how <replaced-
method>elementspecifiesthattheperform(String,String)methodofMyBeanclassshouldbereplaced:
Examplelisting4-23–<replaced-method>elementwith<arg-type>sub-element
<beanid="mybean"class="MyBean">
<replaced-methodname="perform"replacer=".....">
<arg-type>java.lang.String</arg-type>
<arg-type>java.lang.String</arg-type>
</replaced-method>
</bean>
Insteadofusingthefully-qualifiednameasthevalueof<arg-type>element,youcanuseasubstringofthe
fully-qualifiednameasthevalue.Forinstance,insteadofusingjava.lang.String,youcanspecifyStror
Stringasthevalueof<arg-type>elementintheaboveexamplelisting.
Let’snowlookatSpring’sautowiringfeaturethatsavesyoutheeffortofspecifyingbeandependenciesin
theapplicationcontextXMLfile.
4-6Autowiringdependencies
In Spring, you have the option to either explicitly specify bean dependencies using <property> and
<constructor-arg>elementsorletSpringautomaticallyresolvebeandependencies.Theprocessinwhich
dependenciesareautomaticallyresolvedbySpringisreferredtoas‘autowiring’.
IMPORTchapter4/ch04-bankapp-autowiring(This project shows the MyBank application that uses
Spring’sautowiringfeaturefordependencyinjection.Toruntheapplication,executethemainmethodof
theBankAppclassofthisproject)
The<bean>element’sautowireattributespecifieshowabean’sdependenciesareautomaticallyresolved
by Spring. The autowire attribute can take any one of the following values: default, byName, byType,
constructorandno.Let’snowlookateachoftheseattributevaluesindetail.
NOTEYoushouldnotethatthe<bean>element’sautowireattributeisnotinheritedbychildbean
definitions.
byType
Ifyouspecifyautowireattribute’svalueasbyType,Springautowiresbeanpropertiesbasedontheirtype.
For instance, if a bean A defines a property of type X, Spring finds a bean of type X in the
ApplicationContextandinjectsitintobeanA.Let’slookatanexampleusageofbyTypeautowiringinthe
MyBankapplication.
ThefollowingexamplelistingshowstheMyBankapplication’sCustomerRegistrationServiceImplclass:
Examplelisting4-24–CustomerRegistrationServiceImplclass
Project–ch04-bankapp-autowiring
Sourcelocation-src/main/java/sample/spring/chapter04/bankapp/service
packagesample.spring.chapter04.bankapp.service;
publicclassCustomerRegistrationServiceImplimplementsCustomerRegistrationService{
privateCustomerRegistrationDetailscustomerRegistrationDetails;
privateCustomerRegistrationDaocustomerRegistrationDao;
....
publicvoidsetCustomerRegistrationDetails(
CustomerRegistrationDetailscustomerRegistrationDetails){
this.customerRegistrationDetails=customerRegistrationDetails;
}
publicvoidsetCustomerRegistrationDao(
CustomerRegistrationDaocustomerRegistrationDao){
this.customerRegistrationDao=customerRegistrationDao;
}
.....
}
The above example listing shows that the CustomerRegistrationServiceImpl class defines properties
namedcustomerRegistrationDetails(oftypeCustomerRegistrationDetails)andcustomerRegistrationDao
(of type CustomerRegistrationDao). This means that the CustomerRegistrationDetails and
CustomerRegistrationDaoobjectsaredependenciesofCustomerRegistrationServiceImplobject.
The following example listing shows bean definitions for CustomerRegistrationServiceImpl,
CustomerRegistrationDetails and CustomerRegistrationDaoImpl (an implementation of
CustomerRegistrationDaointerface)classes:
Examplelisting4-25–applicationContext.xml-autowiringbyTypeconfiguration
Project–ch04-bankapp-autowiring
Sourcelocation-src/main/resources/META-INF/spring
<beanid="customerRegistrationService"
class="sample.spring.chapter04.bankapp.service.CustomerRegistrationServiceImpl"
scope="prototype"autowire="byType"/>
<beanid="customerRegistrationDetails"
class="sample.spring.chapter04.bankapp.domain.CustomerRegistrationDetails"
scope="prototype"/>
<beanid="customerRegistrationDao"
class="sample.spring.chapter04.bankapp.dao.CustomerRegistrationDaoImpl"/>
Intheaboveexamplelisting,thecustomerRegistrationServicebeandefinitiondoesn’tcontain<property>
elementsforsettingcustomerRegistrationDetailsandcustomerRegistrationDaoproperties(referexample
listing4-24).Instead,the<bean>elementspecifiesautowireattribute’svalueasbyTypetoinstructSpring
to automatically resolve dependencies of the customerRegistrationService bean based on their type.
Spring looks for beans of types CustomerRequestDetails and CustomerRegistrationDao in the
ApplicationContext, and injects them into the customerRegistrationService bean. As
customerRegistrationDetails and customerRegistrationDao beans represent beans of types
CustomerRegistrationDetails and CustomerRegistrationDao, the Spring container injects
customerRegistrationDetailsandcustomerRegistrationDaobeansintocustomerRegistrationServicebean.
It may happen that Spring doesn’t find any bean registered with the ApplicationContext whose type
matches the property type. In such cases, no exception is thrown and the bean property is not set. For
instance, if a bean defines a property x of type Y, and there is no bean of type Y registered with the
ApplicationContext instance, the property x is not set. If Spring finds multiple beans in the
ApplicationContextthatmatchthepropertytype,anexceptionisthrown.Insuchcases,insteadofusing
autowiringfeature,use<property>elementstoexplicitlyidentifybeandependenciesorsetabeanasthe
primarycandidateforautowiringbysettingthevalueofprimaryattributeof<bean>elementtotrue.
constructor
If you specify autowire attribute’s value as constructor, Spring autowires bean class’s constructor
argumentsbasedontheirtype.Forinstance,ifbeanA’sconstructoracceptsargumentsoftypeXandY,
SpringfindsbeansoftypesXandYintheApplicationContextandinjectsthemasargumentstobeanA’s
constructor.Let’slookatanexampleusageofconstructorautowiringintheMyBankapplication.
ThefollowingexamplelistingshowstheMyBankapplication’sCustomerRequestServiceImplclass:
Examplelisting4-26–CustomerRequestServiceImplclass
Project–ch04-bankapp-autowiring
Sourcelocation-src/main/java/sample/spring/chapter04/bankapp/service
packagesample.spring.chapter04.bankapp.service;
publicclassCustomerRequestServiceImplimplementsCustomerRequestService{
privateCustomerRequestDetailscustomerRequestDetails;
privateCustomerRequestDaocustomerRequestDao;
@ConstructorProperties({"customerRequestDetails","customerRequestDao"})
publicCustomerRequestServiceImpl(
CustomerRequestDetailscustomerRequestDetails,
CustomerRequestDaocustomerRequestDao){
this.customerRequestDetails=customerRequestDetails;
this.customerRequestDao=customerRequestDao;
}
.....
}
The CustomerRequestServiceImpl class defines a constructor that accepts arguments of type
CustomerRequestDetailsandCustomerRequestDao.
The following example listing shows bean definitions for CustomerRequestServiceImpl,
CustomerRequestDetails and CustomerRequestDaoImpl (an implementation of CustomerRequestDao
interface)classes:
Examplelisting4-27–applicationContext.xml-constructorautowiring
Project–ch04-bankapp-autowiring
Sourcelocation-src/main/resources/META-INF/spring
<beanid="customerRequestService"
class="sample.spring.chapter04.bankapp.service.CustomerRequestServiceImpl"
autowire="constructor">
</bean>
<beanid="customerRequestDetails"
class="sample.spring.chapter04.bankapp.domain.CustomerRequestDetails"scope="prototype"/>
<beanid="customerRequestDao"
class="sample.spring.chapter04.bankapp.dao.CustomerRequestDaoImpl"/>
In theaboveexamplelisting,thecustomerRequestServicebeandefinitionspecifiesautowire attribute’s
value as constructor, which means that Spring locates beans of types CustomerRequestDetails and
CustomerRequestDao in the ApplicationContext, and passes them as arguments to
CustomerRequestServiceImpl class’s constructor. As customerRequestDetails and customerRequestDao
beans are of type CustomerRequestDetails and CustomerRequestDao, Spring automatically injects
instancesofthesebeansintocustomerRequestServicebean.
IfSpringdoesn’tfindanybeanintheApplicationContextwhosetypematchestheconstructorargument
type, the constructor argument is not set. If Spring finds multiple beans in the ApplicationContext that
match the constructor argument type, an exception is thrown; therefore, in such scenarios use
<constructor-arg> elements to explicitly identify bean dependencies or set a bean as the primary
candidateforautowiringbysettingvalueofprimaryattributeof<bean>elementtotrue.
byName
If you specify autowire attribute’s value as byName, Spring autowires bean properties based on their
names. For instance, if a bean A defines a property named x, Spring finds a bean named x in the
ApplicationContextandinjectsitintobeanA.Let’slookatanexampleusageofbyNameautowiringinthe
MyBankapplication.
ThefollowingexamplelistingshowstheMyBankapplication’sFixedDepositServiceImplclass:
Examplelisting4-28–FixedDepositServiceImplclass
Project–ch04-bankapp-autowiring
Sourcelocation-src/main/java/sample/spring/chapter04/bankapp/service
packagesample.spring.chapter04.bankapp.service;
importsample.spring.chapter04.bankapp.dao.FixedDepositDao;
importsample.spring.chapter04.bankapp.domain.FixedDepositDetails;
publicclassFixedDepositServiceImplimplementsFixedDepositService{
privateFixedDepositDaomyFixedDepositDao;
publicvoidsetMyFixedDepositDao(FixedDepositDaomyFixedDepositDao){
this.myFixedDepositDao=myFixedDepositDao;
}
.....
}
The above example listing shows that FixedDepositServiceImpl class defines a property named
myFixedDepositDaooftypeFixedDepositDao.
The following example listing shows bean definitions for FixedDepositServiceImpl and
FixedDepositDaoImpl(animplementationofFixedDepositDaointerface)classes:
Examplelisting4-29–applicationContext.xml-byNameautowiring
Project–ch04-bankapp-autowiring
Sourcelocation-src/main/resources/META-INF/spring
<beanid="FixedDepositService"
class="sample.spring.chapter04.bankapp.service.FixedDepositServiceImpl"
autowire="byName"/>
<beanid="myFixedDepositDao"
class="sample.spring.chapter04.bankapp.dao.FixedDepositDaoImpl"/>
Intheaboveexamplelisting,FixedDepositServicebeandefinitionspecifiesautowireattribute’svalueas
byName, which means properties of FixedDepositService bean are automatically resolved by Spring
basedontheirnames.Inlisting4-28,wesawthattheFixedDepositServiceImplclassdefinesaproperty
named myFixedDepositDao; therefore, Spring looks for a bean named myFixedDepositDao in the
ApplicationContext and injects it into FixedDepositService bean. In the above example listing,
myFixedDepositDao bean definition represents the FixedDepositDaoImpl class, which means that an
instance of FixedDepositDaoImpl is injected for property named myFixedDepositDao in the
FixedDepositServicebean.
default/no
Ifyouspecifyautowireattribute’svalueasdefaultorno,autowiringfeatureisdisabledforthebean.As
Spring’s default behavior is to use no autowiring for beans, specifying autowire attribute’s value as
defaultmeansnoautowiringwillbeperformedforthebean.Youcanexplicitlyspecifythatabeanmust
notuseSpring’sautowiringfeaturebyspecifyingautowireattribute’svalueasno.
NOTEYoucanchangethedefaultautowiringbehaviorofbeansbysettingthedefault-autowireattribute
of<beans>element.For instance, if you set default-autowire attribute’s value tobyType, it effectively
meanssettingvalueofautowireattributeofallthe<bean>elementsintheapplicationcontextXMLfileto
byType.Youshouldnotethatifa<bean>element’sautowireattributespecifiesadifferentvaluethanthe
<beans>element’sdefault-autowireattribute,the<bean>element’sautowireattributevalueappliestothe
bean.
The following example listing shows the bean definition for the MyBank application’s
CustomerRegistrationServiceImplclassthatspecifiesautowireattribute’svalueasno:
Examplelisting4-30–applicationContext.xml-noautowiring
Project–ch04-bankapp-autowiring
Sourcelocation-src/main/resources/META-INF/spring
<beanid="customerRegistrationService_"
class="sample.spring.chapter04.bankapp.service.CustomerRegistrationServiceImpl"
scope="prototype"autowire="no"/>
Example listing 4-24 showed that the CustomerRegistrationServiceImpl class defines
customerRegistrationDetails(oftypeCustomerRegistrationDetails)andcustomerRegistrationDao(oftype
CustomerRegistrationDao) properties. As the autowire attribute’s value is specified as no for
customerRegistrationService_bean,autowiringisdisabledforcustomerRegistrationService_bean.This
means that the customerRegistrationDetails and customerRegistrationDao properties of
customerRegistrationService_beanarenotsetbySpring.
So far in this section we have seen different ways in which bean dependencies can be autowired by
Spring.Let’snowlookathowwecanmakeabeanunavailableforautowiringpurposesusing<bean>
element’sautowire-candidateattribute.
Makingbeansunavailableforautowiring
ThedefaultbehavioroftheSpringcontaineristomakebeansavailableforautowiring.Youcanmakea
beanunavailabletootherbeansforautowiringpurposesbysettingautowire-candidateattribute’svalueto
false.
In MyBank application, the AccountStatementServiceImpl class defines a property of type
AccountStatementDao.ThefollowingexamplelistingshowstheAccountStatementServiceImplclass:
Examplelisting4-31–AccountStatementServiceImplclass
Project–ch04-bankapp-autowiring
Sourcelocation-src/main/java/sample/spring/chapter04/bankapp/service
packagesample.spring.chapter04.bankapp.service;
importsample.spring.chapter04.bankapp.dao.AccountStatementDao;
importsample.spring.chapter04.bankapp.domain.AccountStatement;
publicclassAccountStatementServiceImplimplementsAccountStatementService{
privateAccountStatementDaoaccountStatementDao;
publicvoidsetAccountStatementDao(AccountStatementDaoaccountStatementDao){
this.accountStatementDao=accountStatementDao;
}
.....
}
The following example listing shows bean definitions for AccountStatementServiceImpl and
AccountStatementDaoImpl(animplementationofAccountStatementDaointerface)classes:
Examplelisting4-32–applicationContext.xml-autowire-candidateattribute
Project–ch04-bankapp-autowiring
Sourcelocation-src/main/resources/META-INF/spring
<beanid="accountStatementService"
class="sample.spring.chapter04.bankapp.service.AccountStatementServiceImpl"
autowire="byType"/>
<beanid="accountStatementDao"
class="sample.spring.chapter04.bankapp.dao.AccountStatementDaoImpl"
autowire-candidate="false"/>
Intheaboveexamplelisting,theaccountStatementServicebeandefinitionspecifiesautowireattribute’s
valueas byType, which means AccountStatementDaopropertytype ofaccountStatementService bean is
autowiredbytype.AsaccountStatementDaobeanisoftypeAccountStatementDao,you mightthink that
Spring will inject accountStatementDao bean instance into accountStatementService bean. But, Spring
won’t consider accountStatementDao bean for autowiring purposes because the accountStatementDao
beandefinitionspecifiesautowire-candidateattribute’svalueasfalse.
NOTEYoushouldnotethatabeanthatisunavailabletootherbeansforautowiringpurposescanitself
makeuseofSpring’sautowiringfeaturetoautomaticallyresolveit’sdependencies.
As mentioned earlier, the default behavior of the Spring container is to make beans available for
autowiring purposes. To make only only a select set of beans available for autowiring purposes, set
<beans> element’s default-autowire-candidates attribute. The default-autowire-candidates attribute
specifies a bean name pattern, and only beans whose names match the specified pattern are made
available for autowiring. The followingexamplelisting shows anexample usageof default-autowire-
candidatesattribute:
Examplelisting4-33–default-autowire-candidatesattributeexample
<beansdefault-autowire-candidates="*Dao">
.....
<beanid="customerRequestDetails"
class="sample.spring.chapter04.bankapp.domain.CustomerRequestDetails"
scope="prototype"autowire-candidate="true"/>
<beanid="customerRequestDao"
class="sample.spring.chapter04.bankapp.dao.CustomerRequestDaoImpl"/>
<beanid="customerRegistrationDao"
class="sample.spring.chapter04.bankapp.dao.CustomerRegistrationDaoImpl"/>
.....
</beans>
Intheaboveexamplelisting,default-autowire-candidatesvalueissetto*Dao,whichmeansthatbeans
whose names end with Dao (like customerRequestDao and customerRegistrationDao beans) will be
available for autowiring purposes. If a bean name doesn’t match the pattern specified by the default-
autowire-candidates attribute (like customerRequestDetails bean), you can still make it available for
autowiringpurposesbysettingtheautowire-candidateattributeofthecorresponding<bean>elementto
true.
Let’snowlookatlimitationsofusingautowiringinapplications.
Autowiringlimitations
Wesawthatautowiringfeaturesavestheefforttoexplicitlyspecifybeandependenciesusing<property>
and<constructor-arg>elements.Thedownsidesofusingautowiringfeatureare:
·Youcan’tuseautowiringtosetpropertiesorconstructorargumentsthatareofsimpleJavatypes
(likeint,long,boolean,String,Date, and so on). You canautowire arrays, typed collections and
mapsiftheautowireattribute’svalueissettobyTypeorconstructor.
· As bean dependencies are automatically resolved by Spring, it results in hiding the overall
structureoftheapplication.Ifyouuse<property>and<constructor-arg>elementstospecifybean
dependencies,itresultsinexplicitlydocumentingtheoverallstructureoftheapplication.Youcan
easily understand and maintain an application in which bean dependencies are explicitly
documented.Forthisreason,itisnotrecommendedtouseautowiringinlargeapplications.
4-7Summary
Inthischapter,welookedathowSpringcaterstodifferentdependencyinjectionscenarios.Welookedat
how you can use ApplicationContextAware interface, <replaced-method> and <lookup-method> sub-
elementsof<bean> element toprogrammaticallyretrieve abean instance from the ApplicationContext.
We also looked at how Spring’s autowiring feature can save the effort for explicitly specifying bean
dependencies in the application context XML file. In the next chapter, we’ll look at how to customize
beansandbeandefinitions.
Chapter5-Customizingbeansandbeandefinitions
5-1Introduction
SofarinthisbookwehaveseenexamplesinwhichtheSpringcontainercreatedabeaninstancebasedon
thebeandefinitionspecifiedintheapplicationcontextXMLfile.Inthischapter,we’llgoastepfurther
andlookat:
·howtoincorporatecustominitializationanddestructionlogicforabean
·howtointeractwithanewlycreatedbeaninstancebyimplementingSpring’sBeanPostProcessor
interface
·howtomodifybeandefinitionsbyimplementingSpring’sBeanFactoryPostProcessorinterface
5-2Customizingbean’sinitializationanddestructionlogic
We saw in earlier chapters that the Spring container is responsible for creating a bean instance and
injectingitsdependencies.Aftercreatingabeaninstancebyinvokingtheconstructorofthebeanclass,the
Springcontainersetsbeanpropertiesbyinvokingbean’ssettermethods.Ifyouwanttoexecutecustom
initialization logic (like opening a file, creating a database connection, and so on) after the bean
propertiesaresetbutbeforethebeaniscompletelyinitializedbytheSpringcontainer,youcandosoby
specifyingthenameoftheinitializationmethodasthevalueofinit-methodattributeof<bean>element.
Similarly,ifyou wantto executecustomcleanuplogic before the Spring container containingthe bean
instance is destroyed, you can specify the name of the cleanup method as the value of destroy-
methodattributeof<bean>element.
IMPORT chapter 5/ch05-bankapp-customization (This project shows the MyBank application that
uses <bean> element’s init-method and destroy-method elements to specify custom initialization and
destructionmethods.Totestwhethertheinitializationmethodisexecuted,executethemainmethodofthe
BankApp class of this project. To test whether the destruction method is executed, execute the main
methodoftheBankAppWithHookclassofthisproject.)
The following example listing shows the MyBank’s FixedDepositDaoImpl class that defines an
initializationmethodnamedinitializeDbConnectionforobtainingconnectiontoMyBank’sdatabase,anda
destructionmethodnamedreleaseDbConnectionforreleasingtheconnection:
Examplelisting5-1–FixedDepositDaoImplclass-Custominitializationanddestructionlogic
Project–ch05-bankapp-customization
Sourcelocation-src/main/java/sample/spring/chapter05/bankapp/dao
packagesample.spring.chapter05.bankapp.dao;
publicclassFixedDepositDaoImplimplementsFixedDepositDao{
privatestaticLoggerlogger=Logger.getLogger(FixedDepositDaoImpl.class);
privateDatabaseConnectionconnection;
publicFixedDepositDaoImpl(){
logger.info("FixedDepositDaoImpl'sconstructorinvoked");
}
publicvoidinitializeDbConnection(){
logger.info("FixedDepositDaoImpl’sinitializeDbConnectionmethodinvoked");
connection=DatabaseConnection.getInstance();
}
publicbooleancreateFixedDeposit(FixedDepositDetailsfixedDepositDetails){
logger.info("FixedDepositDaoImpl’screateFixedDepositmethodinvoked");
//--savethefixeddepositsandthenreturntrue
returntrue;
}
publicvoidreleaseDbConnection(){
logger.info("FixedDepositDaoImpl’sreleaseDbConnectionmethodinvoked");
connection.releaseConnection();
}
}
In the above example listing, the DatabaseConnection object is used for interacting with the MyBank’s
database. FixedDepositDaoImpl class defines an initializeDbConnection method that initializes the
DatabaseConnection object, which is later used by the createFixedDeposit method for saving fixed
depositdetailsintheMyBank’sdatabase.
The following example listing shows the MyBank’s FixedDepositServiceImpl class that uses
FixedDepositDaoImplinstancetocreatenewfixeddeposits:
Examplelisting5-2–FixedDepositServiceImplclass
Project–ch05-bankapp-customization
Sourcelocation-src/main/java/sample/spring/chapter05/bankapp/service
packagesample.spring.chapter05.bankapp.service;
publicclassFixedDepositServiceImplimplementsFixedDepositService{
privatestaticLoggerlogger=Logger.getLogger(FixedDepositServiceImpl.class);
privateFixedDepositDaomyFixedDepositDao;
publicvoidsetMyFixedDepositDao(FixedDepositDaomyFixedDepositDao){
logger.info("FixedDepositServiceImpl'ssetMyFixedDepositDaomethodinvoked");
this.myFixedDepositDao=myFixedDepositDao;
}
@Override
publicvoidcreateFixedDeposit(FixedDepositDetailsfixedDepositDetails)throwsException{
//--createfixeddeposit
myFixedDepositDao.createFixedDeposit(fixedDepositDetails);
}
}
The above example listing shows that the FixedDepositDaoImpl instance is a dependency of
FixedDepositServiceImpl, and is passed as an argument to the setMyFixedDepositDao setter-method.
And, if FixedDepositServiceImpl’s createFixedDeposit method is invoked, it results in invocation of
FixedDepositDaoImpl’screateFixedDepositmethod.
The following example listing shows bean definitions for FixedDepositDaoImpl and
FixedDepositServiceImplclasses:
Examplelisting5-3–applicationContext.xml–usageofinit-methodanddestroy-methodattributes
Project–ch05-bankapp-customization
Sourcelocation-src/main/resources/META-INF/spring
<beans.....>
<beanid="FixedDepositService"
class="sample.spring.chapter05.bankapp.service.FixedDepositServiceImpl">
<propertyname="myFixedDepositDao"ref="myFixedDepositDao"/>
</bean>
<beanid="myFixedDepositDao"
class="sample.spring.chapter05.bankapp.dao.FixedDepositDaoImpl"
init-method="initializeDbConnection"destroy-method="releaseDbConnection"/>
</beans>
The above example listing shows that the <bean> element corresponding to the FixedDepositDaoImpl
class specifies initializeDbConnection and releaseDbConnection as the values of init-method and
destroy-methodattributes,respectively.
NOTEItisimportanttonotethattheinitializationanddestructionmethodsspecifiedbytheinit-method
anddestroy-methodattributesof<bean>elementmustnotacceptanyarguments,butcanbedefinedto
throwexceptions.
The following example listing shows BankApp class whose main method retrieves
FixedDepositServiceImplinstancefromtheApplicationContextandinvokesFixedDepositServiceImpl’s
createFixedDepositmethod:
Examplelisting5-4–BankAppclass
Project–ch05-bankapp-customization
Sourcelocation-src/main/java/sample/spring/chapter05/bankapp
packagesample.spring.chapter05.bankapp;
publicclassBankApp{
publicstaticvoidmain(Stringargs[])throwsException{
ApplicationContextcontext=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
FixedDepositServiceFixedDepositService=context.getBean(FixedDepositService.class);
FixedDepositService.createFixedDeposit(newFixedDepositDetails(1,1000,
12,"someemail@somedomain.com"));
}
}
IfyounowexecutetheBankApp’smainmethod,you’llseethefollowingoutputontheconsole:
FixedDepositDaoImpl'sconstructorinvoked
FixedDepositDaoImpl’sinitializeDbConnectionmethodinvoked
FixedDepositServiceImpl'ssetMyFixedDepositDaomethodinvoked
FixedDepositDaoImpl’screateFixedDepositmethodinvoked
TheaboveoutputshowsthattheSpringcontainerfirstcreatesFixedDepositDaoImpl’sinstance,andthen
invokes initializeDbConnection method. After the invocation of initializeDbConnection method, the
FixedDepositDaoImplinstanceisinjectedintotheFixedDepositServiceImplinstance.Thisshowsthatthe
Springcontainerinjectsadependency(theFixedDepositDaoImplinstance)intothedependentbean(the
FixedDepositServiceImpl instance) after the initialization method of the dependency is invoked by the
Springcontainer.
YoumayhavenoticedthattheoutputfromexecutingBankApp’smainmethoddidn’tcontainthefollowing
message:FixedDepositDaoImpl’sreleaseDbConnectionmethodinvoked(referFixedDepositDaoImpl’s
releaseDbConnection method in example listing 5-1). This means that the FixedDepositDaoImpl’s
releaseDbConnection method was not called by the Spring container when BankApp’s main method
exited.Inarealworldapplicationdevelopmentscenario,thismeansthatthedatabaseconnectionheldby
FixedDepositDaoImpl instance is never released. Let’s now see how you can make Spring gracefully
destroysingleton-scopedbeaninstancesbycallingthecleanupmethodspecifiedbythe<bean>element’s
destroy-methodattribute.
MakingSpringinvokecleanupmethodspecifiedbythedestory-methodattribute
The web version of ApplicationContext implementation is represented by Spring’s
WebApplicationContextobject.WebApplicationContextimplementationhasthenecessarylogictoinvoke
thecleanupmethod(specifiedbythedestroy-methodattribute)ofsingleton-scopedbeaninstancesbefore
thewebapplicationisshutdown.
NOTETheapproachdescribedinthissectiononmakingSpringgracefullydestroysingleton-scopedbean
instancesbycallingthecleanupmethodisspecifictostandaloneapplications.
ThefollowingexamplelistingshowstheBankAppWithHookclass(amodifiedversionofBankAppclass
shown in example listing 5-4) whose main method ensures that cleanup methods (specified by <bean>
element’sdestroy-methodattribute)ofallsingleton-scopedbeansregisteredwiththeSpringcontainerare
invokedwhenthemainmethodexits:
Examplelisting5-5–BankAppWithHookclass–registeringashutdownhookwithJVM
Project–ch05-bankapp-customization
Sourcelocation-src/main/java/sample/spring/chapter05/bankapp
packagesample.spring.chapter05.bankapp;
publicclassBankAppWithHook{
publicstaticvoidmain(Stringargs[])throwsException{
AbstractApplicationContextcontext=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
context.registerShutdownHook();
FixedDepositServiceFixedDepositService=context.getBean(FixedDepositService.class);
FixedDepositService.createFixedDeposit(newFixedDepositDetails(1,1000,
12,"someemail@somedomain.com"));
}
}
Spring’s AbstractionApplicationContext class implements ApplicationContext interface and defines a
registerShutdownHook method that registers a shutdown hook with the JVM. The shutdown hook is
responsibleforclosingtheApplicationContextwhentheJVMisshutdown.Intheaboveexamplelisting,
you’ll notice that the ClassPathXmlApplicationContext instance is assigned to
AbstractionApplicationContext type, and the AbstractionApplicationContext’s registerShutdownHook is
calledtoregisterashutdownhookwiththeJVM.WhentheBankAppWithHook’smainmethodexists,the
shutdownhookdestroysallcachedsingletonbeaninstancesandclosestheApplicationContextinstance.
IfyouexecuteBankAppWithHook’smainmethodofch05-bankapp-customizationproject,you’llseethe
followingoutputontheconsole:
FixedDepositDaoImpl'sconstructorinvoked
FixedDepositDaoImpl’sinitializeDbConnectionmethodinvoked
FixedDepositServiceImpl'ssetMyFixedDepositDaomethodinvoked
FixedDepositDaoImpl'sreleaseDbConnectionmethodinvoked
Themessage‘FixedDepositDaoImpl'sreleaseDbConnectionmethod invoked’ on theconsoleconfirms
that the FixedDepositDaoImpl’s releaseDbConnection method (refer FixedDepositDaoImpl’s
releaseDbConnection method in example listing 5-1) was invoked. As you can see, registering a
shutdown hook with the JVM resulted in invocation of the cleanup method of the singleton-scoped
myFixedDepositDaobean(correspondingtotheFixedDepositDaoImplclass).
Let’snowlookattheimpactofshutdownhookonprototype-scopedbeans.
Cleanupmethodsandprototype-scopedbeans
In case of prototype-scoped beans, destroy-method attribute is ignored by the Spring container. The
destroy-methodattributeisignoredbecausetheSpring containerexpectsthattheobjectthatfetches the
prototype-scoped bean instance from the ApplicationContext is responsible for explicitly calling the
cleanupmethodontheprototype-scopedbeaninstance.
NOTELifecyclesofprototype-andsingleton-scopedbeansaresame,exceptthattheSpringcontainer
willnotcallthecleanupmethod(specifiedbythedestroy-initattribute)oftheprototype-scopedbean
instance.
Let’s now look at how you can specify default initialization and destruction methods for all the beans
containedintheapplicationcontextXMLfile.
Specifyingdefaultbeaninitializationanddestructionmethodsforallbeans
Youcanusethedefault-init-methodanddefault-destroy-methodattributesof<beans>elementtospecify
defaultinitializationanddestructionmethodsforbeans,asshowninthefollowingexamplelisting:
Examplelisting5-6–default-init-methodanddefault-destroy-methodattributes
<beans.....default-init-method="initialize"default-destroy-method="release">
<beanid="A"class="....."init-method="initializeService"/>
<beanid="B"class="....."/>
</beans>
If multiple beans define initialization or cleanup methods with the same name, it makes sense to use
default-init-methodanddefault-destroy-methodattributes.Byspecifyinginit-methodanddestroy-method
attributes,a<bean>elementcanoverridethevaluesspecifiedby<beans>element’sdefault-init-method
anddefault-destroy-methodattributes.Forinstance,intheaboveexamplelisting,beanAspecifiesinit-
method attribute value as initializeService, which means initializeService method (and not initialize
methodspecifiedbythedefault-init-methodattributeof<beans>element)istheinitializationmethodof
beanA.
Instead of using init-method and destroy-method attributes of <bean> element to specify custom
initialization and destruction methods, you can use Spring’s InitializingBean and DisposableBean
lifecycleinterfaces.
InitializingBeanandDisposableBeanlifecycleinterfaces
Abeanthatimplementslifecycleinterfaces,likeApplicationContextAware(refersection4-5ofchapter
4),InitializingBeanandDisposableBean,receivescallbacksfromtheSpringcontainertogiveachanceto
the bean instance to perform some action, or to provide bean instance with some information. For
instance, if a bean implements ApplicationContextAware interface, container invokes
setApplicationContext method of the bean instance to provide the bean with a reference to the
ApplicationContextinwhichthebeanisdeployed.
InitializingBeaninterface defines an afterPropertiesSet method that is invoked by the Spring container
afterthebeanpropertiesareset.BeansperforminitializationworkintheafterPropertiesSetmethod,like
obtainingconnectiontoadatabase,openingaflatfileforreading,andsoon.DisposableBeaninterface
definesadestroymethodthatisinvokedbytheSpringcontainerwhenthebeaninstanceisdestroyed.
NOTE As with the ApplicationContextAware lifecycle interface, beans should avoid implementing
InitializingBeanandDisposableBeaninterfacesbecauseitcouplesapplicationcodewithSpring.
Let’s now look at JSR 250’s @PostConstruct and @PreDestroy annotations for specifying bean
initializationanddestructionmethods.
JSR250’s@PostConstructand@PreDestroyannotations
JSR250(CommonAnnotationsfortheJavaPlatform)definesstandardannotationsthatareusedacross
different Java technologies. JSR 250’s @PostConstruct and @PreDestroy annotations identify
initialization and destruction methods of an object. A bean class in Spring can set a method as an
initializationmethodbyannotatingitwith@PostConstruct,andsetamethodasadestructionmethodby
annotatingitwith@PreDestroyannotation.
NOTEReferJSR250homepage(http://jcp.org/en/jsr/detail?id=250)formoredetails.
IMPORTchapter5/ch05-bankapp-jsr250(This project shows the MyBank application that uses JSR
250’s @PostConstruct and @PreDestroy annotations to identify custom initialization and destruction
methods,respectively.Totestwhethertheinitializationmethodisexecuted,executethemainmethodof
theBankAppclassofthisproject.Totestwhetherthedestructionmethodisexecuted,executethemain
methodoftheBankAppWithHookclassofthisproject.)
ThefollowingexamplelistingshowstheFixedDepositDaoImplclassofch05-bankapp-jsr250projectthat
uses@PostConstructand@PreDestroyannotations:
Examplelisting5-7–FixedDepositDaoImplclass-@PostConstructand@PreDestroyannotations
Project–ch05-bankapp-jsr250
Sourcelocation-src/main/java/sample/spring/chapter05/bankapp/dao
packagesample.spring.chapter05.bankapp.dao;
importjavax.annotation.PostConstruct;
importjavax.annotation.PreDestroy;
publicclassFixedDepositDaoImplimplementsFixedDepositDao{
privateDatabaseConnectionconnection;
.....
@PostConstruct
publicvoidinitializeDbConnection(){
logger.info("FixedDepositDaoImplísinitializeDbConnectionmethodinvoked");
connection=DatabaseConnection.getInstance();
}
.....
@PreDestroy
publicvoidreleaseDbConnection(){
logger.info("FixedDepositDaoImpl'sreleaseDbConnectionmethodinvoked");
connection.releaseConnection();
}
}
In the above example listing, the FixedDepositDaoImpl class uses @PostConstruct and @PreDestroy
annotations toidentify initializationanddestructionmethods.You should note that @PostConstruct and
@PreDestroyannotationsarenotspecifictoSpring.
NOTEJavaSE6providesannotationsdefinedbyJSR250;ifyouareusingJavaSE6orlater,youdon’t
needtoincludeJSR250JARfileinyourapplication’sclasspath.IfyouareusingJavaSE5,youneedto
includeJSR250JARfileandtherelatedJARfilesinyourapplication’sclasspath.
Touse@PostConstructand@PreDestroyannotationsinyourapplication,youneedtoconfigureSpring’s
CommonAnnotationBeanPostProcessorclassintheapplicationcontextXMLfile,asshownhere:
Examplelisting5-8–applicationContext.xml–CommonAnnotationBeanPostProcessorconfiguration
Project–ch05-bankapp-jsr250
Sourcelocation-src/main/resources/META-INF/spring
<beans.....>
<beanid="FixedDepositService"
class="sample.spring.chapter05.bankapp.service.FixedDepositServiceImpl">
<propertyname="myFixedDepositDao"ref="myFixedDepositDao"/>
</bean>
<beanid="myFixedDepositDao"
class="sample.spring.chapter05.bankapp.dao.FixedDepositDaoImpl"/>
<bean
class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
</beans>
CommonAnnotationBeanPostProcessor implements Spring’s BeanPostProcessor interface (explained in
thenextsection),andisresponsibleforprocessingJSR250annotations.
If you execute the main method of BankApp and BankAppWithHook classes, you’ll notice that the
@PostConstruct and @PreDestroy annotated methods of FixedDepositDaoImpl class are executed at
creationanddestructionofFixedDepositDaoImplinstance,respectively.
We’llnowlookatSpring’sBeanPostProcessorinterfacethatallowsyoutointeractwithnewlycreated
beaninstancesbeforeoraftertheyareinitializedbytheSpringcontainer.
5-3 Interacting with newly created bean instances using
BeanPostProcessor
BeanPostProcessor is used to interact with newly created bean instances before and/or after their
initialization method (refer section 5-2) is invoked by the Spring container. You can use
BeanPostProcessortoexecutecustomlogicbeforeand/orafterbean’sinitializationmethodisinvokedby
theSpringcontainer.
NOTEAbeanthatimplementsSpring’sBeanPostProcessorinterfaceisaspecialbeantype;
theSpringcontainerautomaticallydetectsandexecutesaBeanPostProcessorbean.
BeanPostProcessorinterfacedefinesthefollowingmethods:
· ObjectpostProcessBeforeInitialization(Object bean, String beanName) – this method is
invokedbeforetheinitializationmethodofabeaninstanceisinvoked
· Object postProcessAfterInitialization(Object bean, String beanName) – this method is
invokedaftertheinitializationmethodofabeaninstanceisinvoked
BeanPostProcessor’smethodsacceptnewlycreatedbeaninstanceanditsnameasarguments,andreturn
thesameormodifiedbeaninstance.Forinstance,ifyouhaveconfiguredaFixedDepositDaoImplclassas
abeanwithidvalueasmyFixedDepositDaointheapplicationcontextXMLfile(referexamplelisting5-
8), the BeanPostProcessor’s methods receive an instance of FixedDepositDaoImpl class and
myFixedDepositDaostringvalueasarguments.TheBeanPostProcessor’smethodsmayreturntheoriginal
bean instance as-is or they may modify the bean instance or they may return an object that wraps the
originalbeaninstance.
You configure a BeanPostProcessor implementation in the application context XML file like any other
Spring bean. Spring containerautomaticallydetects beans thatimplement BeanPostProcessor interface,
and createstheir instance before creating instance of any other bean defined in the application context
XML file. Once the BeanPostProcessor beans are created, the Spring container invokes each
BeanPostProcessor’spostProcessBeforeInitializationandpostProcessAfterInitializationmethodsforeach
beaninstancecreatedbytheSpringcontainer.
Let’s say that you have defined a singleton-scoped bean ABean and a BeanPostProcessor bean,
MyBeanPostProcessor, in theapplication context XML file. Figure 5-1 shows a sequence diagram that
depictsthesequenceinwhichMyBeanPostProcessor’smethodsareinvokedbytheSpringcontainer.
Theinitmethodcallinthesequencediagramrepresentsacalltotheinitializationmethodofthebean.The
sequence diagram shows that the MyBeanPostProcessor instance is created before the ABean bean
instance is created. As a BeanPostProcessor implementation is configured like any other bean, if
MyBeanPostProcessordefinesaninitializationmethod,containerinvokestheinitializationmethodofthe
MyBeanPostProcessorinstance.AfterABean’sinstanceiscreated,settermethodsoftheABeaninstance
areinvokedbytheSpringcontainertosatisfyitsdependencies,andtoprovidethebeaninstancewiththe
requiredconfigurationinformation.Afterpropertiesareset,butbeforeABean’sinitializationmethodis
invoked, the Spring container invokes MyBeanPostProcessor’s postProcessBeforeInitialization method.
After ABean’s initialization method is invoked, MyBeanPostProcessor’s postProcessAfterInitialization
methodiscalledbytheSpringcontainer.
Figure 5-1 – The Spring container invokes MyBeanPostProcessor’s methods before and after the
initializationofABean’sinitializationmethod
It’s only after invocation of postProcessAfterInitialization method, a bean instance is considered
completely initialized by the Spring container. For instance, if a BBean bean is dependent on ABean,
container will inject ABean instance into BBean only after MyBeanPostProcessor’s
postProcessAfterInitializationisinvokedforbothABeanandBBeaninstances.
YoushouldnotethatifthebeandefinitionforaBeanPostProcessorbeanspecifiesthatitshouldbelazily
created (refer <bean> element’s lazy-init attribute or <beans> element’s default-lazy-init attribute in
section 2-5 of chapter 2), the Spring container ignores lazy initialization configuration and creates the
BeanPostProcessor bean instance before creating instances of singleton-scoped beans defined in the
applicationcontextXMLfile.YoushouldnotethatthebeansthatimplementBeanFactoryPostProcessor
interface (explained in section 5-4) are created before the beans that implement BeanPostProcessor
interface.
Let’snowlookatsomeexamplescenariosinwhichyoucanuseSpring’sBeanPostProcessor.
IMPORT chapter 5/ch05-bankapp-beanpostprocessor (This project shows the MyBank application
that uses BeanPostProcessor implementations to validate bean instances and to resolve bean
dependencies.ToverifythattheBeanPostProcessorimplementationsfunctioncorrectly,executethemain
methodoftheBankAppclassofthisproject.)
BeanPostProcessorexample–Validatingbeaninstances
InaSpringapplication,youmaywanttoverifythatabeaninstanceisconfiguredcorrectlybeforeitis
injectedintodependentbeansoraccessedbyotherobjectsintheapplication.Let’sseehowwecanusea
BeanPostProcessor implementation to give an opportunity to each bean instance to validate its
configurationbeforethebeaninstanceismadeavailabletodependentbeansorotherapplicationobjects.
ThefollowingexamplelistingshowstheMyBank’sInstanceValidatorinterfacethatmustbeimplemented
bybeanswhoseconfigurationwewanttovalidateusingaBeanPostProcessorimplementation:
Examplelisting5-9–InstanceValidatorinterface
Project–ch05-bankapp-beanpostprocessor
Sourcelocation-src/main/java/sample/spring/chapter05/bankapp/common
packagesample.spring.chapter05.bankapp.common;
publicinterfaceInstanceValidator{
voidvalidateInstance();
}
InstanceValidatorinterfacedefinesavalidateInstancemethodthatverifieswhetherthebeaninstancewas
correctly initialized or not. We’ll soon see that the validateInstance method is invoked by a
BeanPostProcessorimplementation.
ThefollowingexamplelistingshowstheFixedDepositDaoImplclassthatimplementsInstanceValidator
interface:
Examplelisting5-10–FixedDepositDaoImplclass
Project–ch05-bankapp-beanpostprocessor
Sourcelocation-src/main/java/sample/spring/chapter05/bankapp/dao
packagesample.spring.chapter05.bankapp.dao;
importorg.apache.log4j.Logger;
importsample.spring.chapter05.bankapp.common.InstanceValidator;
publicclassFixedDepositDaoImplimplementsFixedDepositDao,InstanceValidator{
privatestaticLoggerlogger=Logger.getLogger(FixedDepositDaoImpl.class);
privateDatabaseConnectionconnection;
publicFixedDepositDaoImpl(){
logger.info("FixedDepositDaoImpl'sconstructorinvoked");
}
publicvoidinitializeDbConnection(){
logger.info("FixedDepositDaoImplísinitializeDbConnectionmethodinvoked");
connection=DatabaseConnection.getInstance();
}
@Override
publicvoidvalidateInstance(){
logger.info("ValidatingFixedDepositDaoImplinstance");
if(connection==null){
logger.error("FailedtoobtainDatabaseConnectioninstance");
}
}
}
Intheaboveexamplelisting,theinitializeDbConnectionmethodistheinitializationmethodthatretrieves
aninstanceofDatabaseConnectionbycallinggetInstancestaticmethodofDatabaseConnectionclass.The
connection attribute is null if FixedDepositDaoImpl instance fails to retrieve an instance of
DatabaseConnection. Ifconnection attribute is null, the validateInstance method logs an error message
indicating that the FixedDepositDaoImpl instance is not correctly initialized. As the
initializeDbConnection initialization method sets the value of connection attribute, the validateInstance
method must be invoked after the initializeDbConnection method. In a real world application
developmentscenario,ifabeaninstanceisnotconfiguredcorrectly,thevalidateInstancemethodmaytake
some corrective action or throw a runtime exception to stop the application from starting up. For
simplicity, the validateInstance method logs an error message if a bean instance is not configured
correctly.
The following example listing shows the InstanceValidationBeanPostProcessor class that implements
Spring’sBeanPostProcessorinterface,andisresponsibleforinvokingvalidateInstancemethodofnewly
createdbeans:
Examplelisting5-11–InstanceValidationBeanPostProcessorclass
Project–ch05-bankapp-beanpostprocessor
Sourcelocation-src/main/java/sample/spring/chapter05/bankapp/postprocessor
packagesample.spring.chapter05.bankapp.postprocessor;
importorg.springframework.beans.BeansException;
importorg.springframework.beans.factory.config.BeanPostProcessor;
importorg.springframework.core.Ordered;
publicclassInstanceValidationBeanPostProcessorimplementsBeanPostProcessor,Ordered{
privatestaticLoggerlogger=Logger.getLogger(InstanceValidationBeanPostProcessor.class);
privateintorder;
publicInstanceValidationBeanPostProcessor(){
logger.info("CreatedInstanceValidationBeanPostProcessorinstance");
}
@Override
publicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)
throwsBeansException{
logger.info("postProcessBeforeInitializationmethodinvoked");
returnbean;
}
@Override
publicObjectpostProcessAfterInitialization(Objectbean,StringbeanName)
throwsBeansException{
logger.info("postProcessAfterInitializationmethodinvoked");
if(beaninstanceofInstanceValidator){
((InstanceValidator)bean).validateInstance();
}
returnbean;
}
publicvoidsetOrder(intorder){
this.order=order;
}
@Override
publicintgetOrder(){
returnorder;
}
}
The above example listing shows that the InstanceValidationBeanPostProcessor class implements
Spring’sBeanPostProcessorandOrderedinterfaces.ThepostProcessBeforeInitializationmethodsimply
returnsthebeaninstancepassedtothemethod.InthepostProcessAfterInitializationmethod,ifthebean
instanceisfoundtobeoftypeInstanceValidator,thebeaninstance’svalidateInstancemethodisinvoked.
This means that if a bean implements InstanceValidator interface, InstanceValidationBeanPostProcessor
callsvalidateInstancemethodofthebeaninstanceaftertheinitializationmethodofthebeaninstanceis
invokedbytheSpringcontainer.
The Ordered interface defines a getOrder method which returns an integer value. The integer value
returned by the getOrder method determines the priority of a BeanPostProcessor implementation with
respectto other BeanPostProcessor implementations configured inthe applicationcontextXMLfile. A
BeanPostProcessorwithhigherordervalueisconsideredatalowerpriority,andisexecutedafterthe
BeanPostProcessorimplementationswithlowerordervaluesareexecuted.Aswewanttheintegervalue
returned by the getOrder method to be configured as a bean property, a setOrder method and an order
instancevariablearedefinedintheInstanceValidationBeanPostProcessorclass.
ThefollowingexamplelistingshowsbeandefinitionsforInstanceValidationBeanPostProcessorclass:
Examplelisting5-12–InstanceValidationBeanPostProcessorbeandefinition
Project–ch05-bankapp-beanpostprocessor
Sourcelocation-src/main/resources/META-INF/spring
<beanclass="…...bankapp.postprocessor.InstanceValidationBeanPostProcessor">
<propertyname="order"value="1"/>
</bean>
Intheabovebeandefinition,<bean>element’sidattributeisnot specified because we typically don’t
want InstanceValidationBeanPostProcessor to be a dependency of any other bean. The <property>
elementsetsthevalueoforderpropertyto1.
Let’snowlookataBeanPostProcessorimplementationthatisusedforresolvingbeandependencies.
BeanPostProcessorexample–Resolvingbeandependencies
In chapter 4, we saw that if a bean implements Spring’s ApplicationContextAware interface, it can
programmatically obtain bean instances using ApplicationContext’s getBean method. Implementing
ApplicationContextAwareinterfacecouplestheapplicationcodewithSpring,andforthatreasonitisnot
recommended to implement ApplicationContextAware interface. In this section, we’ll look at a
BeanPostProcessorimplementationthatprovidesbeanswithanobjectthatwrapsanApplicationContext
instance, resulting in application code that is not directly dependent on ApplicationContextAware and
ApplicationContextinterfacesofSpring.
ThefollowingexamplelistingshowstheMyBank’sDependencyResolverinterfacethatisimplementedby
beanswhowanttoprogrammaticallyretrievetheirdependenciesfromtheApplicationContext:
Examplelisting5-13–DependencyResolverinterface
Project–ch05-bankapp-beanpostprocessor
Sourcelocation-src/main/java/sample/spring/chapter05/bankapp/common
packagesample.spring.chapter05.bankapp.common;
publicinterfaceDependencyResolver{
voidresolveDependency(MyApplicationContextmyApplicationContext);
}
DependencyResolverdefinesaresolveDependencymethodthatacceptsaMyApplicationContextobject–
a wrapper around ApplicationContext object. We’ll soon see that the resolveDependency method is
invokedbyaBeanPostProcessorimplementation.
The following example listing shows the FixedDepositServiceImpl class that implements
DependencyResolverinterface:
Examplelisting5-14–FixedDepositServiceImplclass
Project–ch05-bankapp-beanpostprocessor
Sourcelocation-src/main/java/sample/spring/chapter05/bankapp/service
packagesample.spring.chapter05.bankapp.service;
importsample.spring.chapter05.bankapp.common.DependencyResolver;
importsample.spring.chapter05.bankapp.common.MyApplicationContext;
publicclassFixedDepositServiceImplimplementsFixedDepositService,DependencyResolver{
privateFixedDepositDaofixedDepositDao;
.....
@Override
publicvoidresolveDependency(MyApplicationContextmyApplicationContext){
FixedDepositDao=myApplicationContext.getBean(FixedDepositDao.class);
}
}
TheFixedDepositServiceImplclassdefinesaFixedDepositDaoattributeoftypeFixedDepositDao.The
resolveDependency method is responsible for obtaining an instance of FixedDepositDao object from
MyApplicationContext (a wrapper around Spring’s ApplicationContext object) and assigning it to the
FixedDepositDaoattribute.
The following example listing shows that the DependencyResolutionBeanPostProcessor class invokes
resolveDependencymethodonbeansthatimplementDependencyResolverinterface:
Examplelisting5-15–DependencyResolutionBeanPostProcessorclass
Project–ch05-bankapp-beanpostprocessor
Sourcelocation-src/main/java/sample/spring/chapter05/bankapp/postprocessor
packagesample.spring.chapter05.bankapp.postprocessor;
importorg.springframework.beans.factory.config.BeanPostProcessor;
importorg.springframework.core.Ordered;
importsample.spring.chapter05.bankapp.common.MyApplicationContext;
publicclassDependencyResolutionBeanPostProcessorimplementsBeanPostProcessor,
Ordered{
privateMyApplicationContextmyApplicationContext;
privateintorder;
publicvoidsetMyApplicationContext(MyApplicationContextmyApplicationContext){
this.myApplicationContext=myApplicationContext;
}
publicvoidsetOrder(intorder){
this.order=order;
}
@Override
publicintgetOrder(){
returnorder;
}
@Override
publicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)
throwsBeansException{
if(beaninstanceofDependencyResolver){
((DependencyResolver)bean).resolveDependency(myApplicationContext);
}
returnbean;
}
@Override
publicObjectpostProcessAfterInitialization(Objectbean,StringbeanName)
throwsBeansException{
returnbean;
}
}
The DependencyResolutionBeanPostProcessor class implements Spring’s BeanPostProcessor and
Ordered interfaces. The myApplicationContext attribute (of type MyApplicationContext) represents a
dependency of DependencyResolutionBeanPostProcessor. The postProcessBeforeInitialization method
invokes resolveDependency method on bean instances that implement DependencyResolver interface,
passingtheMyApplicationContextobjectasargument.ThepostProcessAfterInitializationmethodsimply
returnsthebeaninstancepassedtothemethod.
The following example listing shows the MyApplicationContext class that acts as a wrapper around
Spring’sApplicationContextobject:
Examplelisting5-16–MyApplicationContextclass
Project–ch05-bankapp-beanpostprocessor
Location-src/main/java/sample/spring/chapter05/bankapp/common
packagesample.spring.chapter05.bankapp.common;
importorg.springframework.context.ApplicationContext;
importorg.springframework.context.ApplicationContextAware;
publicclassMyApplicationContextimplementsApplicationContextAware{
privateApplicationContextapplicationContext;
@Override
publicvoidsetApplicationContext(ApplicationContextapplicationContext)
throwsBeansException{
this.applicationContext=applicationContext;
}
public<T>TgetBean(Class<T>klass){
returnapplicationContext.getBean(klass);
}
}
The MyApplicationContext class implements Spring’s ApplicationContextAware interface to obtain
reference to the ApplicationContext object in which the bean is deployed. The MyApplicationContext
class defines a getBean method that returns a bean instance with the given name from the
ApplicationContextinstance.
ThefollowingexamplelistingshowsthebeandefinitionsforDependencyResolutionBeanPostProcessor
andMyApplicationContextclasses:
Examplelisting5-17–applicationContext.xml
Project–ch05-bankapp-beanpostprocessor
Sourcelocation-src/main/resources/META-INF/spring
<beanclass=".....postprocessor.DependencyResolutionBeanPostProcessor">
<propertyname="myApplicationContext"ref="myApplicationContext"/>
<propertyname="order"value="0"/>
</bean>
<beanid="myApplicationContext"class=".....bankapp.common.MyApplicationContext"/>
The bean definition for DependencyResolutionBeanPostProcessor class shows that its order property
value is set to 0. Example listing 5-12 showed that the InstanceValidationBeanPostProcessor’s order
propertyvalueis1.Aslowerorderpropertyvaluemeanshigherpriority,theSpringcontainerapplies
DependencyResolutionBeanPostProcessor to a bean instance, followed by applying the
InstanceValidationBeanPostProcessor.
ThefollowingexamplelistingshowsthemainmethodofBankAppclassthatchecksthefunctionalityof
DependencyResolutionBeanPostProcessorandInstanceValidationBeanPostProcessor:
Examplelisting5-18–BankAppclass
Project–bankapp-beanpostprocessor
Location-src/main/java/sample/spring/chapter05/bankapp
packagesample.spring.chapter05.bankapp;
publicclassBankApp{
publicstaticvoidmain(Stringargs[])throwsException{
AbstractApplicationContextcontext=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
context.registerShutdownHook();
FixedDepositServiceFixedDepositService=context.getBean(FixedDepositService.class);
FixedDepositService.createFixedDeposit(newFixedDepositDetails(1,1000,12,
"someemail@somedomain.com"));
.....
}
}
BankApp’smainmethodretrievesaninstanceofFixedDepositServicefromtheApplicationContextand
executesFixedDepositService’screateFixedDepositmethod.WhenyouexecuteBankApp’smainmethod,
you’llnoticethattheSpringcontainercreatesinstanceofDependencyResolutionBeanPostProcessorand
InstanceValidationBeanPostProcessor beans before creating instance of any other bean defined in the
application context XML file. And, the DependencyResolutionBeanPostProcessor(order value 0) is
appliedtoanewlycreatedbeaninstancebeforetheInstanceValidationBeanPostProcessor(ordervalue1)
isapplied.
You should note that the Spring container doesn’t apply a BeanPostProcessor implementation to other
BeanPostProcessor implementations. For instance, in the MyBank application,
DependencyResolutionBeanPostProcessor’s postProcessBeforeInitializationand
postProcessAfterInitialization methods are not invoked by the Spring container when an instance of
InstanceValidationBeanPostProcessoriscreated.
Let’s now look at the behavior of a BeanPostProcessor implementation for a bean that implements
FactoryBeaninterface.
BeanPostProcessorbehaviorforFactoryBeans
In section 3-9 of chapter 3, we discussed that a bean that implements Spring’s FactoryBean interface
represents a factory for creating bean instances. The question that you might be asking at this time is
whether a BeanPostProcessor implementation applies to a FactoryBean implementation or to the bean
instances created by the FactoryBean implementation. Later in this section, we’ll see that a
BeanPostProcessor’s postProcessBeforeInitialization and postProcessAfterInitialization methods are
invoked for a FactoryBean instance created by the Spring container. And, only
postProcessAfterInitializationmethodisinvokedforbeaninstancescreatedbyaFactoryBean.
ThefollowingexamplelistingshowstheEventSenderFactoryBean(aFactoryBeanimplementation)class
ofMyBankapplicationthatcreatesinstancesofEventSenderbean:
Examplelisting5-19–EventSenderFactoryBeanclass
Project–ch05-bankapp-beanpostprocessor
Location-src/main/java/sample/spring/chapter05/bankapp/factory
packagesample.spring.chapter05.bankapp.factory;
importorg.springframework.beans.factory.FactoryBean;
importorg.springframework.beans.factory.InitializingBean;
publicclassEventSenderFactoryBeanimplementsFactoryBean<EventSender>,InitializingBean{
.....
@Override
publicEventSendergetObject()throwsException{
logger.info("getObjectmethodofEventSenderFactoryBeaninvoked");
returnnewEventSender();
}
@Override
publicClass<?>getObjectType(){
returnEventSender.class;
}
@Override
publicbooleanisSingleton(){
returnfalse;
}
@Override
publicvoidafterPropertiesSet()throwsException{
logger.info("afterPropertiesSetmethodofEventSenderFactoryBeaninvoked");
}
}
EventSenderFactoryBean class implements Spring’s InitializingBean and FactoryBean interfaces. The
getObject method returns an instance of EventSender object. As the isSingleton method returns false,
EventSenderFactoryBean’s getObject method is invoked each time EventSenderFactoryBean receives
requestforanEventSenderobject.
The following example listing shows the main method of BankApp class of ch05-bankapp-
beanpostprocessorprojectthatretrievesEventSenderinstancesfromtheEventSenderFactoryBean:
Examplelisting5-20–BankAppclass
Project–ch05-bankapp-beanpostprocessor
Location-src/main/java/sample/spring/chapter05/bankapp
packagesample.spring.chapter05.bankapp;
publicclassBankApp{
publicstaticvoidmain(Stringargs[])throwsException{
AbstractApplicationContextcontext=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
context.registerShutdownHook();
.....
context.getBean("eventSenderFactory");
context.getBean("eventSenderFactory");
}
}
In the above example listing, the ApplicationContext’sgetBean method is called twice to retrieve two
distinct EventSender instances from the EventSenderFactoryBean. If you execute BankApp’s main
method,you’llseethefollowingmessagesprintedontheconsole:
CreatedEventSenderFactoryBean
DependencyResolutionBeanPostProcessor'spostProcessBeforeInitializationmethodinvokedfor.....EventSenderFactoryBean
InstanceValidationBeanPostProcessor'spostProcessBeforeInitializationmethodinvokedfor.....EventSenderFactoryBean
afterPropertiesSetmethodofEventSenderFactoryBeaninvoked
DependencyResolutionBeanPostProcessor'spostProcessAfterInitializationmethodinvokedfor.....EventSenderFactoryBean
InstanceValidationBeanPostProcessor'spostProcessAfterInitializationmethodinvokedforbean.....EventSenderFactoryBean
The above output shows that a BeanPostProcessor’s postProcessBeforeInitialization and
postProcessAfterInitializationmethodsareinvokedfortheEventSenderFactoryBeaninstancecreatedby
theSpringcontainer.
ExecutionofBankApp’smainmethodalsoshowsthefollowingoutputontheconsole:
getObjectmethodofEventSenderFactoryBeaninvoked
DependencyResolutionBeanPostProcessor'spostProcessAfterInitializationmethodinvokedfor.....EventSender
getObjectmethodofEventSenderFactoryBeaninvoked
DependencyResolutionBeanPostProcessor'spostProcessAfterInitializationmethodinvokedfor.....EventSender
The above output shows that onlythepostProcessAfterInitialization method of a BeanPostProcessor is
invokedfortheEventSenderinstancecreatedbytheEventSenderFactoryBean.Ifyouwant,youcanmake
modificationstoanEventSenderinstanceinthepostProcessAfterInitializationmethod.
Let’snowlookatSpring’sbuilt-inRequiredAnnotationBeanPostProcessorthatyoucanusetoensurethat
required(ormandatory)beanpropertiesareconfiguredintheapplicationcontextXMLfile.
RequiredAnnotationBeanPostProcessor
If the setter-method for a bean property is annotated with Spring’s @Required annotation, Spring’s
RequiredAnnotationBeanPostProcessor (a BeanPostProcessor implementation) checks if the bean
propertyisconfiguredintheapplicationcontextXMLfile.
NOTEYoushouldnotethattheRequiredAnnotationBeanPostProcessorisnotautomaticallyregistered
withtheSpringcontainer,youneedtoregisteritexplicitlybydefiningitintheapplicationcontextXML
file.
Thefollowingexamplelistingshowsanexampleusageof@Requiredannotation:
Examplelisting5-21–@Requiredannotationusage
importorg.springframework.beans.factory.annotation.Required;
publicclassFixedDepositServiceImplimplementsFixedDepositService{
privateFixedDepositDaofixedDepositDao;
@Required
publicvoidsetFixedDepositDao(FixedDepositDaofixedDepositDao){
this.fixedDepositDao=fixedDepositDao;
}
.....
}
In the above example listing, the setFixedDepositDao setter-method for FixedDepositDao property is
annotatedwith@Requiredannotation.IfyouhavedefinedRequiredAnnotationBeanPostProcessorinthe
applicationcontextXMLfile,theRequiredAnnotationBeanPostProcessorwillcheckifyouhavespecified
a<property>element(orusedp-namespace)tosetthevalueofFixedDepositDaoproperty.Ifyouhaven’t
configuredtheFixedDepositDaopropertyinthebeandefinitionfortheFixedDepositServiceImplclassin
the application context XML file, it’ll result in an exception. This shows that you can use
RequiredAnnotationBeanPostProcessor to ensure that all bean instances in your application are
configuredproperlyintheapplicationcontextXMLfile.
RequiredAnnotationBeanPostProcessor only ensures that a bean property is configured in the bean
definition.Itdoesn’tensurethattheconfiguredpropertyvalueiscorrect.Forinstance,youcanconfigurea
property’s value as null, instead of a valid value. For this reason, beans may still need to implement
initializationmethodstocheckifthepropertiesarecorrectlyset.
Let’s now look at Spring’s DestructionAwareBeanPostProcessor interface that is a sub-interface of
Spring’sBeanPostProcessorinterface.
DestructionAwareBeanPostProcessor
SofarwehaveseenthataBeanPostProcessorimplementationisusedforinteractingwithnewlycreated
bean instances. In some scenarios you may also want to interact with a bean instance before it is
destroyed. To interact with a bean instance before it is destroyed, configure a bean that implements
Spring’s DestructionAwareBeanPostProcessor interface in the application context XML file.
DestructionAwareBeanPostProcessor is asub-interface ofBeanPostProcessor interface and defines the
followingmethod:
voidpostProcessBeforeDestruction(Objectbean,StringbeanName)
ThepostProcessBeforeDestructionmethodacceptsthebeaninstance,whichisabouttobedestroyedby
the Spring container, and its name as arguments. Spring container invokes the
postProcessBeforeDestructionmethodforeachsingleton-scopedbeaninstancebeforethebeaninstanceis
destroyedbytheSpringcontainer.Usually, the postProcessBeforeDestructionmethodisused toinvoke
custom destruction methods on the bean instances. It is important to note that the
postProcessBeforeDestructionmethodisnotcalledforprototype-scopedbeans.
We’llnowlookatSpring’sBeanFactoryPostProcessorinterface,whichallowsyoutomakemodifications
tobeandefinitions.
5-4ModifyingbeandefinitionsusingBeanFactoryPostProcessor
Spring’sBeanFactoryPostProcessorinterfaceisimplementedbyclassesthatwanttomakemodifications
to bean definitions. A BeanFactoryPostProcessor is executed after bean definitions are loaded by the
Springcontainer,butbeforeanybeaninstanceiscreated.ABeanFactoryPostProcessoriscreatedbefore
any other bean defined in the application context XML file, giving the BeanFactoryPostProcessor an
opportunity to make modifications to bean definitions of other beans. You configure a
BeanFactoryPostProcessorimplementationintheapplicationcontextXMLfilelikeanyotherSpringbean.
NOTEInsteadofbeandefinitions,ifyouwanttomodifyorinteractwithbeaninstances,usea
BeanPostProcessor(refertosection5-3)andnotaBeanFactoryPostProcessor.
BeanFactoryPostProcessor interface defines a single method - postProcessBeanFactory. This method
acceptsanargumentoftypeConfigurableListableBeanFactorythatcanbeusedtoobtainandmodifybean
definitions loaded by the Spring container. It is possible to create a bean instance inside
postProcessBeanFactorymethoditselfbycallingConfigurableListableBeanFactory’sgetBeanmethod,but
bean creation inside postProcessBeanFactory method is not recommended. It is important to note that
BeanPostProcessors (refer section 5-3) are not executed for bean instances created inside
postProcessBeanFactorymethod.
ItisimportanttonotethataConfigurableListableBeanFactoryprovidesaccesstotheSpringcontainerjust
like the ApplicationContext object. ConfigurableListableBeanFactory additionally allows you to
configure the Spring container, iterate over beans, and modify bean definitions. For instance, using
ConfigurableListableBeanFactoryobjectyoucanregisterPropertyEditorRegistrars(refersection3-6of
chapter 3), register BeanPostProcessors, and so on. Later in this section, we’ll see how
ConfigurableListableBeanFactoryobjectisusedtomodifybeandefinitions.
Let’snowlookathowwecanuseaBeanFactoryPostProcessortomodifybeandefinitions.
IMPORT chapter 5/ch05-bankapp-beanfactorypostprocessor (This project shows the MyBank
application that uses a BeanFactoryPostProcessor implementation to disable autowiring across the
application,andloganerrormessageifasingleton-scopedbeanisfoundtobedependentonaprototype-
scopedbean.ToverifythattheBeanFactoryPostProcessorimplementationfunctionscorrectly,executethe
mainmethodoftheBankAppclassofthisproject.)
BeanFactoryPostProcessorexample
In the previous chapter, we saw that autowiring hides the overall structure of the application (refer
section4-6of chapter4). Wealsodiscussedthat insteadofusing<property> elementtospecifythata
singleton-scoped bean is dependent on a prototype-scoped bean, you should use <lookup-method> or
<replaced-method>element(refersection4-4and4-5ofchapter4formoredetails)toprogrammatically
obtain a prototype-scoped dependency of a singleton-bean. We’ll now look at a
BeanFactoryPostProcessor implementation that makes beans unavailable for autowiring (refer <bean>
element’sautowire-candidateattributedescribedinsection4-6ofchapter4)andlogsanerrormessageif
itfindsasingleton-scopedbeanisdependentonaprototype-scopedbean.Forsimplicity,weassumethat
asingleton-scopedbeanuses<property> elementtospecifythat itis dependenton aprototype-scoped
bean.
NOTEAbeanthatimplementsSpring’sBeanFactoryPostProcessorinterfaceisaspecialbeantype;the
SpringcontainerautomaticallydetectsandexecutesaBeanFactoryPostProcessorbean.
The following example listing shows the MyBank’s ApplicationConfigurer class that implements
BeanFactoryPostProcessorinterface:
Examplelisting5-22–ApplicationConfigurerclass–aBeanFactoryPostProcessorimplementation
Project–ch05-bankapp-beanfactorypostprocessor
Sourcelocation-src/main/java/sample/spring/chapter05/bankapp/postprocessor
packagesample.spring.chapter05.bankapp.postprocessor;
importorg.springframework.beans.factory.config.BeanDefinition;
importorg.springframework.beans.factory.config.BeanFactoryPostProcessor;
importorg.springframework.beans.factory.config.ConfigurableListableBeanFactory;
publicclassApplicationConfigurerimplementsBeanFactoryPostProcessor{
publicApplicationConfigurer(){
logger.info("CreatedApplicationConfigurerinstance");
}
@Override
publicvoidpostProcessBeanFactory(
ConfigurableListableBeanFactorybeanFactory)throwsBeansException{
String[]beanDefinitionNames=beanFactory.getBeanDefinitionNames();
//--getallthebeandefinitions
for(inti=0;i<beanDefinitionNames.length;i++){
StringbeanName=beanDefinitionNames[i];
BeanDefinitionbeanDefinition=beanFactory.getBeanDefinition(beanName);
beanDefinition.setAutowireCandidate(false);
//--obtaindependenciesofabean
if(beanDefinition.isSingleton()){
if(hasPrototypeDependency(beanFactory,beanDefinition)){
logger.error("Singleton-scoped"+beanName
+"beanisdependentonaprototype-scopedbean.");
}
}
}
}
.....
}
ThefollowingsequenceofactionsisperformedbythepostProcessBeanFactorymethod:
1. First, the postProcessBeanFactory method calls ConfigurableListableBeanFactory’s
getBeanDefinitionNamesmethodtoobtain namesofallthebeandefinitionsloadedbytheSpring
container.Youshouldnotethatthenameofabeandefinitionisthevalueof<bean>element’sid
attribute.
2. Once the names of all the bean definitions are obtained, the postProcessBeanFactory method
invokesConfigurableListableBeanFactory’sgetBeanDefinitionmethodtoobtaintheBeanDefinition
object corresponding to each bean definition. The getBeanDefinition method accepts a bean
definitionname(obtainedinstep1)asargument.
3. A BeanDefinition object represents a bean definition, and can be used to modify bean
configuration.ForeachbeandefinitionloadedbytheSpringcontainer,thepostProcessBeanFactory
methodinvokesBeanDefinition’ssetAutowireCandidatemethodtomakeallthebeansunavailable
forautowiring.
4. BeanDefinition’sisSingleton methodreturns true if a bean definition is for a singleton-scoped
bean. If a bean definition is for a singleton-scoped bean, the postProcessBeanFactory method
invokeshasPrototypeDependencymethodtocheckifthesingleton-scopedbeanisdependentonany
prototype-scopedbean.And,ifthesingleton-scopedbeanisdependentonaprototype-scopedbean,
thepostProcessBeanFactorymethodlogsanerrormessage.
The following example listing shows the implementation of ApplicationConfigurer’s
hasPrototypeDependencymethodthatreturnstrueifabeanisdependentonaprototype-scopedbean:
Examplelisting5-23–ApplicationConfigurer’shasPrototypeDependencymethod
Project–ch05-bankapp-beanfactorypostprocessor
Sourcelocation-src/main/java/sample/spring/chapter05/bankapp/postprocessor
importorg.springframework.beans.MutablePropertyValues;
importorg.springframework.beans.PropertyValue;
importorg.springframework.beans.factory.config.RuntimeBeanReference;
publicclassApplicationConfigurerimplementsBeanFactoryPostProcessor{
.....
privatebooleanhasPrototypeDependency(ConfigurableListableBeanFactorybeanFactory,
BeanDefinitionbeanDefinition){
booleanisPrototype=false;
MutablePropertyValuesmutablePropertyValues=beanDefinition.getPropertyValues();
PropertyValue[]propertyValues=mutablePropertyValues.getPropertyValues();
for(intj=0;j<propertyValues.length;j++){
if(propertyValues[j].getValue()instanceofRuntimeBeanReference){
StringdependencyBeanName=((RuntimeBeanReference)propertyValues[j]
.getValue()).getBeanName();
BeanDefinitiondependencyBeanDef=beanFactory
.getBeanDefinition(dependencyBeanName);
if(dependencyBeanDef.isPrototype()){
isPrototype=true;
break;
}
}
}
returnisPrototype;
}
}
The hasPrototypeDependency method checks if the bean represented by BeanDefinition argument is
dependentonaprototype-scopedbean.TheConfigurableListableBeanFactoryargumentprovidesaccess
to bean definitions loaded bytheSpring container. Thefollowingsequence of actions is performedby
hasPrototypeDependencymethod to find if the bean represented by the BeanDefinition argument has a
prototype-scopeddependency:
1.First,hasPrototypeDependencymethodcallsBeanDefinition’sgetPropertyValuesmethodtoobtain
bean properties defined by <property> elements. BeanDefinition’s getPropertyValues returns an
objectoftypeMutablePropertyValueswhichyoucanusetomodifybeanproperties.Forinstance,
you can add additional properties to the bean definition by using addPropertyValue and
addPropertyValuesmethodsofMutablePropertyValues.
2. As we want to iterate over all the bean properties and check if any bean property refers to a
prototype-scoped bean, the getPropertyValues method ofMutablePropertyValues is invoked to
retrieveanarrayofPropertyValueobjects.APropertyValueobjectholdsinformationaboutabean
property.
3. If abeanproperty refers to a Spring bean, calling PropertyValue’sgetValue method returns an
instance of RuntimeBeanReferenceobject that holds name of the referenced bean. As we are
interested in bean properties that reference Spring beans, the return value of PropertyValue’s
getValuemethodischeckedifitrepresentsaninstanceofRuntimeBeanReferencetype.Ifitdoes,
theobjectreturnedbyPropertyValue’sgetValuemethodiscasttoRuntimeBeanReferencetype,and
thenameofthereferencedbeanisobtainedbycallingtheRuntimeBeanReference’sgetBeanName
method.
4. Now, that we have the name of the bean referenced by the bean property, the BeanDefinition
object for the referenced bean is obtained by calling ConfigurableListableBeanFactory’s
getBeanDefinition method. You can check if the referenced bean is a prototype-scoped bean by
callingBeanDefinition’sisPrototypemethod.
ThefollowingsequencediagramsummarizeshowhasPrototypeDependencymethodworks:
Figure5-2–hasPrototypeDependencymethoditeratesoverbeandefinitionsofdependencies,andreturns
trueifaprototype-scopeddependencyisfound
In the above sequence diagram ConfigurableListableBeanFactory object has been depicted as ‘Bean
factory’object.
The following example listing shows the application context XML file of ch05-bankapp-
beanfactorypostprocessor project that contains bean definitions for ApplicationConfigurer class (a
BeanFactoryPostProcessor implementation), InstanceValidationBeanPostProcessor class (a
BeanPostProcessorimplementation),alongwithbeandefinitionsforapplication-specificobjects:
Examplelisting5-24–applicationContext.xml-BeanFactoryPostProcessorbeandefinition
Project–ch05-bankapp-beanfactorypostprocessor
Sourcelocation-src/main/resources/META-INF/spring
<beans.....>
.....
<beanid="FixedDepositDao"
class="sample.spring.chapter05.bankapp.dao.FixedDepositDaoImpl".....>
<propertyname=“fixedDepositDetails"ref="FixedDepositDetails"/>
</bean>
<beanid="FixedDepositDetails"
class="sample.spring.chapter05.bankapp.domain.FixedDepositDetails"
scope="prototype"/>
<beanclass=".....postprocessor.InstanceValidationBeanPostProcessor">
<propertyname="order"value="1"/>
</bean>
<bean
class="sample.spring.chapter05.bankapp.postprocessor.ApplicationConfigurer"/>
</beans>
In the bean definitions shown above, the singleton-scoped FixedDepositDao bean is dependent on the
prototype-scopedFixedDepositDetailsbean.
If you execute the main method of BankApp class of ch05-bankapp-beanfactorypostprocessor project,
you’llseethefollowingoutputontheconsole:
CreatedApplicationConfigurerinstance
Singleton-scopedFixedDepositDaobeanisdependentonaprototype-scopedbean.
CreatedInstanceValidationBeanPostProcessorinstance
The above output shows that the Spring container creates ApplicationConfigurer (a
BeanFactoryPostProcessor) and executes ApplicationConfigurer’s postProcessBeanFactory method
beforecreatingInstanceValidationBeanPostProcessor(aBeanPostProcessor) instance.Itis importantto
note that the beans that implement the BeanFactoryPostProcessor interface are processed before beans
thatimplementtheBeanPostProcessorinterface.Forthisreason,youcan’tuseaBeanPostProcessor to
make modifications to a BeanFactoryPostProcessor instance. The BeanFactoryPostProcessor gives you
the opportunity to modify bean definitions loaded by the Spring container, and the
BeanFactoryPostProcessor gives you the opportunity to make modifications to newly created bean
instances.
Let’snowlookatsomeofthesimilaritiesbetweenBeanPostProcessorsandBeanFactoryPostProcessors:
· youcanconfiguremultiple BeanFactoryPostProcessors intheapplicationcontext XML file. To
control the order in which BeanFactoryPostProcessors are executed by the Spring container,
implementSpring’sOrderedinterface(refersection5-3toknowmoreaboutOrderedinterface).
· evenifyouspecify thataBeanFactoryPostProcessor implementationis lazily initialized by the
Spring container, BeanFactoryPostProcessors are created when the Spring container instance is
created.
In chapter 3, we looked at CustomEditorConfigurer – a BeanFactoryPostProcessor implementation that
Spring provides out-of-the-box for registering custom property editors. Let’s now look at some more
BeanFactoryPostProcessorimplementationsthatSpringprovidesout-of-the-box.
PropertySourcesPlaceholderConfigurer
Sofarwehaveseenbeandefinitionexamplesinwhich<property>or<constructor-arg>element’svalue
attribute is used to specify the actual string value of a bean property or a constructor argument.
PropertySourcesPlaceholderConfigurer(aBeanFactoryPostProcessor)let’syouspecifytheactualstring
valueofbeanpropertiesandconstructorargumentsinapropertiesfile.Inthebeandefinition,youonly
specify property placeholders (of the form ${<property_name_in_properties_file>}) as the value of
<property> or <constructor-arg> element’s value attribute. When bean definitions are loaded by the
Springcontainer,thePropertySourcesPlaceholderConfigurer pullsthe actual values fromthe properties
fileandreplacesthepropertyplaceholdersinthebeandefinitionswithactualvalues.
IMPORT chapter 5/ch05-propertySourcesPlaceholderConfigurer-example (This project shows a
SpringapplicationthatusesSpring’sPropertySourcesPlaceholderConfigurertosetbeanpropertiesfrom
the properties specified in external properties files. To verify that the
PropertySourcesPlaceholderConfigurerfunctions correctly, execute the main method of the SampleApp
classofthisproject.)
The following example listing shows bean definitions for DataSource and WebServiceConfiguration
classesthatusepropertyplaceholders:
Examplelisting5-25–applicationContext.xml-Beandefinitionsthatusepropertyplaceholders
Project–ch05-propertySourcesPlaceholderConfigurer-example
Sourcelocation-src/main/resources/META-INF/spring
<beanid="datasource"class="sample.spring.chapter05.domain.DataSource">
<propertyname="url"value="${database.url}"/>
<propertyname="username"value="${database.username}"/>
<propertyname="password"value="${database.password}"/>
<propertyname="driverClass"value="${database.driverClass}"/>
</bean>
<beanid="webServiceConfiguration"
class="sample.spring.chapter05.domain.WebServiceConfiguration">
<propertyname="webServiceUrl"value="${webservice.url}"/>
</bean>
The above example listing shows that each <property> element’s value attribute specifies a property
placeholder. When bean definitions are loaded by the Spring container,
PropertySourcesPlaceholderConfigurer replaces property placeholders with values from a properties
file. For instance, if a database.username property is defined in a properties file, the value of
database.usernamepropertyreplacesthe${database.username}propertyplaceholderofdataSourcebean.
The bean definition for the PropertySourcesPlaceholderConfigurer specifies properties files to be
searchedforfindingreplacementforapropertyplaceholder,asshowninthefollowingexamplelisting:
Examplelisting5-26–applicationContext.xml-PropertySourcesPlaceholderConfigurerbeandefinition
Project–ch05-propertySourcesPlaceholderConfigurer-example
Sourcelocation-src/main/resources/META-INF/spring
<bean
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<propertyname="locations">
<list>
<value>classpath:database.properties</value>
<value>classpath:webservice.properties</value>
</list>
</property>
<propertyname="ignoreUnresolvablePlaceholders"value="false"/>
</bean>
PropertySourcesPlaceholderConfigurer’slocationspropertyspecifiespropertiesfilestobesearchedfor
finding the value for a property placeholder. In the above example listing,
PropertySourcesPlaceholderConfigurerlooks for the value of a property placeholder in
database.properties and webservice.properties files. The ignoreUnresolvablePlaceholdersproperty
specifieswhetherPropertySourcesPlaceholderConfigurersilentlyignoresorthrowsanexceptionincase
apropertyplaceholdervalueisnotfoundinanyofthepropertiesfilesspecifiedbythelocationsproperty.
ThevaluefalseindicatesthatthePropertySourcesPlaceholderConfigurerwillthrowanexceptionifvalue
forapropertyplaceholderisnotfoundindatabase.propertiesorwebservice.propertiesfiles.
The following example listing shows the properties defined in database.properties and
webservice.propertiesfiles:
Examplelisting5-27–Propertiesdefinedindatabase.propertiesandwebservice.propertiesfiles
Project–ch05-propertySourcesPlaceholderConfigurer-example
Sourcelocation-src/main/resources/META-INF
----------------database.propertiesfile------------------
database.url=some_url
database.username=some_username
database.password=some_password
database.driverClass=some_driverClass
----------------webservice.propertiesfile------------------
webservice.url=some_url
If you compare the properties defined in database.properties and webservice.properties files with the
property placeholders specified in datasource and webServiceConfiguration bean definitions (refer
examplelisting5-25),you’llnoticethatforeachpropertyplaceholderapropertyisdefinedinoneofthe
propertiesfiles.
Themainmethod of SampleApp class of ch05-propertySourcesPlaceholderConfigurer-example project
retrievesWebServiceConfigurationand DataSource beans from the ApplicationContext and prints their
propertiesontheconsole.IfyouexecuteSampleApp’smainmethod,you’llseethefollowingoutputon
theconsole:
DataSource[url=some_url,username=some_username,password=some_password,driverClass=some_driverClass]
WebServiceConfiguration[webServiceUrl=some_url]
Theaboveoutputshows:
· DataSource’s url property is set to some_url, username to some_username, password to
some_passwordanddriverClasstosome_driverClass.
·WebServiceConfiguration’swebServiceUrlpropertyissettosome_url.
If you remove a property from either database.properties or webservice.properties file, executing
SampleApp’smainmethodwillresultinanexception.
Let’snowlookatlocalOverridepropertyofPropertySourcesPlaceholderConfigurer.
localOverrideproperty
Ifyouwantlocalproperties(setvia<props>element)tooverridepropertiesreadfrompropertiesfile,
youcansetPropertySourcesPlaceholderConfigurer’slocalOverridepropertytotrue.
IMPORT chapter 5/ch05-localoverride-example (This project shows a Spring application that uses
PropertySourcesPlaceholderConfigurer’slocalOverrideproperty.Toruntheapplication,executethemain
methodoftheSampleAppclassofthisproject.)
The following example listing shows bean definitions for DataSource and WebServiceConfiguration
classes:
Examplelisting5-28–applicationContext.xml-Beandefinitionsthatusepropertyplaceholders
Project–ch05-localOverride-example
Sourcelocation-src/main/resources/META-INF/spring
<beanid="datasource"class="sample.spring.chapter05.domain.DataSource">
<propertyname="url"value="${database.url}"/>
<propertyname="username"value="${database.username}"/>
<propertyname="password"value="${database.password}"/>
<propertyname="driverClass"value="${database.driverClass}"/>
</bean>
<beanid="webServiceConfiguration"
class="sample.spring.chapter05.domain.WebServiceConfiguration">
<propertyname="webServiceUrl"value="${webservice.url}"/>
</bean>
The bean definitions for DataSource and WebServiceConfiguration classes are same as we saw in
examplelisting5-25.
The following example listing shows the properties defined in database.properties and
webservice.propertiesfiles:
Examplelisting5-29–Propertiesdefinedindatabase.propertiesandwebservice.propertiesfiles
Project–ch05-localOverride-example
Sourcelocation-src/main/resources/META-INF
----------------database.propertiesfile------------------
database.url=some_url
database.username=some_username
----------------webservice.propertiesfile------------------
webservice.url=some_url
If you compare the properties defined in database.properties and webservice.properties files with the
property placeholders specified in datasource and webServiceConfiguration bean definitions (refer
example listing 5-28), you’ll notice that properties are not defined for ${database.password} and
${database.driverClass}placeholdersinthedatabase.propertiesfile.
The following example listing shows the bean definition for PropertySourcesPlaceholderConfigurer
class:
Examplelisting5-30–applicationContext.xml-PropertySourcesPlaceholderConfigurerbeandefinition
Project–ch05-localOverride-example
Sourcelocation-src/main/resources/META-INF/spring
<bean
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<propertyname="locations">
<list>
<value>classpath:database.properties</value>
<value>classpath:webservice.properties</value>
</list>
</property>
<propertyname="properties">
<props>
<propkey="database.password">locally-set-password</prop>
<propkey="database.driverClass">locally-set-driverClass</prop>
<propkey="webservice.url">locally-set-webServiceUrl</prop>
</props>
</property>
<propertyname="ignoreUnresolvablePlaceholders"value="false"/>
<propertyname="localOverride"value="true"/>
</bean>
The properties property of PropertySourcesPlaceholderConfigurer defines local properties. The
database.password, database.driverClass and webservice.url properties are local properties. The
localOverride property specifies whether local properties take precedence over properties read from
externalpropertiesfiles.AsthevalueoflocalOverridepropertyistrue,localpropertiestakeprecedence.
The main method of SampleApp class in ch05-localOverride-example project retrieves
WebServiceConfigurationandDataSourcebeansfromtheApplicationContextandprintstheirproperties
ontheconsole.IfyouexecuteSampleApp’smainmethod,you’llseethefollowingoutputontheconsole:
DataSource[url=some_url,username=some_username,password=locally-set-password,driverClass=locally-set-driverClass]
WebServiceConfiguration[webServiceUrl=locally-set-webServiceUrl]
The output shows that the value of DataSource’s password and driverClass properties are locally-set-
password and locally-set-driverClass, respectively. This means that the values for DataSource’s
password and driverClass properties come from the local properties defined by the
PropertySourcesPlaceholderConfigurer bean (refer example listing 5-30). This shows that if the
PropertySourcesPlaceholderConfigurercan’tfindapropertyforaplaceholderintheexternalproperties
files, it searches for the property in the local properties defined by
PropertySourcesPlaceholderConfigurerbean.TheoutputalsoshowsthattheWebServiceConfiguration’s
webServiceUrl property value comes from the local properties defined by the
PropertySourcesPlaceholderConfigurer bean (refer example listing 5-30). The value of
PropertySourcesPlaceholderConfigurer’s localOverride property is set to true; therefore, the locally
defined webservice.url property takes precedence over the webservice.url property read from the
webservice.propertiesfile.
NOTEInsteadofusingPropertySourcesPlaceholderConfigurer’spropertiesproperty,youcanuse
<properties>elementofSpring’sutilschema(refersection3-8ofchapter3)orPropertiesFactoryBean
(refersection3-8ofchapter3)todefinelocalproperties.
Instead of directly configuring the PropertySourcesPlaceholderConfigurer bean in your application
context XML file, you can use the <property-placeholder> element of Spring’s context schema. The
<property-placeholder>elementconfiguresaPropertySourcesPlaceholderConfigurerinstance.Let’snow
lookatthe<property-placeholder>elementindetail.
IMPORT chapter 5/ch05-property-placeholder-element-example (This project shows a Spring
applicationthatusesthe<property-placeholder>element.Toruntheapplication,executethemainmethod
oftheSampleAppclassofthisproject.)
<property-placeholder>element
The following example listing shows how the <property-placeholder> element is used to configure a
PropertySourcesPlaceholderConfigurerinstancewiththesameconfigurationastheoneweconfiguredin
examplelisting5-30:
Examplelisting5-31–applicationContext.xml-<property-placeholder>element
Project–ch05-property-placeholder-element-example
Sourcelocation-src/main/resources/META-INF/spring
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util".....>
…..
<context:property-placeholderignore-unresolvable="false"
location="classpath:database.properties,classpath:webservice.properties"
local-override="true"order="1"properties-ref="localProps"/>
<util:propertiesid="localProps">
<propkey="database.password">locally-set-password</prop>
<propkey="database.driverClass">locally-set-driverClass</prop>
<propkey="webservice.url">locally-set-webServiceUrl</prop>
</util:properties>
</beans>
In the above example listing, reference to Spring’s context schema is included so that its elements are
accessible.Theaboveexamplelistingshowsthattheuseof<property-placeholder>elementresultsina
lessverboseconfigurationofPropertySourcesPlaceholderConfigurer.Theignore-unresolvable,location
andlocal-overrideattributescorrespondtoignoreUnresolvablePlaceholders,locationsandlocalOverride
properties of PropertySourcesPlaceholderConfigurer. As the PropertySourcesPlaceholderConfigurer
classimplementsSpring’sOrderedinterface,theorderattribute’svalueisusedtosettheorderproperty
of PropertySourcesPlaceholderConfigurer instance. The properties-ref attribute refers to a
java.util.Properties object that represents the local properties. In the above example listing, the
<properties> element of Spring’s util schema (refer section 3-8 of chapter 3) creates an instance of
java.util.Propertiesobject,whichisreferencedbytheproperties-refattributeof<property-placeholder>
element.
Let’snowlookatSpring’sPropertyOverrideConfigurer(aBeanFactoryPostProcessor)whichallowsyou
tospecifyvaluesforbeanpropertiesinexternalpropertiesfiles.
PropertyOverrideConfigurer
PropertyOverrideConfigurer is similar to PropertySourcesPlaceholderConfigurer in the sense that it
allows you to specify a bean property value in external properties file. When using
PropertyOverrideConfigurer, bean property value is specified in the following format in external
propertiesfiles:
<bean-name>.<bean-property-name>=<value>
here,<bean-name>isthenameofthebean,<bean-property-name>isthenameofthebeanproperty,
and<value>isthevaluethatyouwanttoassigntothebeanproperty.
ThenotabledifferencesbetweenPropertyOverrideConfigurerandPropertySourcesPlaceholderConfigurer
classesare:
·YoucanusePropertyOverrideConfigureronlyforexternalizingvaluesofbeanproperties,thatis,
youcan’tusePropertyOverrideConfigurertoexternalizevaluesofconstructorarguments.
·PropertySourcesPlaceholderConfigurerdoesn’tprovideyouwithanoptiontospecifydefault
values for properties. But, PropertyOverrideConfigurer allows you to specify default values for
beanproperties.
Let’snowlookatanexampleusageofPropertyOverrideConfigurer.
IMPORT chapter 5/ch05-propertyOverrideConfigurer-example (This project shows a Spring
application that uses Spring’s PropertyOverrideConfigurer. To run the application, execute the main
methodoftheSampleAppclassofthisproject.)
PropertyOverrideConfigurerexample
The following example listing shows bean definitions for DataSource and WebServiceConfiguration
classeswhosepropertieswe’llsetusingPropertyOverrideConfigurer:
Example listing 5-32 – applicationContext.xml - Bean definitions for DataSource and
WebServiceConfiguration
Project–ch05-propertyOverrideConfigurer-example
Sourcelocation-src/main/resources/META-INF/spring
<beanid="datasource"class="sample.spring.chapter05.domain.DataSource">
<propertyname="url"value="testurlvalue"/>
<propertyname="username"value="testusernamevalue"/>
<propertyname="password"value="testpasswordvalue"/>
<propertyname="driverClass"value="testdriverClassvalue"/>
</bean>
<beanid="webServiceConfiguration"
class="sample.spring.chapter05.domain.WebServiceConfiguration">
<propertyname="webServiceUrl"value="thiswebserviceurlneedstobereplaced"/>
</bean>
In the above example listing, the <bean> element’s value attribute specifies default value of a bean
property.
The following example listing shows the bean definition for the PropertyOverrideConfigurer class that
replaces the default values of bean properties (shown in example listing 5-32) with values read from
database.propertiesandwebservice.propertiesfiles:
Examplelisting5-33–applicationContext.xml-PropertyOverrideConfigurerconfiguration
Project–ch05-propertyOverrideConfigurer-example
Sourcelocation-src/main/resources/META-INF/spring
<bean
class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<propertyname="locations">
<list>
<value>classpath:database.properties</value>
<value>classpath:webservice.properties</value>
</list>
</property>
</bean>
In the above example listing,PropertyOverrideConfigurer’s locations property specifies the properties
filesthatcontainvaluesforbeanproperties.
NOTE Instead of directly configuring PropertyOverrideConfigurer, you can use <property-override>
elementofSpring’scontextschematoconfigureaPropertyOverrideConfigurerinstance.
The following example listing shows database.properties and webservice.properties files that contain
valuesofbeanproperties:
Examplelisting5-34–Propertiesdefinedindatabase.propertiesandwebservice.properties
Project–ch05-propertyOverrideConfigurer-example
Sourcelocation-src/main/resources/META-INF
----------------database.propertiesfile------------------
datasource.url=some_url
datasource.username=some_username
datasource.password=some_password
----------------webservice.propertiesfile------------------
webServiceConfiguration.webServiceUrl=some_url
The entries in the database.properties and webservice.properties files show that the property name
followsthepattern:<bean-name>.<property-name>. When bean definitionsare loaded bytheSpring
container,PropertyOverrideConfigurerreplacesthedefaultvalueofabeanpropertywiththevalueread
forthatbeanpropertyfromthedatabase.propertiesandwebservice.propertiesfiles.Forinstance,theurl
property of datasource bean is set to the value of datasource.url property defined in the
database.properties file.Similarly,webServiceUrl property of webServiceConfiguration bean is set to
thevalueofwebServiceConfiguration.webServiceUrlpropertydefinedinthewebservice.propertiesfile.
If no value is found for a bean property in the external properties files, the bean property retains its
defaultvalue.Examplelisting5-32showsthatthedriverClasspropertyofdatasourcebeanhasthedefault
value ‘test driverClass value’. Example listing 5-34 shows that there is no property named
datasource.driverClass defined in the database.properties or webservice.properties file; therefore, the
driverClassbeanpropertyretainsitsdefaultvalue.
The main method of SampleApp class of ch05-propertyOverrideConfigurer-example project retrieves
WebServiceConfigurationandDataSourcebeansfromtheApplicationContextandprintstheirproperties
ontheconsole.IfyouexecuteSampleApp’smainmethod,you’llseethefollowingoutputontheconsole:
DataSource[url=some_url,username=some_username,password=some_password,driverClass=testdriverClassvalue]
WebServiceConfiguration[webServiceUrl=some_url]
The above output shows that the default values of all bean properties, except that of driverClass, are
replacedbythepropertyvaluesspecifiedintheexternalpropertiesfiles.
As PropertyOverrideConfigurer and PropertySourcesPlaceholderConfigurer inherit from Spring’s
PropertyResourceConfigurer class, you’ll notice that both of these classes share many common
configurationoptions.Forinstance,youcansetPropertyOverrideConfigurer’slocalOverridepropertyto
controlwhetherthelocalpropertiesgetprecedenceoverpropertiesreadfromexternalpropertiesfiles,
youcansetPropertyOverrideConfigurer’spropertiespropertytodefinelocalproperties,andsoon.
5-5Summary
Inthischapter,wesawhowtoaddcustominitializationanddestructionlogictoabeaninstance.Wealso
lookedathowyoucanmodifynewlycreatedbeaninstancesusingBeanPostProcessorimplementations,
and modify beandefinitions using BeanFactoryPostProcessor implementations. Spring internally makes
useofBeanPostProcessorsandBeanFactoryPostProcessorstoprovidemanyframeworkfeatures.Inthe
nextchapter,we’lllookatSpring’ssupportforannotation-drivendevelopment.
Chapter6-Annotation-drivendevelopmentwithSpring
6-1Introduction
Inpreviouschapters,wesawthatthebeandefinitionscontainedintheapplicationcontextXMLfileare
used as a blueprint by the Spring container to create bean instances. A bean definition specifies
information about bean dependencies, initialization and destruction methods of a bean, lazy or eager
initialization strategy for the bean instance, bean scope, and so on. In this section, we’ll look at
annotationsthatyoucanusetospecifythesame informationin thebeanclassitself,therebysavingthe
effort toexplicitlyconfigureabeanintheapplication context XML file. We’ll alsotouch upon Spring
ExpressionLanguage(SpEL)andhowtovalidateobjectsusingSpring’sValidatorinterfaceandthrough
JSR303annotations.We’llendthischapterwithaquicklookathowtoprogrammaticallydefineSpring
beansusingSpring’s@Configurationand@Beanannotations.
Let’s firstbegin with looking at Spring’s @Component annotation that indicates that a particular class
representsaSpringcomponent.
6-2IdentifyingSpringcomponentswith@Component
Spring’s @Component annotation is a type-level annotation, which indicates that a class represents a
Springcomponent.Itisrecommendedthatyouusemorespecializedformsof@Componentannotationto
annotatecontrollers,servicesanddataaccessobjects(DAOs)ofyourapplication.Forinstance,annotate
controllerswith@Controller,serviceswith@Service,andDAOswith@Repositoryannotation.
IMPORTchapter6/ch06-bankapp-annotations(ThisprojectshowstheMyBankapplicationthatuses
annotationsforregisteringbeanswiththeSpringcontainerandforautowiringdependencies.Torunthe
application,executethemainmethodoftheBankAppclassofthisproject.)
The following example listing shows the MyBank’s FixedDepositServiceImpl class that makes use of
@Serviceannotation:
Examplelisting6-1–FixedDepositServiceImplclass-@Serviceannotationusage
Project–ch06-bankapp-annotations
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp/service
packagesample.spring.chapter06.bankapp.service;
importorg.springframework.stereotype.Service;
@Service(value="FixedDepositService")
publicclassFixedDepositServiceImplimplementsFixedDepositService{.....}
As FixedDepositSerivceImpl class is annotated with @Service annotation, FixedDepositServiceImpl
class represents a Spring component. @Service annotation accepts a value attribute that specifies the
name with which the component is registered as a bean with the Spring container. For instance,
FixedDepositServiceImpl class is registered with Spring container as a bean with the name
FixedDepositService.Thevalueattributeservesthesamepurposeasthe<bean>element’sidattribute.
Like@Serviceannotation,@Component,@Repositoryand@Controllerannotationsspecifythenameof
the component via value attribute. You can specify the name of a Spring component without explicitly
specifying the value attribute. This means that @Service(value="FixedDepositService") is same as
@Service("FixedDepositService").Ifyoudon’tspecifyanameforthecomponent,Springassumesname
of the component is same as the name of the component class. Only difference is that the name of the
componentbeginswithalowercaseletter.Youshouldspecifyacustomnameforacomponentbecauseit’s
particularlyhelpfulwhenautowiringdependencies‘byname’.
If you enable classpath-scanning feature of Spring, bean classes annotated with @Component,
@Controller, @Service or @Repository annotations are automatically registered with the Spring
container. You enable classpath scanning feature of Spring by using the <component-scan> element of
Spring’scontextschema.
Thefollowingexamplelistingshowsusageof<component-scan>element:
Examplelisting6-2–applicationContext.xml
Project–ch06-bankapp-annotations
Sourcelocation-src/main/resources/META-INF/spring
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=".....http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scanbase-package="sample.spring"/>
</beans>
In the above example listing, reference to Spring’s context schema is included so that its elements are
accessible. The <component-scan> element’s base-package attribute specifies comma-separated list of
packages that should be searched for Spring components. As the base-package attribute’s value is
sample.spring,Springcomponentsare searchedinsidesample.spring package and itssub-packages. As
theFixedDepositServiceImplclassshowninexamplelisting6-1isannotatedwith@Serviceannotation
andislocatedinpackagesample.spring.chapter06.bankapp.service,the<component-scan>elementinthe
aboveexamplelistingautomaticallyregistersFixedDepositServiceImplclassasabeanwiththeSpring
container.ThisisequivalenttothefollowingbeandefinitionfortheFixedDepositServiceImplclassinthe
applicationcontextXMLfile:
Examplelisting6-3–BeandefinitionfortheFixedDepositServiceImplclass
<beanid="FixedDepositService"
class="sample.spring.chapter06.bankapp.service.FixedDepositServiceImpl"/>
Ifyouwanttofilterthecomponentclassesthatshouldbeconsideredforautomaticregistrationwiththe
Spring container, use the resource-pattern attribute of <component-scan> element. The default value of
resource-pattern attribute is **/*.class, which means all the component classes under the package(s)
specifiedbythebase-packageattributewillbeconsideredforautomaticregistration.The<include-filter>
and<exclude-filter>sub-elementsof<component-scan>elementprovideamoreconcisewaytospecify
component classes that should be considered for automatic registration, and the classes that should be
ignored. For instance, the following example listing shows an example usage of <include-filter> and
<exclude-filter>elements:
Examplelisting6-4–<include-filter>and<exclude-filter>elements
<beans.....>
<context:component-scanbase-package="sample.example">
<context:include-filtertype="annotation"expression="example.annotation.MyAnnotation"/>
<context:exclude-filtertype="regex"expression=".*Details"/>
</context:component-scan>
</beans>
The<exclude-filter>and<include-filter>elementsdefineatypeattributethatspecifiesthestrategyused
forfilteringcomponentclasses,andtheexpressionattributespecifiesthecorrespondingfilterexpression.
In the above example listing, the <include-filter> element specifies that the component classes that are
annotatedwithMyAnnotationtype-levelannotationareautomaticallyregisteredwiththeSpringcontainer,
andthe<exclude-filter>elementspecifiesthatthecomponentclasseswhosenamesendwithDetailsare
ignoredbythe<component-scan>element.
The following table describes the possible values that the type attributes of <include-filter> and
<exclude-filter>elementscanaccept:
Valueoftypeattribute Description
annotation
If the type attribute’s value is annotation, the expression attribute specifies the fully-
qualifiedclassnameoftheannotationthatacomponentclassmustbeannotatedwith.For
instance, if the expression attribute’s value is example.annotation.MyAnnotation,
componentclassesthat areannotatedwith MyAnnotationannotationare consideredfor
inclusion (in case of <include-filter> element) or exclusion (in case of <exclude-filter>
element).
assignable If the type attribute’s value is assignable, the expression attribute specifies the fully-
qualifiednameofaclassorinterfacetowhichacomponentclassmustbeassignable.
aspectj If the type attribute’s value is aspectj, the expression attribute specifies an AspectJ
expressionthatisusedforfilteringthecomponentclasses.
regex Ifthetypeattribute’svalueisregex,theexpressionattributespecifiesaregularexpression
thatisusedforfilteringcomponentclassesbytheirnames.
custom
If the type attribute’s value is custom, an implementation of
org.springframework.core.type.TypeFilter interface is specified by the expression
attributeforfilteringthecomponentclasses.
NOTE In this section, we looked at an example usage of @Service annotation. @Component,
@Controller and @Repository annotations are specified the same way as @Service annotation. Refer
CustomerRegistrationDetailsandCustomerRequestDetailsclassesofch06-bankapp-annotationsproject
to see usage of @Component annotation. Refer DAO classes contained in ch06-bankapp-annotations
projecttoseeusageof@Repositoryannotation.
AsSpringcomponentsarenotdefinedintheapplicationcontextXMLfile,youdon’thavetheoptionto
use <property> or <constructor-arg> element to specify their dependencies. For this reason, Spring
componentsmakeuseofannotationslike@Autowired,@Inject,andsoon,tospecifytheirdependencies.
Let’snowlookatSpring’s@Autowiredannotation.
6-3@Autowired-autowiringdependenciesbytype
@Autowired annotation is used to autowire dependencies ‘by type’. Spring’s @Autowired annotation
provides the same functionality as the Spring’s autowiring feature that we discussed in chapter 4, but
@Autowired annotation offers a more cleaner and flexible approachto autowiring beandependencies.
@Autowiredannotationcanbeusedatconstructor-level,method-levelandfield-level.
ThefollowingexamplelistingshowstheAccountStatementServiceImplclassthatusesthe@Autowired
annotationatthefield-level:
Examplelisting6-5–AccountStatementServiceImplclass-@Autowiredannotationusageatthefield-
level
Project–ch06-bankapp-annotations
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp/service
packagesample.spring.chapter06.bankapp.service;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Service;
@Service(value="accountStatementService")
publicclassAccountStatementServiceImplimplementsAccountStatementService{
@Autowired
privateAccountStatementDaoaccountStatementDao;
@Override
publicAccountStatementgetAccountStatement(Datefrom,Dateto){
returnaccountStatementDao.getAccountStatement(from,to);
}
}
Intheaboveexamplelisting,theaccountStatementDaofield(oftypeAccountStatementDao)isannotated
with @Autowired annotation. When an instance of AccountStatementServiceImpl is created, Spring’s
AutowiredAnnotationBeanPostProcessor (a BeanPostProcessor implementation) is responsible for
autowiringaccountStatementDaofield.TheAutowiredAnnotationBeanPostProcessorretrievesreference
toanAccountStatementDaotypebeanfromtheSpringcontainerandassignsittotheaccountStatementDao
field.Itisimportanttonotethatthefieldannotatedwith@Autowiredannotationneednotbepublicor
haveacorrespondingpublicsettermethod.
NOTESpring’sAutowiredAnnotationBeanPostProcessorperformsautowiringoffields,methodsand
constructorsthatareannotatedwithSpring’s@AutowiredorJSR330’s@Inject(explainedinsection6-
5)annotation.
The following example listing shows the CustomerRegistrationServiceImpl class that uses the
@Autowiredannotationatthemethod-level:
Example listing 6-6 – CustomerRegistrationServiceImpl class - @Autowired annotation usage at the
method-level
Project–ch06-bankapp-annotations
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp/service
packagesample.spring.chapter06.bankapp.service;
@Service("customerRegistrationService")
@Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)
publicclassCustomerRegistrationServiceImplimplementsCustomerRegistrationService{
privateCustomerRegistrationDetailscustomerRegistrationDetails;
.....
@Autowired
publicvoidobtainCustomerRegistrationDetails(
CustomerRegistrationDetailscustomerRegistrationDetails){
this.customerRegistrationDetails=customerRegistrationDetails;
}
.....
@Override
publicvoidsetAccountNumber(StringaccountNumber){
customerRegistrationDetails.setAccountNumber(accountNumber);
}
.....
}
Intheaboveexamplelisting,obtainCustomerRegistrationDetailsmethodisannotatedwith@Autowired
annotation. If a method is annotated with @Autowired annotation, the arguments of the method are
autowired.AsobtainCustomerRegistrationDetailsmethodisannotatedwith@Autowiredannotation,its
CustomerRegistrationDetailsargumentisautowiredbytype.Itisimportanttonotethatan@Autowired
annotatedmethodneednotbepublic.
NOTE A method annotated with @Autowired annotation is invoked after the component instance is
created,andthefieldsannotatedwith@Autowiredannotationareinjectedwithmatchingbeaninstances.
The following example listing shows the CustomerRequestServiceImpl class that defines a constructor
annotatedwith@Autowiredannotation:
Examplelisting6-7–CustomerRequestServiceImplclass-@Autowiredannotationusageatconstructor-
level
Project–ch06-bankapp-annotations
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp/service
packagesample.spring.chapter06.bankapp.service;
@Service(value="customerRequestService")
publicclassCustomerRequestServiceImplimplementsCustomerRequestService{
privateCustomerRequestDetailscustomerRequestDetails;
privateCustomerRequestDaocustomerRequestDao;
@Autowired
publicCustomerRequestServiceImpl(CustomerRequestDetailscustomerRequestDetails,
CustomerRequestDaocustomerRequestDao){
this.customerRequestDetails=customerRequestDetails;
this.customerRequestDao=customerRequestDao;
}
.....
}
In the above example listing, the CustomerRequestServiceImpl’s constructor is annotated with
@Autowiredannotation.Ifaconstructorisannotatedwith@Autowiredannotation,theargumentsofthe
constructorareautowired.AsCustomerRequestServiceImpl’sconstructorisannotatedwith@Autowired
annotation,itsCustomerRequestDetailsandCustomerRequestDaoargumentsareautowiredbytype.Itis
importanttonotethatan@Autowiredannotatedconstructorneednotbepublic.
Whenusingthe@Autowiredannotation,exceptionisthrownifabeanmatchingtherequiredtypeisnot
found. For instance, in example listing 6-7, if a bean of type CustomerRequestDetails or
CustomerRequestDaoisnotfoundtoberegisteredwiththeSpringcontainer,anexceptionisthrownwhile
creatingtheCustomerRequestServiceImplinstance.@Autowired’srequiredattributespecifieswhetherit
ismandatoryoroptionaltoautowiredependencies.Ifyouset@Autowired’srequiredattributevalueto
false,autowiringofdependenciesisconsideredoptional.Thismeansthatiftherequiredattribute’svalue
is set to false, exception is not thrown if no bean matching the required type is found in the Spring
container. By default, value of required attribute is true; dependencies must be satisfied by the Spring
container.
Ifacomponentclassdefinesan@Autowiredannotatedconstructorwithrequiredattribute’svaluesetto
true, it can’t have another @Autowired annotated constructor. For instance, consider the following
examplelistingthatdefines2constructorsannotatedwiththe@Autowiredannotation:
Examplelisting6-8–Acomponentclassthatdefines2@Autowiredannotatedconstructors
@Service(value="customerRequestService")
publicclassCustomerRequestServiceImplimplementsCustomerRequestService{
.....
@Autowired(required=false)
publicCustomerRequestServiceImpl(CustomerRequestDetailscustomerRequestDetails){.....}
@Autowired
publicCustomerRequestServiceImpl(CustomerRequestDetailscustomerRequestDetails,
CustomerRequestDaocustomerRequestDao){.....}
}
Asautowiringofdependenciesisrequired(@Autowired’srequiredattributeissettotrue)foroneofthe
constructors and optional (@Autowired’s required attribute is set to false) for the other in the above
examplelisting,itresultsinanexceptionthrownbySpring.
A component class can define multiple @Autowired annotated constructors with required attribute’s
valuesettofalse.Insuchacase,oneoftheconstructorswillbeinvokedbySpringtocreateaninstance
of the component class. The following example listing shows a component class that defines 2
constructorsannotatedwith@Autowired(required=false),andadefaultconstructor:
Examplelisting6-9–Acomponentclassthatdefinesmultiple@Autowiredannotatedconstructorswith
requiredattributevaluesettofalse
@Service(value="customerRequestService")
publicclassCustomerRequestServiceImplimplementsCustomerRequestService{
publicCustomerRequestServiceImpl(){
.....
}
@Autowired(required=false)
publicCustomerRequestServiceImpl(CustomerRequestDetailscustomerRequestDetails){
.....
}
@Autowired(required=false)
publicCustomerRequestServiceImpl(CustomerRequestDetailscustomerRequestDetails,
CustomerRequestDaocustomerRequestDao){
.....
}
}
Intheaboveexamplelisting,boththe@Autowiredannotatedconstructorsarecandidatesforautowiring
bySpringtocreateaninstanceoftheCustomerRequestServiceImplclass.Theconstructorwiththelargest
number of satisfied dependencies is chosen. In case of CustomerRequestServiceImpl class, if beans of
typesCustomerRequestDetailsandCustomerRequestDaoareregisteredwiththeSpringcontainer,Spring
invokes CustomerRequestServiceImpl(CustomerRequestDetails, CustomerRequestDao) constructor. If a
bean of type CustomerRequestDetails is registered with container but no bean of type
CustomerRequestDao is registered, CustomerRequestServiceImpl(CustomerRequestDetails) constructor
is invoked. In case none of the dependencies are found, the default constructor of
CustomerRequestServiceImplclassisinvoked.
Let’snowlookathowyoucanuseSpring’s@Qualifierannotationalongwith@Autowiredannotationto
autowiredependenciesbyname.
6-4@Qualifier–autowiringdependenciesbyname
YoucanuseSpring’s@Qualifierannotationalongwith@Autowiredannotationtoautowiredependencies
byname.The@Qualifierannotationcanbeusedatfield-level,method-parameter-levelandconstructor-
argument-level.
ThefollowingexamplelistingshowstheFixedDepositServiceImplclassthatuses@Qualifierannotation:
Examplelisting6-10–FixedDepositServiceImplclass-@Qualifierannotationusage
Project–ch06-bankapp-annotations
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp/service
packagesample.spring.chapter06.bankapp.service;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Qualifier;
@Service(value="FixedDepositService")
publicclassFixedDepositServiceImplimplementsFixedDepositService{
@Autowired
@Qualifier(value="myFixedDepositDao")
privateFixedDepositDaomyFixedDepositDao;
.....
}
In theabove examplelisting, myFixedDepositDaofieldis annotated with@Autowired and @Qualifier
annotations.@Qualifierannotation’svalueattributespecifiesthenameofthebeantobeassignedtothe
myFixedDepositDaofield.
Spring first finds autowiring candidates ‘by type’ for the fields, constructors and methods that are
annotated with @Autowired annotation. Then, Spring uses the bean name specified by @Qualifier
annotationtolocateauniquebeanfromthelistofautowiringcandidates.Forexample,inexamplelisting
6-10,SpringfirstfindsbeansoftypeFixedDepositDaoformyFixedDepositDaofield,andthenlocatesthe
bean named myFixedDepositDao from the list of autowiring candidates. If a bean named
myFixedDepositDaoisfound,SpringassignsittothemyFixedDepositDaofield.
NOTE @Qualifier(value="myFixedDepositDao") is same as @Qualifier("myFixedDepositDao"); you
don’tneedtousethevalueattributetospecifythenameofthebeantobeautowired.
The following example listing shows usage of @Qualifier annotation at method-parameter-level and
constructor-argument-level:
Examplelisting6-11–@Qualifierusageatmethod-parameter-levelandconstructor-argument-level
publicclassSample{
@Autowired
publicSample(@Qualifier("aBean")ABeanbean){....}
@Autowired
publicvoiddoSomething(@Qualifier("bBean")BBeanbean,CBeancBean){.....}
}
Intheaboveexamplelisting,@Qualifierannotationisspecifiedforaconstructorargumentandamethod
argument.WhencreatinganinstanceofSampleclass,SpringfindsabeanoftypeABeanwithnameaBean
and passes it as an argument to the Sample class’s constructor. When calling Sample’s doSomething
method,SpringfindsabeanoftypeBBean(whosenameisbBean)andanotherbeanoftypeCBean,and
passesboththesebeansasargumentstothedoSomethingmethod.ItisimportanttonotethattheBBean
dependencyisautowiredbyname,andCBeandependencyisautowiredbytype.
Let’s now look at JSR 330’s @Inject and @Named annotations that you can use instead of Spring’s
@Autowiredand@Qualifierannotations.
6-5JSR330’s@Injectand@Namedannotations
JSR 330 (Dependency Injection for Java) standardizes dependency injection annotations for the Java
platform.JSR330defines@Injectand@NamedannotationsthataresimilartoSpring’s@Autowiredand
@Qualifierannotations,respectively.Springprovidessupportfor@Injectand@Namedannotations.
IMPORTchapter6/ch06-bankapp-jsr330(This project shows theMyBankapplication that uses JSR
330’s@Injectand@Namedannotationsforautowiringdependencies.Toruntheapplication,executethe
mainmethodoftheBankAppclassofthisproject.)
The following example listing shows the FixedDepositServiceImpl class that makes use of JSR 330’s
@Injectand@Namedannotations:
Examplelisting6-12–FixedDepositServiceImplclass
Project–ch06-bankapp-jsr330
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp/service
packagesample.spring.chapter06.bankapp.service;
importjavax.inject.Inject;
importjavax.inject.Named;
@Named(value="FixedDepositService")
publicclassFixedDepositServiceImplimplementsFixedDepositService{
@Inject
@Named(value="myFixedDepositDao")
privateFixedDepositDaomyFixedDepositDao;
.....
}
If you compare the FixedDepositServiceImpl class shown in the above example listing with the
FixedDepositServiceImplclassinexamplelisting6-10,you’llnoticethatJSR330’s@Namedannotation
hasbeenusedinplaceof@Serviceand@Qualifierannotations,andJSR330’s@Injectannotationhas
beenusedinplaceof@Autowiredannotation.
@Autowired and @Inject annotations have the same semantics; they are used for autowiring
dependenciesbytype.Like@Autowiredannotation,@Inject can beused atmethod-level, constructor-
level and field-level. Dependency injection of constructors is performed first, followed by fields, and
then methods. We saw earlier that @Autowired annotation’s required attribute specifies whether it is
mandatory or optional to autowire dependencies. @Inject doesn’t have any equivalent of @Autowired
annotation’srequiredattribute.
If@Named annotation is used at the type-level, it acts like Spring’s @Component annotation. And, if
@Named annotation is used at the method-parameter-level or constructor-argument-level, it acts like
Spring’s @Qualifier annotation. If a class is annotated with @Named annotation, <component-scan>
element of Spring’s context schema treats it like a component class annotated with @Component
annotation.
To use @Named and @Inject annotations, you need to include JSR 330 JAR file in your project. The
ch06-bankapp-jsr330projectincludesJSR330JARfilethroughthefollowing<dependency>elementin
thepom.xmlfile:
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
In chapter 5, we looked at JSR 250’s @PostConstruct and @PreDestroy annotations that are used to
identify initialization and destruction methods of a bean. Let’s now look at JSR 250’s @Resource
annotationthatyoucanuseforautowiringdependenciesbyname.
6-6JSR250’s@Resourceannotation
Spring supports autowiring ‘by name’ of fields and methods via JSR 250’s @Resource annotation.
@Resourceannotation’snameattributespecifiesthenameofthebeantobeautowired.Itisimportantto
notethatyoucan’tuse@Resourceannotationforautowiringconstructorarguments.
ThefollowingexamplelistingshowshowFixedDepositServiceImplclassfromexamplelisting6-12can
berewrittenusing@Resourceannotation:
Examplelisting6-13–@Resourceannotationusageatfield-level
importjavax.annotation.Resource;
@Named(value="FixedDepositService")
publicclassFixedDepositServiceImplimplementsFixedDepositService{
@Resource(name="myFixedDepositDao")
privateFixedDepositDaomyFixedDepositDao;
.....
}
In the aboveexample listing,@Resource annotation has been used for autowiring myFixedDepositDao
field. As the value of name attribute is myFixedDepositDao, Spring locates a bean named
myFixedDepositDaointheSpringcontainerandassignsittomyFixedDepositDaofield.
Instead of using @Autowired and @Qualifier annotations, you should use @Resource annotation for
autowiring dependencies ‘by name’. As mentioned earlier, if you are using @Autowired-@Qualifier
combinationtoperformautowiring‘byname’,Springfirstfindsbeansbasedonthetypeofthefield(or
thetypeofthemethodargumentorconstructorargument)tobeautowired,followedbynarrowingdownto
a unique bean based on the bean name specified by @Qualifier annotation. But, if you are using
@Resource annotation, Spring uses bean name specified by @Resource annotation to locate a unique
bean.Thismeansthatwhenyouuse@Resourceannotation,typeofthefield(orsettermethodargument)
tobeautowiredisnottakenintoconsiderationbySpring.
NOTEAs@Autowired,@Injectand@ResourceannotationsareprocessedbyBeanPostProcessors,you
should not use these annotations in component classes that implement BeanFactoryPostProcessor or
BeanPostProcessorinterface.
Let’snowlookat@Scope,@Lazy,@DependsOnand@Primaryannotations.
6-7@Scope,@Lazy,@DependsOnand@Primaryannotations
Youspecifythescope(prototypeorsingleton)ofaSpringcomponentusingSpring’s@Scopeannotation.
By default, Spring components are singleton-scoped. If you want a Spring component to be prototype-
scoped, you have to specify so via @Scopeannotation. @Scope annotation plays the same role as the
<bean>element’sscopeattribute(refersection2-5ofchapter2toknowmoreaboutthescopeattribute).
ThefollowingexamplelistingshowstheCustomerRequestDetailsclassthatuses@Scopeannotation:
Examplelisting6-14–@Scopeannotationusage
Project–ch06-bankapp-jsr330
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp/domain
packagesample.spring.chapter06.bankapp.domain;
importjavax.inject.Named;
importorg.springframework.beans.factory.config.ConfigurableBeanFactory;
importorg.springframework.context.annotation.Scope;
@Named(value="customerRequestDetails")
@Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)
publicclassCustomerRequestDetails{.....}
The@Scopeannotationacceptsavalueattributethatspecifiesthescopeofthecomponent.Youcanset
valueattribute’svaluetoprototypeorsingletontoindicatewhetherthecomponentissingleton-scopedor
prototype-scoped, or you can set value attribute’s value to ConfigurableBeanFactory’s
SCOPE_SINGLETON(valueissingleton)orSCOPE_PROTOTYPE(valueisprototype)constants.
Bydefault,singleton-scopedSpringcomponentsareeagerlyinitialized,thatis,theyareinstantiatedwhen
theSpringcontaineriscreated.Ifyouwantasingleton-scopedcomponenttobelazilycreated,annotate
thecomponentclassofasingleton-scopedcomponentwith@Lazyannotation.
NOTE @Lazy annotation serves the same purpose as the <bean> element’s lazy-init
attribute.Refersection2-5ofchapter2toknowmoreaboutlazy-initattribute.
Thefollowingexamplelistingshowsusageof@Lazyannotation:
Examplelisting6-15–@Lazyannotationusage
@Lazy(value=true)
@Component
publicclassSample{.....}
@Lazyannotation’svalueattributespecifieswhetherthecomponentislazilyoreagerlyinitialized.Ifthe
valueattribute’svalueistrue,itmeansthatthecomponentislazilyinitialized.
You specify implicit bean dependencies using @DependsOn annotation. The following example listing
showsusageof@DependsOnannotation:
Examplelisting6-16–@DependsOnannotationusage
@DependsOn(value={"beanA","beanB"})
@Component
publicclassSample{.....}
Intheaboveexamplelisting,@DependsOnannotationontheSampleclassinstructstheSpringcontainer
tocreatebeanAandbeanBbeansbeforecreatinganinstanceofSampleclass.
NOTE@DependsOnannotationservesthesamepurposeasthe<bean>element’sdepends-onattribute.
Refersection4-3ofchapter4toknowmoreaboutdepends-onattribute.
Ifmultipleautowiringcandidatesareavailableforadependency,@Primaryannotationdesignatesabean
as a primary candidate for autowiring. The following example listing shows usage of @Primary
annotation:
Examplelisting6-17–@Primaryannotationusage
@Primary
@Component
publicclassSample{.....}
NOTE@Primaryannotationservesthesamepurposeasthe<bean>element’sprimaryattribute.Refer
section4-6ofchapter4toknowmoreaboutprimaryattribute.
Let’snowlookatSpring’s@Valueannotationthatsimplifiesconfiguringcomponentclasses.
6-8Simplifyingcomponentconfigurationusing@Valueannotation
In previous chapters, we saw examples in which configuration information required by beans was
specifiedviavalueattributeof<property>and<constructor-arg>elements.AsSpringcomponentsarenot
defined in the application context XML file, Spring’s @Value annotation is used to serve the same
purpose as the value attribute of <property>and <constructor-arg> elements. You should note that the
@Value annotation can be used at field-level, method-level, method-parameter-level and constructor-
argument-level.
IMPORT chapter 6/ch06-value-annotation (This project shows an application that uses Spring’s
@ValueannotationtoconfigureSpringcomponents.Toruntheapplication,executethemainmethodofthe
SampleAppclassofthisproject.)
Thefollowingexamplelistingshowsanexampleusageof@Valueannotationatfield-level:
Examplelisting6-18–Sampleclass-@Valueannotationusage
Project–ch06-value-annotation
Sourcelocation-src/main/java/sample/spring/chapter06/beans
packagesample.spring.chapter06.beans;
importorg.springframework.beans.factory.annotation.Value;
@Component(value="sample")
publicclassSample{
@Value("Somecurrency")
privateStringcurrency;
.....
}
In the above example listing, currency field is annotated with @Value annotation. The @Value
annotation’svalue attribute specifies the default value for the field. It is optional to specify the value
attribute;therefore,@Value(value="Somecurrency")issameas@Value("Somecurrency").
YoucanalsouseaSpringExpressionLanguage(SpEL)expressionasthevalueof@Valueannotation.
SpEL is an expression language that you can use to query and manipulate objects at runtime. The
followingexamplelistingshows@ValueannotationsthatmakeuseofSpELexpressions:
Examplelisting6-19–Sampleclass-@ValueannotationthatusesSpELexpressions
Project–ch06-value-annotation
Sourcelocation-src/main/java/sample/spring/chapter06/beans
packagesample.spring.chapter06.beans;
importorg.springframework.beans.factory.annotation.Value;
@Component(value="sample")
publicclassSample{
@Value("#{configuration.environment}")
privateStringenvironment;
.....
@Value("#{configuration.getCountry()}")
privateStringcountry;
@Value("#{configuration.state}")
privateStringstate;
.....
}
The above example listing shows that the @Value annotation specifies a value that has the syntax #
{<spel-expression>}. The SpEL expression specified by @Value annotation is processed by a
BeanPostProcessor.TheSpELexpressionscanmakeuseof<beanName>.<fieldorpropertyormethod>
formattoobtainitsvalue.Forinstance,#{configuration.environment}meansobtainvalueofenvironment
property of bean named configuration, and #{configuration.getCountry()} means invoke getCountry
methodofbeannamedconfiguration.
The following example listing shows the Java class of the configuration bean referenced by SpEL
expressionsshowninexamplelisting6-19:
Examplelisting6-20–Configurationcomponentclass
Project–ch06-value-annotation
Sourcelocation-src/main/java/sample/spring/chapter06/beans
packagesample.spring.chapter06.beans;
importorg.springframework.stereotype.Component;
@Component("configuration")
publicclassConfiguration{
publicstaticStringenvironment="DEV";
publicStringgetCountry(){
return"Somecountry";
}
publicStringgetState(){
return"Somestate";
}
publicString[]splitName(Stringname){
returnname.split("");
}
publicStringgetCity(){
return"Somecity";
}
}
TheaboveexamplelistingshowsthattheConfigurationclassrepresentsaSpringcomponentthatdefines
fields and methods. If you compare example listing 6-19 with 6-20, you’ll notice that #
{configuration.environment} expression refers to the static environment variable defined in the
Configuration class, #{configuration.getCountry()} expression refers to Configuration’s getCountry
method,and#{configuration.state}expressionreferstoConfiguration’sgetStatemethod.
ThemainmethodofSampleAppclassinch06-value-annotationprojectretrievesaninstanceofSample
beanfromtheApplicationContextandprintsthevalueofvariousattributesofSamplebeaninstance.If
youexecuteSampleApp’smainmethod,you’llseethefollowingoutput:
Sample[environment=DEV,currency=Somecurrency,country=Somecountry,state=Somestate,splitName=[FirstName,LastName],
city=Somecity]
Theaboveoutputshows:
· #{configuration.environment} expression results in Sample’senvironment field value set to
DEV,whichisthevaluespecifiedbypublicstaticfieldenvironmentofConfigurationclass.
·#{configuration.getCountry()}expressionresultsinSample’scountryfieldvaluesettoSome
country,whichisthevaluereturnedbyinvokingConfiguration’sgetCountrymethod.
·#{configuration.state}expressionresultsinSample’sstatefieldvaluesettoSomestate,whichis
thevaluereturnedbyinvokingConfiguration’sgetStatemethod.
TheaboveexampleshowsthatyoucanuseSpELtoretrieveconfigurationinformationfromotherbeans.
NOTESpELisaverypowerfulexpressionlanguage,anditoffersmanymorecapabilitiesthandescribed
inthisbook.ItisrecommendedthatyourefertoSpringreferencedocumentationtoknowaboutSpEL.
Thefollowingexamplelistingshowsusageof@Valueannotationatmethod-levelandmethod-parameter-
level:
Examplelisting6-21–Sampleclass-@Valueannotationusageatmethod-levelandmethod-parameter-
level
Project–ch06-value-annotation
Sourcelocation-src/main/java/sample/spring/chapter06/beans
packagesample.spring.chapter06.beans;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Value;
@Component(value="sample")
publicclassSample{
.....
privateString[]splitName;
privateStringcity;
@Autowired
publicvoidsplitName(@Value("#{configuration.splitName(FirstNameLastName')}")
String[]splitName){
this.splitName=splitName;
}
@Autowired
@Value("#{configuration.getCity()}")
publicvoidcity(Stringcity){
this.city=city;
}
.....
}
Theaboveexamplelistingshowsthatthemethodsthatareannotatedwith@Autowiredannotationmake
useof@Valueannotationatmethod-levelandmethod-parameter-level.Youshouldnotethatthe@Value
annotationcanbeusedatmethod-levelandmethod-parameter-levelonlyifthemethodisannotatedwith
@Autowired or @Resource or @Inject annotation. SpEL expression #
{configuration.splitName('FirstName LastName')} results in invocation of Configuration’s splitName
methodwith‘FirstNameLastName’asargument.ThisshowsthatSpELexpressionscanbeusedtoinvoke
methodsthatacceptarguments.
NOTE@ValueannotationisprocessedbyaBeanPostProcessor;therefore,youshouldnotuse@Value
annotation in component classes that implement BeanFactoryPostProcessor or BeanPostProcessor
interface.
UsageofSpELisnotlimitedto@Valueannotations,youcanalsouseSpELinbeandefinitionscontained
intheapplicationcontextXMLfile.
IMPORTchapter6/ch06-spel-example(ThisprojectshowsanapplicationthatusesSpELexpressions
in bean definitions. To run the application, execute the main method of the SampleApp class of this
project.)
ThefollowingexamplelistingshowshowSpELisusedinbeandefinitions:
Examplelisting6-22–applicationContext.xml–SpELexpressionsinbeandefinitions
Project–ch06-spel-example
Sourcelocation-src/main/resources/META-INF/spring
<beans.....>
<beanid="sample"class="sample.spring.chapter06.beans.Sample">
<propertyname="environment"value="#{configuration.environment}"/>
<propertyname="currency"value="Somecurrency"/>
<propertyname="country"value="#{configuration.getCountry()}"/>
<propertyname="state"value="#{configuration.state}"/>
</bean>
<beanid="configuration"class="sample.spring.chapter06.beans.Configuration"/>
</beans>
The above example listing shows that the bean definition for the Sample class makes use of SpEL
expressions(thatrefertoConfigurationbean)tosetdefaultvaluesforenvironment,currency,countryand
stateproperties.
Let’s now look at how you can perform validation of objects in Spring applications using Spring’s
Validatorinterface.
6-9ValidatingobjectsusingSpring’sValidatorinterface
Spring’sValidator interface is part of Spring Validation API that allows you to perform validation of
objects.YoucanusetheValidatorinterfaceforperformingvalidationofobjectsinanyoftheapplication
layers.Forinstance,youcanusetheValidatorinterfacetovalidateobjectsintheweblayeraswellasin
thepersistencelayer.
NOTEAnalternativetousingtheValidatorinterfaceistouseJSR303annotationstospecifyconstraints
thatapplyonanobject.JSR303annotationsareexplainedinthenextsection.
IMPORT chapter 6/ch06-validator-interface (This project shows the MyBank application that uses
Spring’sValidatorinterfacetovalidateFixedDepositDetailsobject. Torun theapplication, execute the
mainmethodoftheBankAppclassofthisproject.)
The FixedDepositDetails object of MyBank application represents details of a fixed deposit. The
followingexamplelistingshowstheFixedDepositDetailsclass:
Examplelisting6-23–FixedDepositDetailsclass
Project–ch06-validator-interface
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp/domain
packagesample.spring.chapter06.bankapp.domain;
publicclassFixedDepositDetails{
privatelongid;
privatefloatdepositAmount;
privateinttenure;
privateStringemail;
publicFixedDepositDetails(longid,floatdepositAmount,inttenure,
Stringemail){
this.id=id;
this.depositAmount=depositAmount;
this.tenure=tenure;
this.email=email;
}
.....
//--gettersandsettersforinstancevariables
publicfloatgetDepositAmount(){
returndepositAmount;
}
…..
}
The above example listing shows thattheFixedDepositDetails class defines id,depositAmount, tenure
andemailinstancevariables.Let’ssaythatbeforethefixeddepositdetailsaresavedinthesystem,we
needtomakesurethatthefixeddepositamount(representedbythedepositAmountinstancevariable)is
not0.
To validate the FixedDepositDetails object’s depositAmount property, we need to create an
implementation of Spring’s Validator interface. The following example listing shows a validator for
objectsoftypeFixedDepositDetails:
Examplelisting6-24–FixedDepositValidatorclass–Spring’sValidatorinterfaceimplementation
Project–ch06-validator-interface
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp/validator
packagesample.spring.chapter06.bankapp.validator;
importorg.springframework.validation.Errors;
importorg.springframework.validation.Validator;
publicclassFixedDepositValidatorimplementsValidator{
@Override
publicbooleansupports(Class<?>clazz){
returnFixedDepositDetails.class.isAssignableFrom(clazz);
}
@Override
publicvoidvalidate(Objecttarget,Errorserrors){
FixedDepositDetailsfixedDepositDetails=(FixedDepositDetails)target;
if(fixedDepositDetails.getDepositAmount()==0){
errors.reject("zeroDepositAmount");
}
}
}
The Validator interface defines supports and validate methods. The supports method checks if the
supplied object instance (represented by the clazz attribute) can be validated. If the supports method
returns true, the validate method is used to validate the object. In the above example listing, the
FixedDepositValidator’s supports method checks if the supplied object instance is of type
FixedDepositDetails. If the supports method returns true, the FixedDepositValidator’s validate method
validates the object. The validate method accepts the object instance to be validated, and an Errors
instance.TheErrorsinstance’srejectmethodisusedtostoreerrorsthatoccurduringvalidation.Youcan
laterinspecttheErrorsinstancetoknowmoreaboutvalidationerrors.
The following example listing shows that the FixedDepositServiceImpl’s createFixedDeposit method
usestheFixedDepositValidator(referexamplelisting6-24)tovalidateFixedDepositDetailsobjects:
Examplelisting6-25–FixedDepositServiceImplclass–ValidatingFixedDepositDetailsobject
Project–ch06-validator-interface
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp/service
packagesample.spring.chapter06.bankapp.service;
importorg.springframework.validation.BeanPropertyBindingResult;
importsample.spring.chapter06.bankapp.validator.FixedDepositValidator;
@Service(value="FixedDepositService")
publicclassFixedDepositServiceImplimplementsFixedDepositService{
@Autowired
@Qualifier(value="myFixedDepositDao")
privateFixedDepositDaomyFixedDepositDao;
@Override
publicvoidcreateFixedDeposit(FixedDepositDetailsfixedDepositDetails)throwsException{
BeanPropertyBindingResultbindingResult=
newBeanPropertyBindingResult(fixedDepositDetails,"Errors");
FixedDepositValidatorvalidator=newFixedDepositValidator();
validator.validate(fixedDepositDetails,bindingResult);
if(bindingResult.getErrorCount()>0){
logger.error("ErrorswerefoundwhilevalidatingFixedDepositDetailsinstance");
}else{
myFixedDepositDao.createFixedDeposit(fixedDepositDetails);
logger.info("Createdfixeddeposit");
}
}
}
FixedDepositServiceImpl’s createFixedDeposit method validates the FixedDepositDetails object
(representedbyfixedDepositDetailsargument)beforeitissavedintothedatastorebyFixedDepositDao.
ThecreateFixedDepositmethodshownintheaboveexamplelistingperformsthefollowingtasks:
· creates an instance of FixedDepositValidator and Spring’s BeanPropertyBindingResult - a
defaultimplementationofErrorsinterfaceprovidedout-of-the-boxbySpring
·invokesFixedDepositValidator’svalidatemethod,passingFixedDepositDetailsobjectandthe
BeanPropertyBindingResultinstance
·invokesBeanPropertyBindingResult’sgetErrorCountmethodtocheckifanyvalidationerrors
werereported.Ifnovalidationerrorsarereported,FixedDepositDao’screateFixedDepositmethod
iscalledtosavefixeddepositdetailsinthedatastore.
The following example listing shows BankApp’smain method that invokes FixedDepositServiceImpl’s
createFixedDepositmethod(referexamplelisting6-25)tocheckifthevalidationisperformedcorrectly
byFixedDepositValidator’svalidatemethod:
Examplelisting6-26–BankAppclass
Project–ch06-validator-interface
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp
packagesample.spring.chapter06.bankapp;
publicclassBankApp{
publicstaticvoidmain(Stringargs[])throwsException{
ApplicationContextcontext=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
FixedDepositServiceFixedDepositService=context.getBean(FixedDepositService.class);
FixedDepositService.createFixedDeposit(newFixedDepositDetails(1,0,
12,"someemail@somedomain.com"));
FixedDepositService.createFixedDeposit(newFixedDepositDetails(1,1000,
12,"someemail@somedomain.com"));
}
}
First, FixedDepositService’s createFixedDeposit method is passed a FixedDepositDetails object with
depositAmountvalueas0,followedbyaFixedDepositDetailsobjectwithdepositAmountvalueas1000.
IfyouexecuteBankApp’smainmethod,you’llseethefollowingoutputontheconsole:
ErrorswerefoundwhilevalidatingFixedDepositDetailsinstance
Createdfixeddeposit
The output ‘Errors were found while validating FixedDepositDetails instance’ shows that
FixedDepositValidator reported errors when the FixedDepositDetails instance with 0 as the
depositAmountvaluewasvalidated.Theoutput‘Createdfixeddeposit’showsthatthenoerrorswere
reportedwhentheFixedDepositDetailsinstancewith1000asthedepositAmountvaluewasvalidated.
NOTE Spring’s Validator interface is typically used in Spring MVC based web applications while
bindinginformationenteredbyauserintheHTMLformtothecorrespondingform-backingobject.
Let’snowlookathowyoucanspecifyconstraintsonbeanpropertiesusingJSR303annotations,andlet
Springperformthevalidation.
6-10SpecifyingconstraintsusingJSR303annotations
JSR 303 (Bean Validation API) allows you to use annotations to specify constraints on JavaBeans
components.WhenusingJSR303withSpring,youannotatebeanpropertieswithJSR303annotations,
andSpringtakescareofvalidatingthebeanandprovidingthevalidationresult.
IMPORTchapter6/ch06-jsr303-validation(ThisprojectshowstheMyBankapplicationthatusesJSR
303annotations.Toruntheapplication,executethemainmethodoftheBankAppclassofthisproject.)
The following example listing shows the FixedDepositDetails class that makes use of JSR 303
annotations:
Examplelisting6-27–FixedDepositDetailsclass–JSR303annotations
Project–ch06-jsr303-validation
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp/domain
packagesample.spring.chapter06.bankapp.domain;
importjavax.validation.constraints.*;
importorg.hibernate.validator.constraints.NotBlank;
publicclassFixedDepositDetails{
@NotNull
privatelongid;
@Min(1000)
@Max(500000)
privatefloatdepositAmount;
@Min(6)
privateinttenure;
@NotBlank
@Size(min=5,max=100)
privateStringemail;
publicFixedDepositDetails(longid,floatdepositAmount,inttenure,Stringemail){
this.id=id;
this.depositAmount=depositAmount;
this.tenure=tenure;
this.email=email;
}
.....
}
@NotNull,@Min,@Max,@NotBlankand@SizearesomeoftheannotationsdefinedbyJSR303Bean
ValidationAPI.TheaboveexamplelistingshowsthatbyusingJSR303annotationsFixedDepositDetails
classclearlyspecifiestheconstraintsthatapplyonitsfields.Ontheotherhand,ifyouareusingSpring
ValidationAPItovalidateanobject,constraintinformationiscontainedintheValidatorimplementation
(referexamplelisting6-24).
The following table describes the constraints enforced by JSR 303 annotations on the
FixedDepositDetailsobjectshowninexamplelisting6-27:
JSR303annotation Constraintdescription
@NotNull
Theannotatedfieldmustnotbenull.
Forinstance,FixedDepositDetails’idfieldmustnotbenull.
@Min
Theannotatedfield’svaluemustbegreaterthanorequaltothespecifiedminimumvalue.
Forinstance,@M in(1000)annotationondepositAmountfieldofFixedDepositDetailsobject
meansthatdepositAmount’svaluemustbegreaterthanorequalto1000.
@Max
Theannotatedfield’svaluemustbelessthanorequaltothespecifiedvalue.
For instance, @Max(500000) annotation on depositAmount field of FixedDepositDetails
objectmeansthatthedepositAmount’svaluemustbelessthanorequalto500000.
@NotBlank Theannotatedfield’svaluemustnotbenullorempty.
Forinstance,FixedDepositDetails’emailfieldmustnotbeemptyornull.
@Size
Theannotatedfield’ssizemustbebetweenthespecifiedminandmaxattributes.
Forinstance,@Size(min=5,max=100)annotationonemailfieldofFixedDepositDetailsobject
meansthatthesizeoftheemailfieldmustbegreaterthanorequalto5andlessthanorequal
to100.
NOTETouseJSR303annotations,ch06-jsr303-validationprojectspecifiesdependencyonJSR303
APIJARfile(validation-api-1.0.0.GA)andHibernateValidatorframework(hibernate-validation-
4.3.0.Final).TheHibernateValidatorframeworkprovidesthereferenceimplementationforJSR303.
Ifyoulookattheimportstatementsinexamplelisting6-27,you’llnoticethatthe@NotBlankannotationis
definedbyHibernateValidatorframework,andnotbyJSR303.HibernateValidatorframeworkprovides
additionalannotationsthatyoucanusealongwithJSR303annotations.
Now, that we have specified JSR 303 constraints on FixedDepositDetails class, let’s look at how to
validateFixedDepositDetailsobjectusingSpring.
JSR303supportinSpring
Spring supports validating objects that make use of JSR 303 constraints. Spring’s
LocalValidatorFactoryBeanclass isresponsiblefordetectingthepresenceofaJSR303provider(like
Hibernate Validator) in the application’s classpath and initializing it. It is important to note that the
LocalValidatorFactoryBean implements JSR 303’s Validator and ValidatorFactory interfaces, and also
Spring’sValidatorinterface.
The following example listing shows the configuration of LocalValidatorFactoryBean class in the
applicationcontextXMLfile:
Examplelisting6-28–applicationContext.xml–Spring’sLocalValidatorFactoryBeanconfiguration
Project–ch06-jsr303-validation
Sourcelocation-src/main/resources/META-INF/spring
<beanid="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
Asyoucansee,LocalValidatorFactoryBeanisconfiguredlikeanyotherSpringbean.Nowthatwehave
configuredLocalValidatorFactoryBean,let’sseehowitisusedtoperformvalidation.
The following example listing shows the FixedDepositServiceImpl class which requires that the
FixedDepositDetailsobjectisvalidatedbeforefixeddepositdetailsaresavedinthedatastore:
Examplelisting6-29–FixedDepositServiceImplclass–validatingFixedDepositDetailsobject
Project–ch06-jsr303-validation
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp/service
packagesample.spring.chapter06.bankapp.service;
importorg.springframework.validation.BeanPropertyBindingResult;
importorg.springframework.validation.Validator;
.....
@Service(value="FixedDepositService")
publicclassFixedDepositServiceImplimplementsFixedDepositService{
@Autowired
privateValidatorvalidator;
@Autowired
@Qualifier(value="myFixedDepositDao")
privateFixedDepositDaomyFixedDepositDao;
@Override
publicvoidcreateFixedDeposit(FixedDepositDetailsfixedDepositDetails)throwsException{
BeanPropertyBindingResultbindingResult=
newBeanPropertyBindingResult(fixedDepositDetails,"Errors");
validator.validate(fixedDepositDetails,bindingResult);
if(bindingResult.getErrorCount()>0){
logger.error("ErrorswerefoundwhilevalidatingFixedDepositDetailsinstance");
}else{
myFixedDepositDao.createFixedDeposit(fixedDepositDetails);
logger.info("Createdfixeddeposit");
}
}
}
Theaboveexamplelistingshows thatSpring’s Validatorimplementationisreferencedbythevalidator
field. As LocalValidatorFactoryBean implements Spring’s Validator interface,
LocalValidatorFactoryBean instance is assigned to the validator field. FixedDepositServiceImpl’s
createFixedDeposit method invokes Validator’s validate method to perform validation of
FixedDepositDetailsobject.
Oneoftheinterestingthingstonoticeinexamplelisting6-29isthatwearenotdealingwithJSR303API
to perform validation of FixedDepositDetails object. Instead, we have used Spring Validation API to
performvalidation.ThisispossiblebecauseLocalValidatorFactoryBeanimplementsvalidatemethodof
Spring’sValidatorinterfacetouseJSR303APItoperformvalidationofobjects,shieldingdevelopers
fromJSR303-specificAPIdetails.
As LocalValidatorFactoryBean implements JSR 303’s Validator and ValidatorFactory interfaces, you
havetheoptiontouseJSR303APItoperformvalidationofFixedDepositDetailsobject.Thefollowing
examplelistingshowsanalternativeimplementationofFixedDepositServiceImplclassthatmakesuseof
JSR303’sValidatortoperformvalidation:
Examplelisting6-30–FixedDepositServiceImplJsr303class-validatingFixedDepositDetailsobject
Project–ch06-jsr303-validation
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp/service
packagesample.spring.chapter06.bankapp.service;
importjavax.validation.ConstraintViolation;
importjavax.validation.Validator;
@Service(value="FixedDepositServiceJsr303")
publicclassFixedDepositServiceJsr303ImplimplementsFixedDepositService{
.....
@Autowired
privateValidatorvalidator;
@Autowired
@Qualifier(value="myFixedDepositDao")
privateFixedDepositDaomyFixedDepositDao;
@Override
publicvoidcreateFixedDeposit(FixedDepositDetailsfixedDepositDetails)throwsException{
Set<ConstraintViolation<FixedDepositDetails>>violations=
validator.validate(fixedDepositDetails);
Iterator<ConstraintViolation<FixedDepositDetails>>itr=violations.iterator();
if(itr.hasNext()){
logger.error("ErrorswerefoundwhilevalidatingFixedDepositDetailsinstance");
}else{
myFixedDepositDao.createFixedDeposit(fixedDepositDetails);
logger.info("Createdfixeddeposit");
}
}
}
TheaboveexamplelistingshowsthatJSR303’sValidatorimplementationisreferencedbythevalidator
field. As LocalValidatorFactoryBean implements JSR 303’s Validator interface,
LocalValidatorFactoryBean instance is assigned to the validator field. The createFixedDeposit method
validatesFixedDepositDetailsobjectbycallingValidator’svalidatemethod.Thevalidatemethodreturns
ajava.util.SetobjectthatcontainstheconstraintviolationsreportedbyJSR303provider.Youcancheck
thejava.util.Setobjectreturnedbythevalidatemethodtoknowifanyconstraintviolationswerereported.
For instance, in the above example listing, the createFixedDeposit method calls FixedDepositDao’s
createFixedDepositmethodonlyifjava.util.Setdoesn’tcontainanyconstraintviolations.
Inthissection,wesawhowtouseSpring’ssupportforJSR303toperformvalidationofobjects.Weonly
lookedatconstraints,like@NotNull,@Size,andsoon,thatareprovidedout-of-the-boxbyJSR303.Itis
importanttonotethatJSR303allowsyoutocreatecustomconstraintsandusetheminyourapplication.
Forinstance,youcancreatea@MyConstraintcustomconstraintandacorrespondingvalidatortoenforce
thatconstraintonobjects.
Let’snowlookatannotationsthatyoucanusetoprogrammaticallyconfigureSpringbeans.
6-11 Programmatically configuring Spring beans using
@Configurationand@Beanannotations
Youcanuse@Configurationand@BeanannotationstoprogrammaticallyconfigureSpringbeans.Ifyou
annotate a class with @Configuration annotation, it indicates that the class contains @Bean annotated
methodsthatreturnbeaninstancesmeanttoberegisteredwiththeSpringcontainer.
NOTETouse@Configurationannotatedclassesfordefiningbeans,CGLIBlibraryisrequiredbecause
Springextends@Configurationannotatedclassestoaddbehaviortothe@Beanannotatedmethods.
StartingwithSpring3.2,theCGLIBclassesarepackagedwithinthespring-coreJARfileitself;therefore,
youdon’tneedtoexplicitlyspecifythatyourprojectisdependentonCGLIBJARfile.
IMPORTchapter6/ch06-bankapp-configuration(ThisprojectshowstheMyBankapplicationthatuses
@Configuration and @Bean annotations to programmatically configure beans. To run the application,
executethemainmethodoftheBankAppclassofthisproject.)
The following example listing shows the BankAppConfiguration class that is annotated with
@Configurationannotation:
Examplelisting6-31–BankAppConfigurationclass-@Configurationand@Beanannotations
Project–ch06-bankapp-configuration
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp
packagesample.spring.chapter06.bankapp;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.context.annotation.Scope;
.....
@Configuration
publicclassBankAppConfiguration{
.....
@Bean(name="customerRegistrationService")
@Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)
publicCustomerRegistrationServicecustomerRegistrationService(){
returnnewCustomerRegistrationServiceImpl();
}
.....
}
BankAppConfigurationclassdefines@Beanannotatedmethodsthatreturnbeaninstances.@Bean’sname
attributespecifiesthenamewithwhichthereturnedbeaninstanceisregisteredwiththeSpringcontainer.
@Scopeannotationspecifiesthescope(singletonorprototype)ofthereturnedbeaninstance.
NOTE@Scope annotation is also used at the type-level to specify the scope of a Spring component.
Referexamplelisting6-14thatshowsusageof@Scopeannotationattype-level.
In example listing 6-31, the customerRegistrationService method returns an instance of
CustomerRegistrationServicebeanthatisregisteredwiththeSpringcontainerasaprototype-scopedbean
namedcustomerRegistrationService.ThecustomerRegistrationServicemethodhasthesameeffectasthe
followingbeandefinitionintheapplicationcontextXMLfile:
<beanid="customerRegistrationService"scope="prototype”
class="sample.spring.chapter06.bankapp.service.CustomerRegistrationServiceImpl"/>
Thefollowingtabledescribestheattributesof@Beanannotationthatyoucanusetoconfigurethebean
instance:
Valueoftypeattribute Description
Autowire
Sameas<bean>element’sautowireattribute(refersection4-6ofchapter4toknowmore
about autowire attribute). If the bean returned by the @Bean annotated method is
dependent on other beans, you can use autowire attribute to instruct Sp ring to p erform
autowiringofdependenciesbynameortype.
initM ethod Sameas<bean>element’sinit-method attribute (refer section 5-2 of chap ter 5 to know
moreaboutinit-methodattribute)
destroyMethod Same as <bean> element’s destroy-method attribute (refer section 5-2 of chapter 5 to
knowmoreaboutdestroy-methodattribute)
Itisimportanttonotethat@Beanannotatedmethodsmayalsobeannotatedwith@Lazy,@DependsOn,
@Primaryand@Scopeannotations.Theseannotationsapplytotheobjectinstancereturnedbythe@Bean
annotatedmethod.Forinstance,@DependsOnannotationspecifiestheimplicitdependenciesoftheobject
instance returned by the @Bean annotated method. Also, if the bean instance returned by @Bean
annotated method implements lifecycle interfaces (like InitializingBean and DisposableBean), and
Spring’s*Aware interfaces (like ApplicationContextAware,BeanNameAware, and so on), it’ll receive
callbacksfromtheSpringcontainer.
In the examples that we have seen so far, we created an instance of ClassPathXmlApplicationContext
class (an implementation of ApplicationContext interface) to represent the Spring container. If you are
using an @Configuration annotated class as the source of beans, you need to create an instance of
AnnotationConfigApplicationContext class (another implementation of ApplicationContext interface) to
representtheSpringcontainer.
The following example listing shows the BankApp class that creates an instance of
AnnotationConfigApplicationContext class and retrieves beans from the newly created
AnnotationConfigApplicationContextinstance:
Examplelisting6-32–BankAppclass-AnnotationConfigApplicationContextusage
Project–ch06-bankapp-configuration
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp
packagesample.spring.chapter06.bankapp;
importorg.springframework.context.annotation.AnnotationConfigApplicationContext;
publicclassBankApp{
publicstaticvoidmain(Stringargs[])throwsException{
AnnotationConfigApplicationContextcontext=
newAnnotationConfigApplicationContext(BankAppConfiguration.class);
.....
FixedDepositServiceFixedDepositService=context.getBean(FixedDepositService.class);
FixedDepositService.createFixedDeposit(newFixedDepositDetails(1,1000,
12,"someemail@somedomain.com"));
.....
}
}
In the above example listing, the BankAppConfiguration class is passed as an argument to the
AnnotationConfigApplicationContext’s constructor. As AnnotationConfigApplicationContext class
implementsApplicationContextinterface,youcanaccessregisteredbeansinthesamewayasincaseof
ClassPathXmlApplicationContext.
You should note that @Bean annotated methods can also be defined in @Component and JSR 330’s
@Named annotated classes.Incase you have definedbeans inmultiple@Configuration, @Component
and @Named annotated classes, pass all these classes to the AnnotationConfigApplicationContext’s
constructor.
The following example listing shows @Bean annotated methods of BankAppConfiguration class that
returnaBeanFactoryPostProcessorandaBeanPostProcessorimplementation:
Example listing 6-33 – BankAppConfiguration class – defining BeanFactoryPostProcessor and
BeanPostProcessorbeans
Project–ch06-bankapp-configuration
Sourcelocation-src/main/java/sample/spring/chapter06/bankapp
packagesample.spring.chapter06.bankapp;
importorg.springframework.context.annotation.Bean;
@Configuration
publicclassBankAppConfiguration{
.....
@Bean
publicExampleBeanPostProcessorexampleBeanPostProcessor(){
returnnewExampleBeanPostProcessor();
}
@Bean
publicstaticBeanNamePrinterBeanFactoryPostProcessorapplicationConfigurer(){
returnnewBeanNamePrinterBeanFactoryPostProcessor();
}
}
In the aboveexample listing,ExampleBeanPostProcessor instance representsa BeanPostProcessor that
prints a message on the console before and after a newly created bean instance is initialized, and
BeanNamePrinterBeanFactoryPostProcessor instance represents a BeanFactoryPostProcessor
implementationthatprintsnamesofallthebeansregisteredwiththeSpringcontainer.
Ifyougotoch06-bankapp-configurationprojectandexecuteBankApp’smainmethod,you’llnoticethat
theBeanNamePrinterBeanFactoryPostProcessor is invoked before any bean defined in @Configuration
annotatedclassiscreatedbytheSpringcontainer,andtheExampleBeanPostProcessor is invoked each
timeanewbeaninstanceiscreatedbytheSpringcontainer.Thisshowsthatwhetheryouconfigurebeans
declaratively (via application context XML file) or programmatically (via @Configuration annotated
class), beans that implement callback interfaces (like ApplicationContextAware, BeanNameAware,
InitializingBean, DisposableBean, BeanFactoryPostProcessor, and so on) receive callback from the
Springcontainer.
6-12Summary
ThischapterlookedatannotationsthatyoucanusetosimplifydevelopingSpringapplications.Welooked
at how to designate a bean class as a Spring component using Spring’s @Component, @Service,
@Repositoryand@Controllerannotations, perform classpathscanning toautomaticallyregister Spring
components with container, validate objects using Spring Validation API and JSR 303’s annotations,
performdependencyinjectionusingSpring’s@Autowired,JSR330’s@InjectandJSR250’s@Resource
annotations, anduse@Configurationand@Bean annotations to configure beans programmatically. The
nextchaptershowshowSpringsimplifiesinteractingwithdatabases.
Chapter7-DatabaseinteractionusingSpring
7-1Introduction
SpringsimplifiesinteractionwithdatabasesbyprovidingalayerofabstractionontopofJDBC.Spring
also simplifies using ORM (Object Relational Mapping) frameworks, like Hibernate
(http://www.hibernate.org/) and MyBatis (http://www.mybatis.org), for database interaction. In this
chapter, we’ll look at examples that demonstrate how Spring simplifies developing applications that
interactwithdatabases.
NOTETheexamplesdescribedinthischaptermakeuseofHibernate4.Ifyouareusing
Hibernate 3, the changes that you’ll need to make to the configuration are specified at
relevantplaces.
We’llbeginthischapterbylookingatasampleapplicationthatusesSpring’sJDBCabstractiontointeract
with MySQL database. After that, we we’ll develop the same application using Spring’s support for
Hibernate framework. We’ll wrap this chapter by looking at Spring’s support for programmatic and
declarativetransactionmanagement.
Let’sfirstlookattheMyBankapplication’srequirementsthatwe’llbedevelopinginthischapter.
7-2MyBankapplication’srequirements
MyBankapplicationisaninternetbankingapplicationthatallowsbankcustomerstocheckbankaccount
details, generate bank statement, create fixed deposits, request cheque book, and so on. The following
figure shows the BANK_ACCOUNT_DETAILSand FIXED_DEPOSIT_DETAILS tables in which
MyBankapplication’sdataisstored:
Figure7-1DatabasetablesusedbytheMyBankapplication
BANK_ACCOUNT_DETAILS table contains information about bank accounts, and
FIXED_DEPOSIT_DETAILS table contains information about fixed deposits. The above figure shows
that there is many-to-one relationship between FIXED_DEPOSIT_DETAILS and
BANK_ACCOUNT_DETAILS tables. When a bank customer opens a new fixed deposit, the fixed
deposit amount is deducted from the BANK_ACCOUNT_DETAILS table’s BALANCE_AMOUNT
column,andthefixeddepositdetailsaresavedintheFIXED_DEPOSIT_DETAILStable.
ThecolumnsofBANK_ACCOUNT_DETAILStableare:
·ACCOUNT_ID–accountidentifierthatuniquelyidentifiesacustomer’sbankaccount.
· BALANCE_AMOUNT – holds the current balance in the bank account. When a customer
requestsforopeningafixeddeposit,thefixeddepositamountisdeductedfromthiscolumn.
·LAST_TRANSACTION_TS–specifiesthedate/timewhenthelasttransactionwasperformed
onthisaccount.
ThecolumnsofFIXED_DEPOSIT_DETAILStableare:
·FIXED_DEPOSIT_ID–fixeddepositidentifierthatuniquelyidentifiesafixeddeposit.Whena
customeropensafixeddeposit,auniquefixeddepositidentifier isgeneratedby theMyBankfor
futurereferencebythecustomer.ThevalueofFIXED_DEPOSIT_IDcolumnisauto-generatedby
MySQLdatabase.
·ACCOUNT_ID–foreignkeythatidentifiesthebankaccountwithwhichthefixeddepositis
associated.Everyquarter,interestgeneratedbythefixeddepositiscreditedintothebankaccount
identifiedbythiscolumn.
·FD_CREATION_DATE–thedateonwhichthefixeddepositwascreated
·AMOUNT–fixeddepositamount
·TENURE–fixeddeposittenure(inmonths).Fixeddeposittenuremustbegreaterthanorequal
to12monthsandlessthanorequalto60months.
·ACTIVE–indicateswhetherthefixeddepositiscurrentlyactiveornot.Anactivefixeddeposit
generatesinterestonthefixeddepositamount.
Let’snowlookathowwecancreatetheMyBankapplicationusingSpring’sJDBCmodule.
7-3DevelopingtheMyBankapplicationusingSpring’sJDBCmodule
Spring’sJDBCmodulesimplifiesinteractionwithdatasourcesbytakingcareoflowerleveldetailsof
openingandclosingconnections,managingtransactions,processingexceptions,andsoon.Inthissection,
we’ll develop the MyBank application (as described in the previous section) using Spring’s JDBC
module. For the sake of simplicity, we’ll develop only the services and DAOs that form part of the
MyBankapplication.
IMPORTchapter7/ch07-bankapp-jdbc(ThisprojectshowstheMyBankapplicationthatusesSpring’s
JDBC module to interact with the database. To run the application, execute the main method of the
BankAppclass of this project. Before executing BankApp’s main method, install MySQL database and
executethespring_bank_app_db.sqlSQLscriptcontainedinthesqlfolderofch07-bankapp-jdbcproject.
Executing spring_bank_app_db.sql script creates SPRING_BANK_APP_DB database and adds
BANK_ACCOUNT_DETAILS and FIXED_DEPOSIT_DETAILS tables to the
SPRING_BANK_APP_DB database. Also, modify the src/main/resources/META-
INF/spring/database.propertiesfiletopointtoyourMySQLinstallation.)
InMyBankapplication,youfirstneedtoconfigureajavax.sql.DataSourceobjectthatidentifiesthedata
sourcewithwhichtheMyBankapplicationinteracts,followedbyimplementingDAOsthatuseSpring’s
JDBCmoduleclassestointeractwiththedatasource.Let’slookateachofthesestepsindetail.
Configuringadatasource
If you are using Spring to develop a standalone application, you can configure the data source in the
application context XML file. If you are developing an enterprise application, you can define a data
source that is bound to the application server’s JNDI, and retrieve the JNDI-bound data source in the
applicationcontextXMLfileforusebytheapplication.Incaseofch07-bankapp-jdbcproject,thedata
sourceisconfiguredintheapplicationcontextXMLfile.
The following example listing shows how MyBank application’s data source is configured in the
applicationcontextXMLfile:
Examplelisting7-1–applicationContext.xml–datasourceconfiguration
Project–ch07-bankapp-jdbc
Sourcelocation-src/main/resources/META-INF/spring
<context:property-placeholderlocation="classpath*:META-INF/spring/database.properties"/>
<beanid="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
<propertyname="driverClassName"value="${database.driverClassName}"/>
<propertyname="url"value="${database.url}"/>
<propertyname="username"value="${database.username}"/>
<propertyname="password"value="${database.password}"/>
</bean>
Intheaboveexamplelisting,the<property-placeholder>element(refersection5-4ofchapter5formore
details)ofSpring’scontextschemaloadspropertiesfromtheMETA-INF/spring/database.propertiesfile
andmakesthemavailabletobeandefinitionsintheapplicationcontextXMLfile.ThedataSourcebean
representsajavax.sql.DataSourceobjectthatactsasafactoryforcreatingconnectionstothedatasource.
BasicDataSourceclassisan implementation of javax.sql.DataSource interfacethat supportsconnection
pooling feature. BasicDataSource class is part of Apache Commons DBCP project
(http://commons.apache.org/dbcp/) and supports database connection pooling feature. The values for
driverClassName, url, username and password properties of BasicDataSource class comes from the
propertiesdefinedinthedatabase.propertiesfile.TheclosemethodofBasicDataSourceclassclosesall
idle connections in the pool. As the bean definition for the BasicDataSource class specifies value of
destroy-methodattributeasclose,allidleconnectionsinthepoolareclosedwhenthedataSourcebean
instanceisdestroyedbytheSpringcontainer.
ConfiguringadatasourceinJavaEEenvironments
If you are developing an enterprise application that is deployed in an application server, you can use
Spring’sjeeschema’s<jndi-lookup>elementtomaketheJNDI-bounddatasourceavailableasaSpring
beanintheApplicationContext:
<jee:jndi-lookupjndi-name="java:comp/env/jdbc/bankAppDb"id="dataSource"/>
here,jndi-nameattributespecifiestheJNDInamewithwhichthejavax.sql.DataSourceobjectisboundto
theJNDI,andidattributespecifiesthenamewithwhichthejavax.sql.DataSourceobjectisregisteredas
abeanintheApplicationContext.
Let’snowlookatsomeoftheSpring’sJDBCmoduleclassesthatyoucanuseinyourDAOstointeract
withthedatabase.
CreatingDAOsthatuseSpring’sJDBCmoduleclasses
Spring’sJDBCmoduledefinesmultipleclassesthatsimplifydatabaseinteraction.We’llfirstlookatthe
JdbcTemplateclassthatisattheheartofSpring’sJDBCmodule.Theotherclassesthatwe’lldiscussin
this section are NamedParameterJdbcTemplate and SimpleJdbcInsert. To learn about other Spring’s
JDBCmoduleclasses,refertoSpring’sreferencedocumentation.
JdbcTemplate
JdbcTemplateclasstakescareofmanagingConnection,StatementandResultSetobjects,catchingJDBC
exceptions and translating them into easily understandable exceptions (like
IncorrectResultSetColumnCountException and CannotGetJdbcConnectionException), performing batch
operations,andsoon.AnapplicationdeveloperonlyneedstoprovideSQLtotheJdbcTemplateclass,
andextractresultsaftertheSQLisexecuted.
AsJdbcTemplateactsasawrapperaroundjavax.sql.DataSourceobject,youdon’tneedtodirectlydeal
withajavax.sql.DataSourceobject.AJdbcTemplateinstanceistypicallyinitializedwithreferencetothe
javax.sql.DataSource object from which it needs to obtain connections, as shown in the following
examplelisting:
Examplelisting7-2–applicationContext.xml–JdbcTemplateconfiguration
Project–ch07-bankapp-jdbc
Sourcelocation-src/main/resources/META-INF/spring
<beanid="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate">
<propertyname="dataSource"ref="dataSource"/>
</bean>
<beanid="dataSource"class="org.apache.commons.dbcp.BasicDataSource".....>
.....
</bean>
TheaboveexamplelistingshowsthattheJdbcTemplateclassdefinesadataSourcepropertythatrefersto
ajavax.sql.DataSourceobject.
If your application uses a JNDI-bound data source, use the <jndi-lookup> element of jee schema to
registertheJNDI-bounddatasourceasabeanwiththeSpringcontainer.Now,thetheJdbcTemplateclass
can refer to the javax.sql.DataSource bean registered by the <jndi-lookup> element, as shown in the
followingexamplelisting:
Examplelisting7-3–JdbcTemplateconfigurationforJNDI-bounddatasource
<beans.....
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation=".....
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-4.0.xsd">
<beanid="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate">
<propertyname="dataSource"ref="dataSource"/>
</bean>
<jee:jndi-lookupjndi-name="java:comp/env/jdbc/bankAppDb"id="dataSource"/>
.....
</beans>
Intheaboveexamplelisting,referencetoSpring’sjeeschemaisincludedintheapplicationcontextXML
file. The <jndi-lookup> element retrieves javax.sql.DataSource object from JNDI and exposes it as a
beannameddataSource,whichisreferencedbytheJdbcTemplateclass.
JdbcTemplateinstanceisthread-safe,whichmeansmultipleDAOsofyourapplicationcansharethesame
instance of JdbcTemplate class to interact with the database. The following example listing shows
FixedDepositDaoImpl’screateFixedDepositmethodthatmakesuseofJdbcTemplatetosavefixeddeposit
detailsinthedatabase:
Examplelisting7-4–FixedDepositDaoImplclass–savingdatausingJdbcTemplate
Project–ch07-bankapp-jdbc
Sourcelocation-src/main/java/sample/spring/chapter07/bankapp/dao
packagesample.spring.chapter07.bankapp.dao;
importjava.sql.*;
importorg.springframework.jdbc.core.JdbcTemplate;
importorg.springframework.jdbc.core.PreparedStatementCreator;
importorg.springframework.jdbc.support.GeneratedKeyHolder;
importorg.springframework.jdbc.support.KeyHolder;
importorg.springframework.stereotype.Repository;
@Repository(value="FixedDepositDao")
publicclassFixedDepositDaoImplimplementsFixedDepositDao{
@Autowired
privateJdbcTemplatejdbcTemplate;
.....
publicintcreateFixedDeposit(finalFixedDepositDetailsfixedDepositDetails){
finalStringsql=
"insertintofixed_deposit_details(account_id,fixedDeposit_creation_date,amount,
tenure,active)values(?,?,?,?,?)";
KeyHolderkeyHolder=newGeneratedKeyHolder();
jdbcTemplate.update(newPreparedStatementCreator(){
@Override
publicPreparedStatementcreatePreparedStatement(Connectioncon)
throwsSQLException{
PreparedStatementps=con.prepareStatement(sql,newString[]{
"fixed_deposit_id"});
ps.setInt(1,fixedDepositDetails.getBankAccountId());
ps.setDate(2,
newjava.sql.Date(fixedDepositDetails.getFixedDepositCreationDate().getTime()));
.....
returnps;
}
},keyHolder);
returnkeyHolder.getKey().intValue();
}
.....
}
In the above example listing, the FixedDepositDaoImpl class is annotated with Spring’s @Repository
annotationbecausetheFixedDepositDaoImplclassrepresentsaDAOclass.JdbcTemplateinstancethat
we configured in the application context XML file (refer example listing 7-2) is autowired into the
FixedDepositDaoImpl class. JdbcTemplate’s update method accepts an instance of
PreparedStatementCreator and an instance of KeyHolder. PreparedStatementCreator is used to perform
insert,updateordeleteoperationonthedatabase.Spring’sKeyHolderinterfacerepresentsaholderfor
thekeysthatareauto-generatedwheninsertSQLstatementsareexecuted.GeneratedKeyHolderclassis
thedefaultimplementationofKeyHolderinterface.
Once the INSERT SQL statement is successfully executed, the auto-generated keys are added to the
GeneratedKeyHolderinstance.Youcanextracttheauto-generatedkeysfromtheGeneratedKeyHolderby
callingthe getKey method.In example listing 7-4, the createFixedDeposit method inserts fixed deposit
detailsintotheFIXED_DEPOSIT_DETAILStableandreturnstheauto-generatedkey.Examplelisting7-
4showsthatyoudon’tneedtoworryaboutcatchingSQLExceptionthatmaybethrownbytheexecution
of PreparedStatement. This is because JdbcTemplate is responsible for catching SQLExceptions and
handlingthem.
Let’snowlookatNamedParameterJdbcTemplateclass.
NamedParameterJdbcTemplate
Asshowninexamplelisting7-4,ifyouareusingJdbcTemplateclassfordatabaseinteraction,parameters
to be passed to the SQL statement are specified using ? placeholders. Spring’s
NamedParameterJdbcTemplateisawrapperaroundJdbcTemplateinstancethatallowsyoutousenamed
parametersintheSQLstatementratherthanusing?.
ThefollowingexamplelistingshowshowtheNamedParameterJdbcTemplateclassisconfiguredinthe
applicationcontextXMLfile:
Examplelisting7-5–applicationContext.xml–NamedParameterJdbcTemplateconfiguration
Project–ch07-bankapp-jdbc
Sourcelocation-src/main/resources/META-INF/spring
<beanid="namedJdbcTemplate"
class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-argindex="0"ref="dataSource"/>
</bean>
<beanid="dataSource"class="org.apache.commons.dbcp.BasicDataSource".....>
.....
</bean>
The above example listing shows that the NamedParameterJdbcTemplate class accepts
javax.sql.DataSourceobjectasconstructorargument.
The following example listing shows the FixedDepositDaoImpl class that uses
NamedParameterJdbcTemplatetofetchfixeddepositdetailsfromtheFIXED_DEPOSIT_DETAILStable:
Examplelisting7-6–FixedDepositDaoImplclass–NamedParameterJdbcTemplateusage
Project–ch07-bankapp-jdbc
Sourcelocation-src/main/java/sample/spring/chapter07/bankapp/dao
packagesample.spring.chapter07.bankapp.dao;
importjava.sql.ResultSet;
importorg.springframework.jdbc.core.RowMapper;
importorg.springframework.jdbc.core.namedparam.MapSqlParameterSource;
importorg.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
importorg.springframework.jdbc.core.namedparam.SqlParameterSource;
.....
@Repository(value="FixedDepositDao")
publicclassFixedDepositDaoImplimplementsFixedDepositDao{
.....
@Autowired
privateNamedParameterJdbcTemplatenamedParameterJdbcTemplate;
.....
publicFixedDepositDetailsgetFixedDeposit(finalintFixedDepositId){
finalStringsql="select*fromfixed_deposit_detailswherefixed_deposit_id
=:FixedDepositId";
SqlParameterSourcenamedParameters=newMapSqlParameterSource(
"FixedDepositId",FixedDepositId);
returnnamedParameterJdbcTemplate.queryForObject(sql,namedParameters,
newRowMapper<FixedDepositDetails>(){
publicFixedDepositDetailsmapRow(ResultSetrs,introwNum)throwsSQLException{
FixedDepositDetailsfixedDepositDetails=newFixedDepositDetails();
fixedDepositDetails.setActive(rs.getString("active"));
.....
returnfixedDepositDetails;
}
});
}
}
NamedParameterJdbcTemplateinstance that we configured in the application context XML file (refer
examplelisting7-5)isautowiredintoFixedDepositDaoImplclass.Intheaboveexamplelisting,theSQL
query passed to NamedParameterJdbcTemplate’s queryForObject method contains a named parameter
FixedDepositId. The named parameter values are supplied via an implementation of Spring’s
SqlParameterSource interface. MapSqlParameterSource class is an implementation of
SqlParameterSourceinterfacethatstoresnamedparameters(andtheirvalues)inajava.util.Map.Inthe
above example listing, MapSqlParameterSource instance holds value of FixedDepositId named
parameter.NamedParameterJdbcTemplate’squeryForObjectmethodexecutesthesuppliedSQLqueryand
returnsasingleobject.Spring’sRowMapperobjectisusedformappingeachreturnedrowtoanobject.
In the above example listing, RowMapper maps the returned row in the ResultSet to a
FixedDepositDetailsobject.
Let’snowlookatSpring’sSimpleJdbcInsertclass.
SimpleJdbcInsert
SimpleJdbcInsertclassmakesuseofdatabasemetadatatosimplifycreatingabasicSQLinsertstatement
foratable.
ThefollowingexamplelistingshowstheBankAccountDaoImplclassthatmakesuseofSimpleJdbcInsert
toinsertbankaccountdetailsintoBANK_ACCOUNT_DETAILStable:
Examplelisting7-7–BankAccountDaoImplclass–SimpleJdbcInsertusage
Project–ch07-bankapp-jdbc
Sourcelocation-src/main/java/sample/spring/chapter07/bankapp/dao
packagesample.spring.chapter07.bankapp.dao;
importjavax.sql.DataSource;
importorg.springframework.jdbc.core.simple.SimpleJdbcInsert;
.....
@Repository(value="bankAccountDao")
publicclassBankAccountDaoImplimplementsBankAccountDao{
privateSimpleJdbcInsertinsertBankAccountDetail;
@Autowired
privatevoidsetDataSource(DataSourcedataSource){
this.insertBankAccountDetail=newSimpleJdbcInsert(dataSource)
.withTableName("bank_account_details")
.usingGeneratedKeyColumns("account_id");
}
@Override
publicintcreateBankAccount(finalBankAccountDetailsbankAccountDetails){
Map<String,Object>parameters=newHashMap<String,Object>(2);
parameters.put("balance_amount",bankAccountDetails.getBalanceAmount());
parameters.put("last_transaction_ts",newjava.sql.Date(
bankAccountDetails.getLastTransactionTimestamp().getTime()));
Numberkey=insertBankAccountDetail.executeAndReturnKey(parameters);
returnkey.intValue();
}
.....
}
AsthesetDataSourcemethodisannotatedwith@Autowiredannotation,javax.sql.DataSourceobjectis
passed as an argument to the setDataSource method. In the setDataSource method, an instance of
SimpleJdbcInsertiscreatedbypassingreferencetojavax.sql.DataSourceobjecttotheSimpleJdbcInsert
constructor.
SimpleJdbcInsert’s withTableName method sets the name of the table into which you want to insert
record(s). As we want to insert bank account details into BANK_ACCOUNT_DETAILS table,
‘bank_account_details’ string value is passed as argument to the withTableName method.
SimpleJdbcInsert’s usingGeneratedKeyColumns method sets names of table columns that contain auto-
generatedkeys.IncaseofBANK_ACCOUNT_DETAILStable,ACCOUNT_IDcolumncontainstheauto-
generatedkey;therefore,‘account_id’stringvalueispassedtotheusingGeneratedKeyColumnsmethod.
The actual insert operation is performed by calling SimpleJdbcInsert’s executeAndReturnKey method.
The executeAndReturnKey method accepts a java.util.Map type argument that contains table column
names and their corresponding values, and returns the generated key value. You should note that the
SimpleJdbcInsertclassinternallyusesJdbcTemplatetoexecutetheactualSQLinsertoperation.
IfyoulookatBankAccountDaoImplclassofch07-bankapp-jdbcproject,you’llnoticethatitmakesuseof
both SimpleJdbcInsert and JdbcTemplate classes to interact with the database. Similarly,
FixedDepositDaoImpl class of ch07-bankapp-jdbc project uses both JdbcTemplate and
NamedParameterJdbcTemplate classes for database interaction. This shows that you can use a
combinationofSpring’sJDBCmoduleclassestointeractwithadatabase.
NOTEAsch07-bankapp-jdbcprojectmakesuseofSpring’sJDBCmoduleandusesSpring’sTransaction
Managementfeature(explainedinsection7-5),thepom.xmlfileofch07-bankapp-jdbcprojectdepends
onspring-jdbcandspring-txJARfiles.
Let’snowlookatBankAppclassofch07-bankapp-jdbcprojectthatcreatesabankaccountandopensa
fixeddepositcorrespondingtoit.
BankAppclass
BankApp class of ch07-bankapp-jdbc project runs the MyBank application as a standalone Java
application.BankApp’smainmethodcreatesabankaccountintheBANK_ACCOUNT_DETAILStable
and creates a fixed deposit (corresponding to the newly created bank account) in the
FIXED_DEPOSIT_DETAILStable.
ThefollowingexamplelistingshowstheBankAppclass:
Examplelisting7-8–BankAppclass
Project–ch07-bankapp-jdbc
Sourcelocation-src/main/java/sample/spring/chapter07/bankapp
packagesample.spring.chapter07.bankapp;
.....
publicclassBankApp{
privatestaticLoggerlogger=Logger.getLogger(BankApp.class);
publicstaticvoidmain(Stringargs[])throwsException{
ApplicationContextcontext=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
BankAccountServicebankAccountService=context.getBean(BankAccountService.class);
BankAccountDetailsbankAccountDetails=newBankAccountDetails();
.....
intbankAccountId=bankAccountService.createBankAccount(bankAccountDetails);
.....
FixedDepositServiceFixedDepositService=context.getBean(FixedDepositService.class);
FixedDepositDetailsfixedDepositDetails=newFixedDepositDetails();
.....
intFixedDepositId=FixedDepositService.createFixedDeposit(fixedDepositDetails);
.....
}
}
Intheaboveexamplelisting,theBankAccountServiceobjectinteractswithBankAccountDaoImpl(refer
example listing 7-7) to create a bank account, and FixedDepositService object interacts with
FixedDepositDaoImpl(referexamplelisting7-4and7-6)objecttoopenafixeddepositcorrespondingto
thenewlycreatedbankaccount.IfyouexecuteBankApp’smainmethod,you’llfindthatanewrecordis
insertedintobothBANK_ACCOUNT_DETAILSandFIXED_DEPOSIT_DETAILStables.
In this section, we looked at how Spring’s JDBC module simplifies updating or fetching data from
databases.Spring’sJDBCmodulecanalsobeusedforthefollowingpurposes:
·executingstoredproceduresandfunctions.Forinstance,youcanuseSpring’sSimpleJdbcCall
classforexecutingstoredproceduresandfunctions
·executingpreparedstatementsinbatches
· accessing relational databases in an object-oriented manner. For instance, you can extend
Spring’s MappingSqlQuery class to create an SQL query and map the returned ResultSet to a
domainobject.
·configuringanembeddeddatabaseinstance.Forinstance,youcanSpring’sjdbcschematocreate
an instance ofHSQL, H2 or Derbydatabases,and register thedatabaseinstance withtheSpring
containerasabeanoftypejavax.sql.DataSource.
Let’s now look at how we can use Spring’s support for Hibernate ORM framework to interact with
databases.
7-4DevelopingtheMyBankapplicationusingHibernate
Spring’s ORM module provides integration with Hibernate, Java Persistence API (JPA), MyBatis, and
JavaDataObjects(JDO).Inthissection,we’llseehowSpringsimplifiesusingHibernateframeworkfor
database interaction. As Hibernate itself is a JPA provider, we’ll use JPA annotations to map our
persistententityclassestodatabasetables.
IMPORT chapter 7/ch07-bankapp-hibernate (This project shows the MyBank application that uses
Hibernatetointeractwiththedatabase.Toruntheapplication,executethemainmethodoftheBankApp
classofthisproject.)
Let’sfirstlookathowtoconfigureHibernate’sSessionFactoryinstance.
ConfiguringSessionFactoryinstance
SessionFactoryisafactoryforcreatingHibernate’sSessionobject.ItistheSessionobjectthatisusedby
DAOs to perform create, read, delete and update operations on persistent entities. Spring’s
org.springframework.orm.hibernate4.LocalSessionFactoryBean(aFactoryBeanimplementation)createsa
SessionFactoryinstancethatcanbeusedbyDAOclassesforobtainingaSessioninstance.
NOTE If you want to use JPA’s EntityManager in your application’s DAOs for database interaction,
configure Spring’s LocalContainerEntityManagerFactoryBean instead of
org.springframework.orm.hibernate4.LocalSessionFactoryBean.
The following example listing shows how the LocalSessionFactoryBean class is configured in the
applicationcontextXMLfile:
Examplelisting7-9–applicationContext.xml-LocalSessionFactoryBeanconfiguration
Project–ch07-bankapp-hibernate
Sourcelocation-src/main/java/sample/spring/chapter07/bankapp
<beanid="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<propertyname="dataSource"ref="dataSource"/>
<propertyname="packagesToScan"value="sample.spring"/>
</bean>
ThedataSourcepropertyspecifiesreferencetoabeanoftypejavax.sql.DataSource.ThepackagesToScan
propertyspecifiesthepackage(s)underwhichSpringlooksforpersistentclasses.Forinstance,theabove
example listing specifies that if a persistent class is annotated with JPA’s @Entity annotation, and is
located inside sample.spring package (or its sub-packages), it is automatically detected by
org.springframework.orm.hibernate4.LocalSessionFactoryBean.AnalternativetousingpackagesToScan
propertyistoexplicitlyspecifyallthepersistentclassesusingannotatedClassesproperty,asshowninthe
followingexamplelisting:
Examplelisting7-10LocalSessionFactoryBean’sannotatedClassesproperty
<beanid="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<propertyname="dataSource"ref="dataSource"/>
<propertyname="annotatedClasses">
<list>
<value>sample.spring.chapter07.bankapp.domain.BankAccountDetails</value>
<value>sample.spring.chapter07.bankapp.domain.FixedDepositDetails</value>
</list>
</property>
</bean>
In the above example listing, annotatedClasses property (of type java.util.List) lists down all the
persistentclassesintheapplication.
NOTEIfyouareusingHibernate3,useSpring’s
org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBeaninsteadof
org.springframework.orm.hibernate4.LocalSessionFactoryBeantocreateaSessionFactoryinstance.
As we have configured LocalSessionFactoryBean, let’s now look at DAOs that make use of
SessionFactoryinstancecreatedbyLocalSessionFactoryBeantoperformdatabaseoperations.
CreatingDAOsthatuseHibernateAPIfordatabaseinteraction
Tointeractwiththedatabase,DAOsneedaccesstoHibernate’sSessionobject.ToaccessHibernate’s
Session object, inject the SessionFactory instance created by LocalSessionFactoryBean bean (refer
example listing 7-9) into DAOs, and use the injected SessionFactory instance to obtain a Session
instance.
ThefollowingexamplelistingshowstheFixedDepositDaoImplclassthatusesHibernateAPIforsaving
andretrievingtheFixedDepositDetailspersistententity:
Examplelisting7-11–FixedDepositDaoImplclass-HibernateAPIusage
Project–ch07-bankapp-hibernate
Sourcelocation-src/main/java/sample/spring/chapter07/bankapp/dao
packagesample.spring.chapter07.bankapp.dao;
importorg.hibernate.SessionFactory;
.....
@Repository(value="FixedDepositDao")
publicclassFixedDepositDaoImplimplementsFixedDepositDao{
@Autowired
privateSessionFactorysessionFactory;
publicintcreateFixedDeposit(finalFixedDepositDetailsfixedDepositDetails){
sessionFactory.getCurrentSession().save(fixedDepositDetails);
returnfixedDepositDetails.getFixedDepositId();
}
publicFixedDepositDetailsgetFixedDeposit(finalintFixedDepositId){
Stringhql="fromFixedDepositDetailsasFixedDepositDetailswhere"
+"FixedDepositDetails.FixedDepositId="
+FixedDepositId;
return(FixedDepositDetails)sessionFactory.getCurrentSession()
.createQuery(hql).uniqueResult();
}
}
The above example listing shows that an instance of SessionFactory is autowired into
FixedDepositDaoImplinstance,whichislaterusedbycreateFixedDepositandgetFixedDepositmethods
tosaveandretrieveFixedDepositDetailspersistententity.AutowiringofSessionFactoryinstanceshows
thatyoucanautowireanobjectcreatedbySpring’sFactoryBeanimplementationbysimplydefiningthe
type created by the FactoryBean and annotating it with @Autowired annotation (refer section 3-9 of
chapter 3 to know more about Spring’s FactoryBean interface). The createFixedDeposit and
getFixedDeposit methods call SessionFactory’s getCurrentSession method to obtain an instance of
Session. It is important to note that the call to getCurrentSession method returns the Session object
associatedwiththecurrenttransactionorthread.UsinggetCurrentSessionmethodisusefulifyouwant
Springtomanagetransactions,whichisthecaseinMyBankapplication.
Let’snowlookatSpring’sprogrammaticanddeclarativetransactionmanagementfeature.
7-5TransactionmanagementusingSpring
SpringFrameworksupportsbothprogrammaticanddeclarativetransactionmanagement.Inprogrammatic
transactionmanagement,Spring’stransactionmanagementabstractionisusedtoexplicitlystart,endand
committransactions.Indeclarativetransactionmanagement,youannotatemethodsthatexecutewithina
transactionwithSpring’s@Transactionalannotation.
Let’sfirstlookatthetransactionmanagementrequirementofMyBankapplicationdescribedinsection7-
2.
MyBank’stransactionmanagementrequirements
Insection7-2,itwasmentionedthatwhenabankcustomeropensanewfixeddeposit,thefixeddeposit
amountisdeductedfromtheBANK_ACCOUNT_DETAILStable’sBALANCE_AMOUNTcolumn,and
thefixeddepositdetailsaresavedintheFIXED_DEPOSIT_DETAILStable.
ThefollowingsequencediagramshowsthatthecreateFixedDepositmethodofFixedDepositServiceImpl
classsavesthefixeddepositdetailsinFIXED_DEPOSIT_DETAILStableanddeductsthefixeddeposit
amountfromthecorrespondingbankaccountinBANK_ACCOUNT_DETAILStable:
Figure7-2 The sequence of actions performed by MyBank application when a customer opens a new
fixeddeposit
The above sequence diagram shows that FixedDepositServiceImpl’s createFixedDeposit method calls
FixedDepositDaoImpl’s createFixedDeposit method and BankAccountDaoImpl’s subtractFromAccount
method. FixedDepositDaoImpl’s createFixedDeposit method saves the fixed deposit details in the
FIXED_DEPOSIT_DETAILS table. BankAccountDaoImpl’s subtractFromAccount method first checks
thatthecustomer’sbankaccountcontainssufficientbalanceto createthefixeddepositof the specified
amount. If sufficient balance is available in customer’s bank account, the subtractFromAccount method
deductsthefixeddepositamountfromthecustomer’sbankaccount.Ifsufficientbalanceisn’tavailable,
an exception is thrown by BankAccountDaoImpl’s subtractFromAccount method. If
FixedDepositDaoImpl’s createFixedDeposit or BankAccountDaoImpl’s subtractFromAccount method
failsforsomereason,thesystemwillbeleftinaninconsistentstate;therefore,boththemethodsmustbe
executedwithinatransaction.
Let’s now look at how you can use Spring to programmatically manage transactions in the MyBank
application.
Programmatictransactionmanagement
YoucanprogrammaticallymanagetransactionsbyusingSpring’sTransactionTemplateclassorbyusing
an implementation of Spring’s PlatformTransactionManager interface. TransactionTemplate class
simplifies transaction management by taking care of initiating and committing transactions. You only
needtoprovideanimplementationofSpring’sTransactionCallbackinterfacethatcontainsthecodetobe
executedwithinatransaction.
IMPORT chapter 7/ch07-bankapp-tx-jdbc (This project shows the MyBank application that uses
Spring’sTransactionTemplateclassforprogrammaticallymanagingtransactions.Toruntheapplication,
execute the main method of the BankApp class of this project. Create SPRING_BANK_APP_DB
database, and BANK_ACCOUNT_DETAILS and FIXED_DEPOSIT_DETAILS tables as described for
ch07-bankapp-jdbcproject)
ThefollowingexamplelistingshowshowtheTransactionTemplateclassisconfiguredintheapplication
contextXMLfile:
Examplelisting7-12–applicationContext.xml-TransactionTemplateconfiguration
Project–ch07-bankapp-tx-jdbc
Sourcelocation-src/main/resources/META-INF/spring
<beanid="dataSource"class="org.apache.commons.dbcp.BasicDataSource".....>
.....
</bean>
<beanid="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<propertyname="dataSource"ref="dataSource"/>
</bean>
<beanid="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<propertyname="transactionManager"ref="txManager"/>
<propertyname="isolationLevelName"value="ISOLATION_READ_UNCOMMITTED"/>
<propertyname="propagationBehaviorName"value="PROPAGATION_REQUIRED"/>
</bean>
TransactionTemplate’s transactionManager property refers to Spring’s PlatformTransactionManager
implementationthatisresponsibleformanagingtransactions.
TransactionTemplate’sisolationLevelNamepropertyspecifiesthetransactionisolationleveltobesetfor
thetransactionsmanagedbythetransactionmanager.ThevalueofisolationLevelNamepropertyrefersto
a constant defined by Spring’s TransactionDefinition interface. For instance,
ISOLATION_READ_UNCOMMITTED is a constant defined by TransactionDefinition interface that
indicatesthattheuncommittedchangesbyatransactioncanbereadbyothertransactions.
TransactionTemplate’s propagationBehaviorName property specifies the transaction propagation
behavior. The value of propagationBehaviorName property refers to a constant defined by Spring’s
TransactionDefinition interface. For instance, PROPAGATION_REQUIRED is a constant defined by
TransactionDefinitioninterfacethatindicates:
·ifamethodisnotinvokedwithinatransaction,thetransactionmanagerstartsanewtransaction
andexecutesthemethodinthenewlycreatedtransaction
·ifamethodisinvokedwithinatransaction,thetransactionmanagerexecutesthemethodinthe
sametransaction
Spring provides a couple ofbuilt-in PlatformTransactionManager implementations that you can choose
from, depending upon the data access technology used by your application. For instance,
DataSourceTransactionManageris appropriate for managing transactionsinapplications thatuseJDBC
forinteractingwithadatabase,HibernateTransactionManagerisappropriatewhenHibernateisusedfor
database interaction and JpaTransactionManager when JPA’s EntityManager is used for data access. In
example listing 7-12, TransactionTemplate’s transactionManager property refers to a
DataSourceTransactionManager instance because the MyBank application of ch07-bankapp-tx-jdbc
projectuses JDBC for data access. The example listing 7-12 shows that
DataSourceTransactionManager’s dataSource property refers to a javax.sql.DataSource object that
representsthedatabasewhosetransactionsaremanagedbytheDataSourceTransactionManagerinstance.
ThefollowingexamplelistingshowstheFixedDepositServiceImplclassthatusesTransactionTemplate
instancefortransactionmanagement:
Examplelisting7-13–FixedDepositServiceImplclassthatusesTransactionTemplate
Project–ch07-bankapp-tx-jdbc
Sourcelocation-src/main/java/sample/spring/chapter07/bankapp/service
packagesample.spring.chapter07.bankapp.service;
importorg.springframework.transaction.TransactionStatus;
importorg.springframework.transaction.support.TransactionCallback;
importorg.springframework.transaction.support.TransactionTemplate;
.....
@Service(value="FixedDepositService")
publicclassFixedDepositServiceImplimplementsFixedDepositService{
@Autowired
privateTransactionTemplatetransactionTemplate;
.....
@Override
publicintcreateFixedDeposit(finalFixedDepositDetailsfixedDepositDetails)throwsException{
transactionTemplate.execute(newTransactionCallback<FixedDepositDetails>(){
publicFixedDepositDetailsdoInTransaction(TransactionStatusstatus){
try{
myFixedDepositDao.createFixedDeposit(fixedDepositDetails);
bankAccountDao.subtractFromAccount(
fixedDepositDetails.getBankAccountId(),
fixedDepositDetails.getFixedDepositAmount()
);
}catch(Exceptione){status.setRollbackOnly();}
returnfixedDepositDetails;
}
});
returnfixedDepositDetails.getFixedDepositId();
}
.....
}
TheaboveexamplelistingshowsFixedDepositServiceImpl’screateFixedDepositmethod(referfigure7-
2formoredetails)thatsavesfixeddepositdetailsintheFIXED_DEPOSIT_DETAILStable,anddeducts
thefixeddepositamountfromthecorrespondingbankaccountintheBANK_ACCOUNT_DETAILStable.
You create an implementation of TransactionCallback interface to define the actions that you want to
executewithinatransaction.And,TransactionTemplate’sexecutemethodexecutestheactionscontained
in the TransactionCallback instance within a transaction. TransactionCallback interface defines a
doInTransaction method that you implement to provide the actions that should be executed within a
transaction. TransactionCallback’s doInTransaction method is invoked within a transaction by
TransactionTemplate’s executemethod.ThedoInTransaction method accepts a TransactionStatus object
thatyoucanusetocontroltheoutcomeofthetransaction.Inexamplelisting7-13,TransactionCallback’s
doInTransaction method contains calls to FixedDepositDaoImpl’s createFixedDeposit method and
BankAccountDaoImpl’ssubtractFromAccountmethodbecausewewantboththemethodstobeexecuted
withinasingletransaction.Aswe’dwanttorollbackthetransactionifeitherofthemethodsfails,the
setRollbackOnly method of TransactionStatus is invoked in case of an exception. If you call
TransactionStatus’ssetRollbackOnlymethod,theTransactionTemplateinstancerollbacksthetransaction.
A transaction will be automatically rolled back if the actions contained in the doInTransaction method
resultinajava.lang.RuntimeException.
TransactionCallbackinstanceacceptsagenerictypeargumentwhichreferstotheobjecttypereturnedby
the doInTransaction method. In example listing 7-13, a FixedDepositDetails object is returned by the
doInTransaction method. If you don’t want the doInTransaction method to return any object, use the
TransactionCallbackWithoutResultabstractclassthatimplementstheTransactionCallbackinterface.The
TransactionCallbackWithoutResult class allows you to create TransactionCallback implementations in
whichdoInTransactionmethoddoesn’treturnavalue.
The following example listing shows the main method of BankApp class that calls
BankAccountServiceImpl’s createBankAccount method to create a bank account, and
FixedDepositServiceImpl’s createFixedDeposit method to create a fixed deposit corresponding to the
newlycreatedbankaccount:
Examplelisting7-14–BankAppclass
Project–ch07-bankapp-tx-jdbc
Sourcelocation-src/main/java/sample/spring/chapter07/bankapp
packagesample.spring.chapter07.bankapp;
publicclassBankApp{
.....
publicstaticvoidmain(Stringargs[])throwsException{
ApplicationContextcontext=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
BankAccountServicebankAccountService=context.getBean(BankAccountService.class);
FixedDepositServiceFixedDepositService=context.getBean(FixedDepositService.class);
BankAccountDetailsbankAccountDetails=newBankAccountDetails();
bankAccountDetails.setBalanceAmount(1000);
.....
intbankAccountId=bankAccountService.createBankAccount(bankAccountDetails);
FixedDepositDetailsfixedDepositDetails=newFixedDepositDetails();
fixedDepositDetails.setFixedDepositAmount(1500);
fixedDepositDetails.setBankAccountId(bankAccountId);
.....
intFixedDepositId=FixedDepositService.createFixedDeposit(fixedDepositDetails);
.....
}
}
The above example listing shows that a bank account is first created with a balance amount of 1000,
followedbycreatingafixeddepositofamount1500.Asfixeddepositamountisgreaterthanthebalance
in the bank account, BankAccountDaoImpl’s subtractFromAccount method throws an exception (refer
BankAccountDaoImpl’ssubtractFromAccountmethodorfigure7-2).
If you execute BankApp’s main method, you’ll notice that the fixed deposit is not created in the
FIXED_DEPOSIT_DETAILS table, and 1500 amount is not deducted from the
BANK_ACCOUNT_DETAILS table. This shows that both FixedDepositDaoImpl’s createFixedDeposit
andBankAccountDaoImpl’ssubtractFromAccountareexecutedinthesametransaction.
Instead of using TransactionTemplate class, you can directly use a PlatformTransactionManager
implementation to programmatically manage transactions. When using PlatformTransactionManager
implementation, you are required to explicitly initiate and commit (or roll back) transactions. For this
reason, it is recommended to use TransactionTemplate instead of directly using a
PlatformTransactionManagerimplementation.
Let’snowlookatdeclarativetransactionmanagementfeatureofSpring.
Declarativetransactionmanagement
ProgrammatictransactionmanagementcouplesyourapplicationcodewithSpring-specificclasses.Onthe
other hand, declarative transaction management requires you to only annotate methods or classes with
Spring’s @Transactional annotation. If you want to execute a method within a transaction, annotate the
method with @Transactional annotation. If you want to execute all the methods of a class within a
transaction,annotatetheclasswith@Transactionalannotation.
NOTEInsteadofusing@Transactionalannotationfordeclarativetransactionmanagement,youcanuse
Spring’stxschemaelementstoidentifytransactionalmethods.AsusingSpring’stxschemaresultsin
verboseapplicationcontextXMLfile,we’llbeonlylookingatusing@Transactionalannotationfor
declarativetransactionmanagement.
IMPORTchapter7/ch07-bankapp-jdbcandchapter7/ch07-bankapp-hibernate (The ch07-bankapp-
jdbc project shows the MyBank application that uses Spring’s JDBC module for database interaction
(refersection7-3tolearnmoreaboutch07-bankapp-jdbcproject).Thech07-bankapp-hibernateproject
showstheMyBankapplicationthatusesHibernatetointeractwiththedatabase(refersection7-4tolearn
moreaboutch07-bankapp-hibernateproject).
Youenabledeclarativetransactionmanagementusing<annotation-driven>elementofSpring’stxschema.
The following example listing shows the <annotation-driven> element’s usage in ch07-bankapp-jdbc
project:
Examplelisting7-15–applicationContext.xml-<annotation-driven>element
Project–ch07-bankapp-jdbc
Sourcelocation-src/main/resources/META-INF/spring
<beans.....xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation=".....http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
.....
<tx:annotation-driventransaction-manager="txManager"/>
<beanid="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<propertyname="dataSource"ref="dataSource"/>
</bean>
.....
</beans>
In the above example listing, Spring’s txschema is included so that its elements are accessible in the
application context XML file. The <annotation-driven> element enables declarative transaction
management.The<annotation-driven>element’stransaction-managerattributespecifiesreferencetothe
PlatformTransactionManager implementation to use for transaction management. The above example
listing shows that the DataSourceTransactionManager is used as the transaction manager in ch07-
bankapp-jdbcproject.
The following example listing shows how you can use declarative transaction management in ch07-
bankapp-hibernateprojectthatusesHibernateORMfordataaccess:
Examplelisting7-16–applicationContext.xml-<annotation-driven>element
Project–ch07-bankapp-hibernate
Sourcelocation-src/main/resources/META-INF/spring
<beans.....xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation=".....http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
.....
<tx:annotation-driventransaction-manager="txManager"/>
<beanid="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<propertyname="sessionFactory"ref="sessionFactory"/>
</bean>
.....
</beans>
If you compare the above example listing with 7-15, you’ll notice that the only difference is in the
PlatformTransactionManager implementation referenced by the transaction-manager attribute of
<annotation-driven> element. The above example listing shows that if Hibernate ORM is used for
database interaction, the org.springframework.orm.hibernate4.HibernateTransactionManager
implementationofPlatformTransactionManagerisusedformanagingtransactions.
NOTE If you are using Hibernate 3, set transaction-manager attribute to
org.springframework.orm.hibernate3.HibernateTransactionManager instead of
org.springframework.orm.hibernate4.HibernateTransactionManager.
The following example listing shows the FixedDepositServiceImpl class that makes use of declarative
transactionmanagement:
Examplelisting7-17–FixedDepositServiceImplclass-@Transactionalannotationusage
Project–ch07-bankapp-jdbc
Sourcelocation-src/main/java/sample/spring/chapter07/bankapp/service
packagesample.spring.chapter07.bankapp.service;
importorg.springframework.transaction.annotation.Transactional;
.....
@Service(value="FixedDepositService")
publicclassFixedDepositServiceImplimplementsFixedDepositService{
.....
@Transactional
publicintcreateFixedDeposit(FixedDepositDetailsfixedDepositDetails)throwsException{
bankAccountDao.subtractFromAccount(fixedDepositDetails.getBankAccountId(),
fixedDepositDetails.getFixedDepositAmount());
returnmyFixedDepositDao.createFixedDeposit(fixedDepositDetails);
}
.....
}
Intheaboveexamplelisting,thecreateFixedDepositmethodisannotatedwith@Transactionalannotation.
ThismeansthatthecreateFixedDepositmethodisexecutedwithinatransaction.Thetransactionmanager
specifiedviathetransaction-managerattributeof<annotation-driven>element(referexamplelisting7-15
and 7-16) is used for managing the transaction. If a java.lang.RuntimeException is thrown during
executionofcreateFixedDepositmethod,thetransactionisautomaticallyrolledback.
@Transactionalannotationdefinesattributesthatyoucanusetoconfigurethebehaviorofthetransaction
manager. For instance, you can use the rollbackFor attribute to specify exception classes that result in
transaction roll back. The exception classes specified by rollbackFor attribute must be subclasses of
java.lang.Throwableclass.Similarly,youcanuseisolationattributetospecifythetransactionisolation
level.
Incaseyourapplicationdefinesmultipletransactionmanagers,youcanuse@Transactionalannotation’s
valueattributetospecifythebeannameofthePlatformTransactionManagerimplementationthatyouwant
touse for managing transactions.The followingexamplelistingshows that2transactionmanagers, tx1
and tx2, are defined in the application context XML file. The tx1 transaction manager is used by
SomeServiceImpl’smethodAandtx2transactionmanagerisusedbySomeServiceImpl’smethodB:
Examplelisting7-18–@Transactional’svalueattributeusage
-----------------------SomeServiceImplclass------------------------
@Service
publicclassSomeServiceImplimplementsSomeService{
.....
@Transactional(value="tx1")
publicintmethodA(){.....}
@Transactional(value="tx2")
publicintmethodB(){.....}
}
-----------------------applicationcontextXMLfile------------------------
<tx:annotation-driven/>
<beanid="tx1"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<propertyname="sessionFactory1"ref="sessionFactory1"/>
</bean>
<beanid="tx2"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<propertyname="dataSource"ref="dataSource"/>
</bean>
Intheaboveexamplelisting,the<annotation-driven>elementofSpring’stxschemadoesn’tspecifythe
transaction-manager attribute because the transaction manager to use for managing transactions is
specified by the @Transactional annotation itself. In the above example listing, @Transactional
annotation’svalueattributespecifiesthetransactionmanagertouseformanagingtransactions.Thismeans
that SomeServiceImpl’s methodA executes under tx1 transaction manager and SomeServiceImpl’s
methodBexecutesundertx2transactionmanager.
Let’snowlookatSpring’ssupportforJTA(JavaTransactionAPI)transactions.
Spring’ssupportforJTA
Inchapter1,wediscussedthatwhenmultipletransactionalresourcesareinvolvedinatransaction,JTAis
used for transaction management. Spring provides a generic JtaTransactionManager class (a
PlatformTransactionManager implementation) that you can use in applications to manage JTA
transactions.
Figure 7-3 JTA transaction managers and resource-specific transaction managers implement
PlatformTransactionManagerinterface
In most application server environments, the JtaTransactionManager will meet your requirements. But,
Spring also provides vendor-specific PlatformTransactionManager implementations that leverage
application server-specific features to manage JTA transactions. The vendor-specific JTA transaction
managers provided by Spring are: OC4JJtaTransactionManager (for Oracle OC4J),
WebLogicJtaTransactionManager (for WebLogic application server),
WebSphereUowTransactionManager (for WebSphere application server). Figure 7-3 summarizes how
JTA transaction managers and resource-specific transaction managers are related to the
PlatformTransactionManager interface. The figure shows that the PlatformTransactionManager is
implementedbybothJTAtransactionmanagerclassesandresource-specifictransactionmanagerclasses.
Let’s now look at how Spring simplifies configuring a JTA transaction manager in application context
XMLfile.
ConfiguringaJTAtransactionmanagerusing<jta-transaction-manager>element
Spring’s tx schema provides a <jta-transaction-manager> element that automatically detects the
application server in which the application is deployed and configures an appropriate JTA transaction
manager. This saves the effort for explicitly configuring an application server-specific JTA transaction
manager in the application context XML file. For instance, if you deploy an application in WebSphere
application server, the <jta-transaction-manager> element configures an instance of
WebSphereUowTransactionManager instance. If the same application is deployed in WebLogic
application server, the <jta-transaction-manager> element configures an instance of
WebLogicJtaTransactionManagerinstance.Iftheapplicationisdeployedinanyapplicationserverother
than OC4J, WebSphere or WebLogic, the <jta-transaction-manager> element configures an instance of
JtaTransactionManagerinstance.
7-6Summary
In this chapter, we saw that Spring supports database interaction using JDBC and Hibernate ORM
framework. We also saw how we can use Spring to manage transactions programmatically and
declaratively. In the next chapter, we’ll look athow Spring simplifies sending emails, interaction with
messagingmiddlewares,andperformtransparentcachingofdata.
Chapter8-Messaging,emailing,asynchronousmethod
execution,andcachingusingSpring
8-1Introduction
In the previous chapter, we saw that Spring simplifies database interaction. In the context of MyBank
application,thischaptergoesastepfurtherandshowshowSpringsimplifies:
·sendingandreceivingJMSmessagesfromaJMSprovider,likeActiveMQ
·sendingemailmessages
·asynchronouslyexecutingmethods
·storingandretrievingdatafromcache
Let’sfirstlookattheMyBankapplication’srequirementsthatwe’llimplementinthischapter.
8-2MyBankapplication’srequirements
MyBank application allows its customers to open fixed deposits and retrieve details of their existing
fixeddeposits.Figure8-1showsthesequenceofeventsthatoccurwhenacustomerrequestsforopening
anewfixeddeposit.
First, FixedDepositService’s createFixedDeposit method is invoked that sends 2 JMS messages – a
message containing customer’s email id, and a message that contains fixed deposit details.
EmailMessageListenerretrievestheJMSmessagecontainingtheemailidofthecustomerandsendsan
email to the customer informing that the request for opening a fixed deposit has been received.
FixedDepositMessageListenerretrievestheJMSmessagecontainingfixeddepositdetailsandsavesthe
fixeddepositdetailsinthedatabase.
A scheduled job runs every 5 seconds to check if any new fixed deposits have been created in the
database. If the job finds any new fixed deposits, it subtracts the fixed deposit amount from the bank
accountofthecustomerandsendsanemailtothecustomerinformingthatthefixeddepositrequesthas
beensuccessfullyprocessed.
Figure8-1MyBankapplicationbehaviorwhenacustomerrequestsforopeninganewfixeddeposit
The following diagram shows the behavior of MyBank application when FixedDepositService’s
findFixedDepositsByBankAccount method is invoked to retrieve all fixed deposits corresponding to a
bankaccount:
Figure 8-2 MyBank application behavior when a customer requests for the details of all his fixed
deposits
The above figure shows thatwhen FixedDepositService’sfindFixedDepositsByBankAccountmethod is
invoked,thefixeddepositinformationisfetchedfromthedatabaseandcachedintomemory.Ifyoucan
FixedDepositService’sfindFixedDepositsByBankAccountagain,thefixeddepositinformationisfetched
fromthecacheandnotfromthedatabase.
Let’s now look at how Spring is used in the MyBank application to send JMS messages to JMS
destinationsconfiguredinActiveMQ.
IMPORTchapter8/ch08-bankapp(Togetthemostofoutofthischapter,installMySQLdatabaseand
execute the spring_bank_app_db.sql SQL script contained in the sql folder of ch08-bankapp project.
Executing spring_bank_app_db.sql script creates SPRING_BANK_APP_DB database and adds
BANK_ACCOUNT_DETAILS and FIXED_DEPOSIT_DETAILS tables to the
SPRING_BANK_APP_DB database. Modify the src/main/resources/META-
INF/spring/database.properties to point to your MySQL installation. To get the email feature working,
modifysrc/main/resources/META-INF/spring/email.propertiestospecifytheemailserverandtheemail
accounttouseforsendingemails.ModifytheBankAppclasstospecifytheemailidofthecustomerto
whomtheemailsaresent)
8-3SendingJMSmessages
SpringsimplifiesinteractionwithJMSprovidersbyprovidingalayerofabstractionontopofJMSAPI.
InthecontextofMyBankapplication,thissectionshowshowtosynchronouslyandasynchronouslysend
andreceivemessagesfromanActiveMQbrokerusingSpring.Forthesakeofsimplicity,theActiveMQ
brokerisconfiguredtoruninembeddedmodeinch08-bankappproject.
NOTEInSpring,JMSsupportclassesaredefinedinspring-jmsJARfile;therefore,youmustdefinethat
yourapplicationdependsonspring-jmsJARfiletouseSpring’ssupportforJMS.
ConfiguringActiveMQbrokertoruninembeddedmode
AnembeddedActiveMQbrokerrunsinthesameJVMastheapplication.YoucanuseActiveMQ’sXML
schema to configure an embedded ActiveMQ broker in a Spring application. The following example
listing shows how ActiveMQ’s XML schema is used to configure an embedded ActiveMQ broker in
MyBankapplication:
Examplelisting8-1–applicationContext.xml–embeddedActiveMQbrokerconfiguration
Project–ch08-bankapp
Sourcelocation-src/main/resources/META-INF/spring
<beans.....
xmlns:amq="http://activemq.apache.org/schema/core"
xsi:schemaLocation=".....http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.7.0.xsd.....">
<amq:broker>
<amq:transportConnectors>
<amq:transportConnectoruri="tcp://localhost:61616"/>
</amq:transportConnectors>
</amq:broker>
.....
</beans>
In the above example listing, the amq namespace refers to ActiveMQ’s XML schema (activemq-core-
5.7.0.xsd)thatallowsyoutoconfigureanembeddedActiveMQbroker.The<broker>elementconfigures
an embedded ActiveMQ broker with name localhost. The <transportConnectors> element specifies the
transport connectors onwhich the embedded ActiveMQ broker allows clients toconnect. In the above
examplelisting,the<transportConnector>sub-elementof<transportConnectors>specifiesthatclientscan
connecttotheembeddedActiveMQbrokeronportnumber61616usingaTCPsocket.
Let’snowlookathowtoconfigureaJMSConnectionFactoryforcreatingconnectionstotheembedded
ActiveMQinstance.
ConfiguringaJMSConnectionFactory
The following example listing shows how a JMS ConnectionFactory is configured in the application
contextXMLfile:
Examplelisting8-2–applicationContext.xml–JMSConnectionFactoryconfiguration
Project–ch08-bankapp
Sourcelocation-src/main/resources/META-INF/spring
<beans.....
xmlns:amq="http://activemq.apache.org/schema/core"
xsi:schemaLocation=".....http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.7.0.xsd.....">
.....
<amq:connectionFactorybrokerURL="vm://localhost"id="jmsFactory"/>
<beanclass="org.springframework.jms.connection.CachingConnectionFactory"
id="cachingConnectionFactory">
<propertyname="targetConnectionFactory"ref="jmsFactory"/>
</bean>
.....
</beans>
In the above example listing, the <connectionFactory> element of amq schema creates a JMS
ConnectionFactory instance that is used for creating connections to the embedded ActiveMQ instance
(refer example listing 8-1). The brokerUrl attribute specifies the URL for connecting to the ActiveMQ
broker.AsweareusingembeddedActiveMQbroker,thebrokerUrlspecifiesthatVMprotocol(specified
byvm://)isusedtoconnecttotheActiveMQbrokerinstance.
Spring’s CachingConnectionFactory is an adapter for the JMS ConnectionFactory (specified by the
targetConnectionFactory property), that provides the additional feature of caching instances of JMS
Session,MessageProducerandMessageConsumer.
Let’snowlookathowtouseSpring’sJmsTemplateclasstosendJMSmessages.
SendingJMSmessagesusingJmsTemplate
Spring’s JmsTemplate class simplifies synchronously sending and receiving JMS messages. For the
purpose of this chapter, we’ll only look at how to send JMS messages using JmsTemplate. Like
TransactionTemplate(refersection7-5ofchapter7)andJdbcTemplate(refersection7-3ofchapter7)
classes,theJmsTemplateclassprovidesalayerofabstractionsothatyoudon’thavetodealwithlower-
levelJMSAPI.
ThefollowingexamplelistingshowshowtheJmsTemplateclassisconfiguredintheapplicationcontext
XMLfileofMyBankapplicationtosendmessagestotheembeddedActiveMQinstance:
Examplelisting8-3–applicationContext.xml–JmsTemplateconfiguration
Project–ch08-bankapp
Sourcelocation-src/main/resources/META-INF/spring
<beans.....
xmlns:amq="http://activemq.apache.org/schema/core"
xsi:schemaLocation=".....http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.7.0.xsd.....">
.....
<beanclass="org.springframework.jms.core.JmsTemplate"id="jmsTemplate">
<propertyname="connectionFactory"ref="cachingConnectionFactory"/>
<propertyname="defaultDestination"ref="FixedDepositDestination"/>
</bean>
<amq:queueid="FixedDepositDestination"physicalName="aQueueDestination"/>
<amq:queueid="emailQueueDestination"physicalName="emailQueueDestination"/>
.....
</beans>
JmsTemplate’sconnectionFactorypropertyspecifiestheJMSConnectionFactorythatisusedforcreating
aconnectionwiththeJMSprovider.JmsTemplate’sdefaultDestinationpropertyreferstothedefaultJMS
destination to which the JmsTemplate sends JMS messages. In the above example listing,
connectionFactorypropertyreferstotheCachingConnectionFactoryinstance(referexamplelisting8-2),
and defaultDestination property refers to the JMSqueue destination created by amq schema’s <queue>
element.
Theamqschema’s<queue>elementcreatesaJMSqueuedestinationinActiveMQ.Inexamplelisting8-
3,thefirst<queue>elementcreatesaJMSqueuedestinationnamedaQueueDestinationinActiveMQ,and
the second <queue> element creates a JMS queue destination named emailQueueDestination in
ActiveMQ. The physicalName attribute refers to the name with which the JMS queue destination is
created in ActiveMQ, and id attribute refers to the name with which the JMS queue destination is
accessedbyotherbeansintheSpringcontainer.Inexamplelisting8-3,JmsTemplate’sdefaultDestination
property refers to the id attribute of the <queue> element that creates the aQueueDestination JMS
destination; therefore, the aQueueDestination is the default JMS destination to which the JmsTemplate
instancesendsJMSmessages.
JMSSessionusedbyJmsTemplatehastheacknowledgementmodesettoauto-acknowledgeandisnot
transactedinnature.IfyouwantJmsTemplatetousetransactedSessions,setJmsTemplate’stransacted
propertytotrue.IncaseoftransactedSessions,anewtransactionbeginswhentheSessioniscreatedby
theapplication,orwhenthetransactioniscommittedorrolledback.ThismeansthatatransactedJMS
Session is always associated with a transaction. You can use a transacted JMS Session to send and
receive JMS messages within a transaction. If you use JmsTemplate with Spring’s
JmsTransactionManager,theJmsTemplateinstancewillalwaysgetatransactedJMSSession.
Let’snowlookathowJmsTransactionManagerisconfigured,andJMSmessagesaresentbyJmsTemplate
withinatransaction.
SendingJMSmessageswithinatransaction
Inchapter7,wesawthatSpringprovidesacoupleofPlatformTransactionManagerimplementationsthat
provide resource-specific transaction management. In your JMS applications, you can use Spring’s
JmsTransactionManager (an implementation of PlatformTransactionManager) class for managing
transactions for a single JMS ConnectionFactory. As JmsTransactionManager implements
PlatformTransactionManager, you can use TransactionTemplate for programmatically managing JMS
transactionsoryoucanuse@TransactionalannotationfordeclarativelymanagingJMStransactions.
ThefollowingexamplelistingshowstheconfigurationofSpring’sJmsTransactionManagerinapplication
contextXMLfile:
Examplelisting8-4–applicationContext.xml–JmsTransactionManagerconfiguration
Project–ch08-bankapp
Sourcelocation-src/main/resources/META-INF/spring
<beanid="jmsTxManager"class="org.springframework.jms.connection.JmsTransactionManager">
<propertyname="connectionFactory"ref="cachingConnectionFactory"/>
</bean>
JmsTransactionManager’sconnectionFactorypropertyspecifiesreferencetotheJMSConnectionFactory
for which the JmsTransactionManager manages transactions. In the above example listing, reference to
Spring’s CachingConnectionFactory bean (refer example listing 8-2) is specified as the value for
connectionFactory property. As the CachingConnectionFactory caches JMS Sessions, using
CachingConnectionFactorywithJmsTransactionManagerresultsinreducedutilizationofresources.
IfyouwanttoprogrammaticallymanageJMStransactionsusingTransactionTemplateclass,configurethe
TransactionTemplateclassintheapplicationcontextXMLfile.Ifyouwanttousedeclarativetransaction
management,use<annotation-driven>elementofSpring’stxschema.
ThefollowingexamplelistingshowstheFixedDepositServiceImplclassthatmakesuseofJmsTemplate
tosendmessagestotheembeddedActiveMQbroker:
Examplelisting8-5–FixedDepositServiceImplclass–sendJMSmessagesusingJmsTemplate
Project–ch08-bankapp
Sourcelocation-src/main/java/sample/spring/chapter08/bankapp/service
packagesample.spring.chapter08.bankapp.service;
importjavax.jms.*;
importorg.springframework.jms.core.JmsTemplate;
importorg.springframework.jms.core.MessageCreator;
@Service(value="FixedDepositService")
publicclassFixedDepositServiceImplimplementsFixedDepositService{
@Autowired
privateJmsTemplatejmsTemplate;
.....
@Override
@Transactional("jmsTxManager")
publicvoidcreateFixedDeposit(finalFixedDepositDetailsfixedDepositDetails)throwsException{
jmsTemplate.send("emailQueueDestination",newMessageCreator(){
publicMessagecreateMessage(Sessionsession)throwsJMSException{
TextMessagetextMessage=session.createTextMessage();
textMessage.setText(fixedDepositDetails.getEmail());
returntextMessage;
}
});
//--thisJMSmessagegoestothedefaultdestinationconfiguredfortheJmsTemplate
jmsTemplate.send(newMessageCreator(){
publicMessagecreateMessage(Sessionsession)throwsJMSException{
ObjectMessageobjectMessage=session.createObjectMessage();
objectMessage.setObject(fixedDepositDetails);
returnobjectMessage;
}
});
}
.....
}
The above example listing shows that JmsTemplate’s send method is used to send messages to
emailQueueDestinationandaQueueDestinationJMSdestinations.Refer examplelisting 8-3 tosee how
these JMS destinations are configured in the application context XML file. The name of the JMS
destination passed to JmsTemplate’ssend method is resolved to the actual JMS Destination object by
Spring’s DynamicDestinationResolver instance (an implementation of Spring’s DestinationResolver
interface). If you have configured JMS destinations in the application context XML file using amq
schema’s <queue> (or <topic>) element, the JMS destination name passed to the JmsTemplate’s send
message is the value of id attribute of the <queue> (or <topic>) element corresponding to the JMS
destinationtowhichyouwanttosendmessages.
In example listing 8-5, the FixedDepositServiceImpl’s createFixedDeposit method is annotated with
@Transactional("jmsTxManager"), which means that the createFixedDeposit method executes within a
transaction,andthetransactionismanagedbyjmsTxManagertransactionmanager(referexamplelisting
8-4toseehowjmsTxManagerisconfigured).JmsTemplate’ssendmethodacceptsthenameoftheJMS
destination(towhichtheJMSmessageistobesent)andaMessageCreatorinstance.Ifyoudon’tspecify
theJMSdestination,thesendmethodsendstheJMSmessagetothedefaultdestinationthatyouconfigured
fortheJmsTemplateusingdefaultDestinationproperty(referexamplelisting8-3).
InMessageCreator’screateMessagemethodyoucreatetheJMSmessagethatyouwanttosend.Youdon’t
need to explicitly handle checked exceptions thrown by JMS API, as they are taken care by the
JmsTemplate itself. Example listing 8-5 shows that if you are using JmsTemplate, you don’t need to
explicitly obtain Connection from ConnectionFactory, create Session from Connection, and so on, for
sending JMS messages. So, using JmsTemplate hides the lower-level JMS API details from the
developers.
In example listing 8-5, the TextMessage and ObjectMessage instances represent JMS messages. Both,
TextMessage and ObjectMessage classes implement javax.jms.Message interface. In the MyBank
application,theTextMessageinstancehasbeenusedtosendtheemailid(asimplestringvalue)ofthe
customer requesting to open a fixed deposit, and the ObjectMessage instance has been used to send
FixedDepositDetails object (a Serializable object) that contains fixed deposit information. As the
FixedDepositServiceImpl’screateFixedDepositmethodexecuteswithinaJMStransaction,eitherboththe
messagesaresenttotheActiveMQinstanceornone.
Insteadofusing@Transactionalannotation,youcanprogrammaticallymanageJMStransactionsbyusing
theTransactionTemplateclass(refersection7-5ofchapter7).Thefollowingexamplelistingshowshow
you can configure the TransactionTemplate class to use JmsTransactionManager for transaction
management:
Examplelisting8-6–TransactionTemplateconfiguration
<beanid="jmsTxManager"
class="org.springframework.jms.connection.JmsTransactionManager">
<propertyname="connectionFactory"ref="cachingConnectionFactory"/>
</bean>
<beanid="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<propertyname="transactionManager"ref="jmsTxManager"/>
</bean>
In the above example listing, TransactionTemplate’s transactionManager property refers to the
JmsTransactionManagerbean.
OnceyouhaveconfiguredtheTransactionTemplateclass,youcanuseittomanageJMStransactions.The
followingexamplelistingshowsavariantofFixedDepositServiceImpl’screateFixedDepositmethodthat
usesTransactionTemplateformanagingJMStransactions:
Examplelisting8-7–ProgrammaticallymanagingJMStransactionsusingTransactionTemplate
packagesample.spring.chapter08.bankapp.service;
importjavax.jms.*;
importorg.springframework.jms.core.JmsTemplate;
importorg.springframework.jms.core.MessageCreator;
@Service(value="FixedDepositService")
publicclassFixedDepositServiceImplimplementsFixedDepositService{
@Autowired
privateJmsTemplatejmsTemplate;
@Autowired
privateTransactionTemplatetransactionTemplate;
.....
publicvoidcreateFixedDeposit(finalFixedDepositDetailsfixedDepositDetails)throwsException{
transactionTemplate.execute(newTransactionCallbackWithoutResult(){
protectedvoiddoInTransactionWithoutResult(TransactionStatusstatus){
jmsTemplate.send("emailQueueDestination",newMessageCreator(){.....});
jmsTemplate.send(newMessageCreator(){.....});
}
});
}
.....
}
TheaboveexamplelistingshowsthatJMSmessagesaresentfromwithinthedoInTransactionmethodof
TransactionCallbackWithoutResultclasssothattheyareinthesameJMStransaction.Thisissimilarto
how we programmatically managed JDBC transactions (refer section 7-5 of chapter 7) using
TransactionTemplate.
SofarwehaveseenexamplesinwhichJmsTemplateisusedtosendmessagestoapre-configuredJMS
destination.Let’snowlookathowtoconfigureJmsTemplateclassifanapplicationusesdynamicJMS
destinations.
DynamicJMSdestinationsandJmsTemplateconfiguration
If your application uses dynamic JMS destinations (that is, JMS destinations are created by the
applicationatruntime),youmustspecifytheJMSdestinationtype(queueortopic)usingpubSubDomain
propertyofJmsTemplate.ThepubSubDomainpropertyisusedtodeterminetheJMSdestinationtypeto
whichtheJmsTemplatesendsJMSmessages.Ifyoudon’tspecifythepubSubDomainproperty,bydefault
JMSqueueisassumedtobethedestinationtype.
ThefollowingexamplelistingshowstheJmsTemplatethatsendsmessagestoadynamicallycreatedJMS
topic:
Examplelisting8-8–UsingJmsTemplateforsendingmessagestodynamicJMStopicdestinations
--------------------------applicationContext.xml---------------------
<beanclass="org.springframework.jms.core.JmsTemplate"id="jmsTemplate">
<propertyname="connectionFactory"ref="cachingConnectionFactory"/>
<propertyname="defaultDestination"ref="FixedDepositDestination"/>
<propertyname="pubSubDomain"value="true"/>
</bean>
------------------Dynamictopiccreation------------------
jmsTemplate.send("dynamicTopic",newMessageCreator(){
publicMessagecreateMessage(Sessionsession)throwsJMSException{
session.createTopic("dynamicTopic");
ObjectMessageobjectMessage=session.createObjectMessage();
objectMessage.setObject(someObject);
returnobjectMessage;
}
});
In the above example listing, JmsTemplate’s pubSubDomain property is set to true, which means that
when dynamic destinations are used, Spring resolves a dynamic destination’s name to a JMS topic.
NoticethatthenameoftheJMSdestinationpassedtoJmsTemplate’ssendmethodisdynamicTopic,anda
JMS topic with the same name is created by MessageCreator’s createMessage method. As no
dynamicTopic JMSdestinationis configured in the applicationcontextXML file, Spring doesn’tknow
whether the dynamicTopic JMS destination is a queue or a topic. As JmsTemplate’s pubSubDomain
property is set to true, Spring’s DynamicDestinationResolver resolves dynamicTopic JMS destination
nametothedynamicTopicJMStopiccreatedatruntimebyMessageCreator’screateMessagemethod.If
you had not set JmsTemplate’s pubSubDomain property, Spring’s DynamicDestinationResolver would
havetriedresolvingdynamicTopicJMSdestinationnametoadynamicTopicJMSqueue.
Let’snowlookathowJmsTemplatesimplifiessendingJavaobjectsasJMSmessages.
JmsTemplateandmessageconversion
JmsTemplate defines multiple convertAndSendmethods that convert and send a Java object as a JMS
message. By default, JmsTemplate is configured with a SimpleMessageConverter instance (an
implementationofSpring’sMessageConverterinterface)thatconvertsJavaobjectstoJMSmessages,and
viceversa.
MessageConverterinterfacedefinesthefollowingmethods:
·ObjecttoMessage(Objectobject,Sessionsession)–convertstheJavaobject(represented
byobjectargument)toaJMSMessageusingthesuppliedJMSSession(representedby
sessionargument)
·ObjectfromMessage(Messagemessage)-convertsMessageargumenttoJavaobject
Spring’s SimpleMessageConverter class provides conversion between String and JMS TextMessage,
byte[] and JMS BytesMessage, Map and JMS MapMessage, and Serializable object and JMS
ObjectMessage. If you want to modify the JMS Message created by JmsTemplate’s convertAndSend
method,youcanuseaMessagePostProcessorimplementationtomakemodifications.
The following example listing shows a scenario in which a MessagePostProcessor implementation is
usedtomodifytheJMSmessagecreatedbyJmsTemplate’sconvertAndSendmethod:
Examplelisting8-9–JmsTemplate’sconvertAndSendmethodusage
jmsTemplate.convertAndSend("aDestination","Hello,World!!",
newMessagePostProcessor(){
publicMessagepostProcessMessage(Messagemessage)throwsJMSException{
message.setBooleanProperty("printOnConsole",true);
returnmessage;
}
});
In the above example listing, ‘Hello, World !!’ string is passed to the convertAndSend method. The
convertAndSend method creates a JMS TextMessage instance and makes it available to the
MessagePostProcessorimplementationtoperformanypostprocessingofthemessagebeforeitissent.In
theaboveexamplelisting,MessagePostProcessor’spostProcessMessagemethodsetsaprintOnConsole
propertyontheJMSmessagebeforeitissenttoaDestination.
SofarwehaveseenhowtosendJMSmessagestoJMSdestinationsusingJmsTemplate.Let’snowlook
at how to receive JMS messages from JMS destinations using JmsTemplate and Spring’s message
listenercontainers.
8-4ReceivingJMSmessages
You can receive JMS messages synchronously using JmsTemplate and asynchronously using Spring’s
messagelistenercontainers.
SynchronouslyreceivingJMSmessagesusingJmsTemplate
JmsTemplatedefinesmultiplereceivemethodsthatyoucanusetosynchronouslyreceiveJMSmessages.
ItisimportanttonotethatcalltoJmsTemplate’sreceivemethodcausesthecallingthreadtoblockuntila
JMS message is obtained from the JMS destination. To ensure that the calling thread is not blocked
indefinitely, you must specify an appropriate value for JmsTemplate’s receiveTimeout property. The
receiveTimeout property specifies the amount of time (in milliseconds) the calling thread should wait
beforegivingup.
JmsTemplate alsodefines multiplereceiveAndConvert methods thatautomaticallyconvert the received
JMS message toa Java object. By default, JmsTemplate uses SimpleMessageConverter for performing
conversions.
AsynchronouslyreceivingJMSmessagesusingmessagelistenercontainers
YoucanuseSpring’smessagelistenercontainerstoasynchronouslyreceiveJMSmessages.Amessage
listener container takes care of transaction and resource management aspects, so that you can focus on
writingthemessageprocessinglogic.
A message listener container receives messages from JMS destinations and dispatches them to JMS
MessageListenerimplementationsforprocessing.Thefollowingexamplelistingshowshowtoconfigure
amessagelistenercontainerusing<listener-container>elementofSpring’sjmsschema:
Examplelisting8-10–applicationContext.xml–messagelistenercontainerconfiguration
Project–ch08-bankapp
Sourcelocation-src/main/resources/META-INF/spring
<beans.....xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation=".....
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-4.0.xsd">
.....
<jms:listener-containerconnection-factory="cachingConnectionFactory"
destination-type="queue"transaction-manager="jmsTxManager">
<jms:listenerdestination="aQueueDestination"ref="FixedDepositMessageListener"/>
<jms:listenerdestination="emailQueueDestination"ref="emailMessageListener"/>
</jms:listener-container>
<beanclass="sample.spring.chapter08.bankapp.jms.EmailMessageListener"
id="emailMessageListener"/>
<beanclass="sample.spring.chapter08.bankapp.jms.FixedDepositMessageListener"
id="FixedDepositMessageListener"/>
.....
</beans>
In the above example listing, Spring’s jms schema is included so that its elements are available in the
applicationcontextXMLfile.The<listener-container>elementconfiguresamessagelistenercontainer
for each of the MessageListener implementations defined by <listener> sub-elements. The connection-
factory attribute specifies reference to the JMS ConnectionFactory bean that the message listener
container uses to obtain connections to the JMS provider. As we are using Spring’s
CachingConnectionFactory in the MyBank application, the connection-factory attribute refers to the
cachingConnectionFactorybeandefinedintheapplicationcontextXMLfileofMyBankapplication(refer
example listing 8-2). The destination-type attribute specifies the JMS destination type with which the
messagelistenercontainerisassociatedwith.Thepossiblevaluesthatthedestination-typeattributecan
acceptare:queue,topicanddurableTopic.
The transaction-manager attribute of <listener-container> element specifies a
PlatformTransactionManager implementation that ensures JMS message reception and message
processingbyMessageListenerhappenswithinatransaction.Intheaboveexamplelisting,thevalueof
transaction-managerattributereferstotheJmsTransactionManagerimplementation(referexamplelisting
8-4) configured for the MyBank application. If a MessageListener implementation interacts with other
transactional resources also, consider using Spring’s JtaTransactionManager instead of
JmsTransactionManager. In a standalone application, you can use embedded transaction managers, like
Atomikos(http://www.atomikos.com/),toperformJTAtransactionsinyourapplication.
NOTE By default, the <listener-container> element creates an instance of Spring’s
DefaultMessageListenerContainer class corresponding to each JMS MessageListener implementation
specifiedby<listener>sub-elements.
Each <listener> element specifies a JMS MessageListener implementation which is asynchronously
invoked by the message listener container. The <listener> element’s destination attribute specifies the
JMSdestinationnamefromwhichMessageListenerimplementationreceivesitsmessagesviathemessage
listener container. The <listener> element’s ref attribute specifies reference to the MessageListener
implementation responsible for processing the JMS messages received from the destination. Example
listing 8-10 shows that the FixedDepositMessageListener (a MessageListener implementation) is
responsible for processing messages received from aQueueDestination destination, and the
EmailMessageListener (a MessageListener implementation) is responsible for processing messages
receivedfromemailQueueDestinationdestination.
MessageListenerinterfacedefinesanonMessagemethodthatisasynchronouslyinvokedbythemessage
listener container. The message listener container passes the JMS Message received from the JMS
destinationtotheonMessagemethod.TheonMessagemethodisresponsibleforprocessingthereceived
JMS message. The following example listing shows implementation of MyBank application’s
FixedDepositMessageListenerthatisresponsibleforretrievingFixedDepositDetailsobjectfromtheJMS
Message,andthensavingthefixeddepositinformationcontainedintheFixedDepositDetailsobjectinto
thedatabase:
Examplelisting8-11–FixedDepositMessageListenerclass–processingJMSmessage
Project–ch08-bankapp
Sourcelocation-src/main/java/sample/spring/chapter08/bankapp/jms
packagesample.spring.chapter08.bankapp.jms;
importjavax.jms.MessageListener;
importjavax.jms.ObjectMessage;
importsample.spring.chapter08.bankapp.domain.FixedDepositDetails;
.....
publicclassFixedDepositMessageListenerimplementsMessageListener{
@Autowired
@Qualifier(value="FixedDepositDao")
privateFixedDepositDaomyFixedDepositDao;
@Autowired
privateBankAccountDaobankAccountDao;
@Transactional
publicintcreateFixedDeposit(FixedDepositDetailsfixedDepositDetails){
bankAccountDao.subtractFromAccount(fixedDepositDetails.getBankAccountId(),
fixedDepositDetails.getFixedDepositAmount());
returnmyFixedDepositDao.createFixedDeposit(fixedDepositDetails);
}
@Override
publicvoidonMessage(Messagemessage){
ObjectMessageobjectMessage=(ObjectMessage)message;
FixedDepositDetailsfixedDepositDetails=null;
try{
fixedDepositDetails=(FixedDepositDetails)objectMessage.getObject();
}catch(JMSExceptione){
e.printStackTrace();
}
if(fixedDepositDetails!=null){
createFixedDeposit(fixedDepositDetails);
}
}
}
In the above example listing, FixedDepositMessageListener’s onMessage method obtains the
FixedDepositDetailsobjectfromtheJMSmessageandsavesthefixeddepositdetailsintothedatabase.
FixedDepositMessageListener’screateFixedDeposit method is responsible for saving the fixed deposit
information into the database. As the createFixedDeposit method is annotated with @Transactional
annotation, it is executed under the transaction managed by DataSourceTransactionManager (refer the
applicationContext.xmlfileofch08-bankappproject).ThemessagelistenercontainerreceivestheJMS
messageandexecutesFixedDepositMessageListener’sonMessagemethodunderthetransactionmanaged
byJmsTransactionManager(referexamplelisting8-10).
As onMessage and createFixedDeposit methods execute under different transaction managers, the
databaseupdateisnotrolledbackiftheJMStransactionfailsforsomereason,andtheJMSmessageis
not redelivered to the MessageListener if the database update fails for some reason. If you want JMS
messagereception(andprocessing)andthedatabaseupdatetobepartofthesametransaction,youshould
useJTAtransactions.
Inthissection,welookedathowtosendandreceiveJMSmessagesusingSpring.Let’snowlookathow
Springsimplifiessendingemails.
8-5Sendingemails
Spring simplifies sending emails from an application by providing a layer of abstraction on top of
JavaMailAPI.Springtakescareofresourcemanagementandexceptionhandlingaspects,sothatyoucan
focusonwritingthenecessarylogicrequiredtopreparetheemailmessage.
To send emails using Spring, you first need to configure Spring’s JavaMailSenderImpl class in your
application context XML file. The JavaMailSenderImpl class acts as a wrapper around JavaMail API.
The following example listing shows how JavaMailSenderImpl class is configured in MyBank
application:
Examplelisting8-12–applicationContext.xml–JavaMailSenderImplclassconfiguration
Project–ch08-bankapp
Sourcelocation-src/main/resources/META-INF/spring
<beanid="mailSender"class="org.springframework.mail.javamail.JavaMailSenderImpl">
<propertyname="host"value="${email.host}"/>
<propertyname="protocol"value="${email.protocol}"/>
.....
<propertyname="javaMailProperties">
<props>
<propkey="mail.smtp.auth">true</prop>
<propkey="mail.smtp.starttls.enable">true</prop>
</props>
</property>
</bean>
JavaMailSenderImpl class defines properties, like host, port, protocol, and so on, that provide
informationaboutthe mail server. The javaMailProperties property specifies configuration information
thatisusedbyJavaMailSenderImplinstanceforcreatingaJavaMailSessionobject.Themail.smtp.auth
property value is set to true, which means that SMTP (Simple Mail Transfer Protocol) is used for
authentication with the mail server. The mail.smtp.starttls.enable property value is set to true, which
meansTLS-protectedconnectionisusedforauthenticatingwiththemailserver.
Examplelisting8-12showsthatthevaluesofsomeofthepropertiesof JavaMailSenderImplclassare
specifiedusingpropertyplaceholders.Forinstance,hostpropertyvalueisspecifiedas${email.host}and
protocol property value as ${email.protocol}. The value of these property placeholders comes from
email.propertiesfilelocatedinsrc/main/resources/META-INF/springdirectory.Thefollowingexample
listingshowsthecontentsofemail.propertiesfile:
Examplelisting8-13–email.properties
Project–ch08-bankapp
Sourcelocation-src/main/resources/META-INF/spring
email.host=smtp.gmail.com
email.port=587
email.protocol=smtp
email.username=<enter-email-id>
email.password=<enter-email-password>
The above example listing shows that email.properties file contains mail server information,
communicationprotocolinformation,andthemailaccounttouseforconnectingtothemailserver.The
propertiesspecifiedintheemail.propertiesfileareusedtoconfiguretheJavaMailSenderImpl instance
(referexamplelisting8-12).
NOTETheclassesthatprovideabstractionontopofJavaMailAPIaredefinedinspring-context-support
JARfile.So,touseSpring’ssupportforsendingemails,youmustdefinethatyourapplicationdependson
spring-context-supportJARfile.
Spring’s SimpleMailMessage class represents a simple email message. SimpleMailMessage defines
properties,liketo,cc,subject,text,andsoon,thatyoucansettoconstructtheemailmessagethatyou
wanttosendfromyourapplication.
The following example listing shows the MyBank’s application context XML file that configures two
SimpleMailMessageinstancescorrespondingtothetwoemailmessagesthatwesendfromtheMyBank
application:
Examplelisting8-14–applicationContext.xml–SimpleMailMessageconfiguration
Project–ch08-bankapp
Sourcelocation-src/main/resources/META-INF/spring
<beanclass="org.springframework.mail.SimpleMailMessage"id="requestReceivedTemplate">
<propertyname="subject"value="${email.subject.request.received}"/>
<propertyname="text"value="${email.text.request.received}"/>
</bean>
<beanclass="org.springframework.mail.SimpleMailMessage"id="requestProcessedTemplate">
<propertyname="subject"value="${email.subject.request.processed}"/>
<propertyname="text"value="${email.text.request.processed}"/>
</bean>
Intheaboveexamplelisting,therequestReceivedTemplatebeanrepresentstheemailmessagethatissent
to the customer informing that the request for opening a fixed deposit has been received, and
requestProcessedTemplatebeanrepresentstheemailmessagethatissenttothecustomerinformingthat
therequestforopeningthefixeddeposithasbeensuccessfullyprocessed.SimpleMailMessage’ssubject
property specifies the subject line of the email, and text property specifies the body of the email. The
values for these properties are defined in the emailtemplate.properties file, as shown in the following
examplelisting:
Examplelisting8-15–emailtemplate.properties
Project–ch08-bankapp
Sourcelocation-src/main/resources/META-INF/spring
email.subject.request.received=Fixeddepositrequestreceived
email.text.request.received=Yourrequestforcreatingthefixeddeposithasbeenreceived
email.subject.request.processed=Fixeddepositrequestprocessed
email.text.request.processed=Yourrequestforcreatingthefixeddeposithasbeenprocessed
We have so far seen how to configure JavaMailSenderImpl and SimpleMailMessage classes in the
applicationcontextXMLfile.Let’snowlookathowtosendemailmessages.
The following example listing shows the MyBank application’s EmailMessageListener class (a JMS
MessageListener implementation) that retrieves customer’s email address from the JMS message and
sendsanemailtothecustomerinformingthattherequestforopeningafixeddeposithasbeenreceived:
Examplelisting8-16–EmailMessageListenerclass–sendingemailsusingMailSender
Project–ch08-bankapp
Sourcelocation-src/main/java/sample/spring/chapter08/bankapp/jms
packagesample.spring.chapter08.bankapp.jms;
importorg.springframework.mail.MailSender;
importorg.springframework.mail.SimpleMailMessage;
.....
publicclassEmailMessageListenerimplementsMessageListener{
@Autowired
privatetransientMailSendermailSender;
@Autowired
@Qualifier("requestReceivedTemplate")
privatetransientSimpleMailMessagesimpleMailMessage;
publicvoidsendEmail(){
mailSender.send(simpleMailMessage);
}
publicvoidonMessage(Messagemessage){
TextMessagetextMessage=(TextMessage)message;
try{
simpleMailMessage.setTo(textMessage.getText());
}catch(Exceptione){
e.printStackTrace();
}
sendEmail();
}
}
TheaboveexamplelistingshowsthattheMailSender’ssendmethodsendstheemailmessagerepresented
by the SimpleMailMessage instance. As JavaMailSenderImpl class implements Spring’s MailSender
interface, the JavaMailSenderImpl instance (refer example listing 8-12) is autowired into the
EmailMessageListener instance. SimpleMailMessage instance named requestReceivedTemplate (refer
example listing 8-14) is also autowired into the EmailMessageListener instance. As
SimpleMailMessage’s to property identifies the email recipient, the onMessage method retrieves the
emailidofthecustomerfromtheJMSmessageandsetsitasthevalueoftoproperty.
Spring’sMailSenderinterfacerepresentsagenericinterfacethatisindependentofJavaMailAPI,andis
suited for sending simple email messages. Spring’s JavaMailSender interface (a sub-interface of
MailSender)isdependentonJavaMailAPI,anddefinesthefunctionalityforsendingMIMEmessages.A
MIMEmessageisusedifyouwantto send emailscontaininginlineimages, attachments, andsoon.A
MIME message is represented by a MimeMessage class in JavaMail API. Spring provides a
MimeMessageHelperclassandaMimeMessagePreparatorcallbackinterfacethatyoucanusetocreate
andpopulateaMimeMessageinstance.
The following example listing shows the MyBank application’s FixedDepositProcessorJob class that
subtractsthefixeddepositamountfromthecustomer’sbankaccountandsendsanemailtothecustomer
informingthattherequestforopeningthefixeddeposithasbeenprocessed:
Examplelisting8-17–FixedDepositProcessorJobclass–JavaMailSenderusage
Project–ch08-bankapp
Sourcelocation-src/main/java/sample/spring/chapter08/bankapp/job
packagesample.spring.chapter08.bankapp.job;
importjavax.mail.internet.MimeMessage;
importorg.springframework.mail.javamail.JavaMailSender;
publicclassFixedDepositProcessorJob{
.....
@Autowired
privatetransientJavaMailSendermailSender;
@Autowired
@Qualifier("requestProcessedTemplate")
privatetransientSimpleMailMessagesimpleMailMessage;
privateList<FixedDepositDetails>getInactiveFixedDeposits(){
returnmyFixedDepositDao.getInactiveFixedDeposits();
}
publicvoidsendEmail()throwsAddressException,MessagingException{
List<FixedDepositDetails>inactiveFixedDeposits=getInactiveFixedDeposits();
for(FixedDepositDetailsfixedDeposit:inactiveFixedDeposits){
MimeMessagemimeMessage=mailSender.createMimeMessage();
MimeMessageHelpermimeMessageHelper=newMimeMessageHelper(mimeMessage);
mimeMessageHelper.setTo(fixedDeposit.getEmail());
mimeMessageHelper.setSubject(simpleMailMessage.getSubject());
mimeMessageHelper.setText(simpleMailMessage.getText());
mailSender.send(mimeMessage);
}
myFixedDepositDao.setFixedDepositsAsActive(inactiveFixedDeposits);
}
}
TheaboveexamplelistingshowsthatJavaMailSender’ssendmethodisusedtosendaMIMEmessage.
As JavaMailSenderImpl instance implements Spring’s JavaMailSender interface, JavaMailSenderImpl
instance (refer example listing 8-12) is autowired into the FixedDepositProcessorJob instance.
SimpleMailMessage instance named requestProcessedTemplate (refer example listing 8-14) is also
autowired intothe FixedDepositProcessorJob instance. The mailSender instance variable is defined of
type JavaMailSender (and not MailSender) because the FixedDepositProcessorJob creates and sends
MIMEmessages.FixedDepositProcessorJob’ssendEmailmethodcreatesaninstanceofaMimeMessage
using JavaMailSender’s createMimeMessage method. Spring’s MimeMessageHelper is then used to
populatetheMimeMessageinstancewithto,subjectandtextproperties.
The following example listing shows how the FixedDepositProcessorJob’s sendEmail method can be
writtenusingSpring’sMimeMessagePreparatorcallbackinterfaceinsteadofMimeMessageHelper:
Examplelisting8-18–MimeMessagePreparatorusage
importjavax.mail.Message;
importjavax.mail.internet.InternetAddress;
importorg.springframework.mail.javamail.MimeMessagePreparator;
publicclassFixedDepositProcessorJob{
.....
publicvoidsendEmail_()throwsAddressException,MessagingException{
List<FixedDepositDetails>inactiveFixedDeposits=getInactiveFixedDeposits();
for(finalFixedDepositDetailsfixedDeposit:inactiveFixedDeposits){
mailSender.send(newMimeMessagePreparator(){
@Override
publicvoidprepare(MimeMessagemimeMessage)throwsException{
mimeMessage.setRecipient(Message.RecipientType.TO,
newInternetAddress(fixedDeposit.getEmail()));
mimeMessage.setSubject(simpleMailMessage.getText());
mimeMessage.setText(simpleMailMessage.getText());
}
});
}
myFixedDepositDao.setFixedDepositsAsActive(inactiveFixedDeposits);
}
}
TheaboveexampleshowsthataMimeMessagePreparatorinstanceispassedtoJavaMailSender’ssend
method to prepare a MimeMessage instance for sending. MimeMessagePreparator’s prepare method
providesanewinstanceofMimeMessagethatyouneedtopopulate.Intheaboveexamplelisting,notice
thatsettingtheMimeMessage’srecipientpropertyrequiresyoutodealwithlower-levelJavaMailAPI.In
example listing 8-17, MimeMessageHelper’s setTo method accepted an email id of the recipient as a
stringargumenttosettheMimeMessage’srecipientproperty.Forthisreason,youshouldconsiderusing
MimeMessageHelper to populate the MimeMessage instance passed to the prepare method of
MimeMessagePreparator.
Let’snowlookathowyoucanuseSpringtoexecuteataskasynchronously,andtoscheduleexecutionofa
taskinthefuture.
8-6Taskschedulingandasynchronousexecution
You can asynchronously execute java.lang.Runnable tasks using Spring’s TaskExecutor, and you can
schedule execution ofjava.lang.Runnable tasks using Spring’s TaskScheduler. Instead of directly using
TaskExecutorandTaskScheduler,youcanuseSpring’s@Asyncand@Scheduledannotationstoexecutea
methodasynchronouslyandtoscheduleexecutionofamethod,respectively.
Let’sfirstlookatTaskExecutorandTaskSchedulerinterfaces.
TaskExecutorinterface
Java 5 introduced the concept of executors for executing java.lang.Runnable tasks. An executor
implements java.util.concurrent.Executor interface that defines a single method, execute(Runnable
runnable).Spring’sTaskExecutorextendsjava.util.concurrent.Executorinterface.Springalsoprovidesa
couple of TaskExecutor implementations that you can choose from depending upon your application’s
requirements. DependingupontheTaskExecutorimplementationyouchoose, the Runnable task may be
executed synchronously or asynchronously, using a thread pool or CommonJ, and so on. Some of the
TaskExecutor implementations provided by Spring are: ThreadPoolTaskExecutor (asynchronously
executestasksusingathreadfromathreadpool),SyncTaskExecutor(executestaskssynchronously)and
SimpleAsyncTaskExecutor(asynchronouslyexecuteseachtaskinanewthread).
ThreadPoolTaskExecutor is the most commonly used TaskExecutor implementation that uses Java 5’s
ThreadPoolExecutor to execute tasks. The following example listing shows how to configure a
ThreadPoolTaskExecutorinstanceintheapplicationcontextXMLfile:
Examplelisting8-19–ThreadPoolTaskExecutorconfiguration
<beanid="myTaskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<propertyname="corePoolSize"value="5"/>
<propertyname="maxPoolSize"value="10"/>
<propertyname="queueCapacity"value="15"/>
<propertyname="rejectedExecutionHandler"ref="abortPolicy"/>
</bean>
<beanid="abortPolicy"class="java.util.concurrent.ThreadPoolExecutor.AbortPolicy"/>
ThecorePoolSizepropertyspecifiestheminimumnumberofthreadsinthethreadpool.ThemaxPoolSize
property specifies the maximum number of threads that can be accommodated in the thread pool. The
queueCapacity property specifies the maximum number of tasks that can wait in the queue if all the
threadsinthethread pool arebusy executingtasks.TherejectedExecutionHandler propertyspecifiesa
handlerfortasksrejectedbytheThreadPoolTaskExecutor.AtaskisrejectedbyThreadPoolTaskExecutor
ifthequeueisfullandthereisnothreadavailableinthethreadpoolforexecutingthesubmittedtask.The
rejectedExecutionHandler property refers to an instance of
java.util.concurrent.RejectedExecutionHandlerobject.
In example listing 8-19, the rejectedExecutionHandler property refers to
java.util.concurrent.ThreadPoolExecutor.AbortPolicy instance that always throws
RejectedExecutionException. The other possible handlers for rejected tasks are:
java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy (the rejected task is executed in caller’s
thread), java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy (the handler discards the oldest
task from the queue and retries executing the rejected task), and
java.util.concurrent.ThreadPoolExecutor.DiscardPolicy(thehandlersimplydiscardstherejectedtask).
The <executor> element of Spring’s task schema simplifies configuring a ThreadPoolTaskExecutor
instance,asshowninthefollowingexamplelisting:
Examplelisting8-20–ThreadPoolTaskExecutorconfigurationusingSpring’staskschema
<beans.....xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation=".....http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.0.xsd">
<task:executorid="myTaskExecutor"pool-size="5-10"
queue-capacity="15"rejection-policy="ABORT"/>
</beans>
Intheaboveexamplelisting,the<executor>elementconfiguresaThreadPoolTaskExecutorinstance.The
pool-sizeattributespecifiesthecorepoolsizeandthemaximumpoolsize.Intheaboveexamplelisting,5
is the core pool size and 10 is the maximum pool size. The queue-capacity attribute sets the
queueCapacity property, and rejection-policy attribute specifies the handler for rejected tasks. The
possible values of rejection-policy attribute are ABORT, CALLER_RUNS, DISCARD_OLDEST, and
DISCARD.
OnceyouhaveconfiguredaThreadPoolTaskExecutorinstancebyexplicitlydefiningitasaSpringbean
(referexamplelisting8-19)orbyusingSpring’staskschema(referexamplelisting8-20),youcaninject
theThreadPoolTaskExecutorinstanceintobeansthatwanttoasynchronouslyexecutejava.lang.Runnable
tasks,asshowninthefollowingexamplelisting:
Examplelisting8-21–ExecutingtasksusingThreadPoolTaskExecutor
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.core.task.TaskExecutor;
@Component
publicclassSample{
@Autowired
privateTaskExecutortaskExecutor;
publicvoidexecuteTask(Runnabletask){
taskExecutor.execute(task);
}
}
Intheaboveexamplelisting,aninstanceofThreadPoolTaskExecutorisautowiredintotheSampleclass,
andislaterusedbySample’sexecuteTaskmethodtoexecuteajava.lang.Runnabletask.
TaskExecutor executes a java.lang.Runnable task immediately after it is submitted, and the task is
executedonlyonce.Ifyouwanttoscheduleexecutionofajava.lang.Runnabletask,andyouwantthetask
tobeexecutedperiodically,youshoulduseaTaskSchedulerimplementation.
TaskSchedulerinterface
Spring’sTaskScheduler interface provides the abstraction to schedule execution of java.lang.Runnable
tasks. Spring’s Trigger interface abstracts the time when a java.lang.Runnable task is executed. You
associateaTaskSchedulerinstancewithaTriggerinstancetoscheduleexecutionofjava.lang.Runnable
tasks.PeriodicTrigger(animplementationofTriggerinterface)isusedifyouwantperiodicexecutionof
tasks.CronTrigger(anotherimplementationofTriggerinterface)acceptsacronexpressionthatindicates
thedate/timewhenthetaskisexecuted.
ThreadPoolTaskScheduler is one of the most commonly used implementations of TaskScheduler that
internally uses Java 5’s ScheduledThreadPoolExecutor (an implementation of Java 5’s
ScheduledExecutorService interface) to schedule task execution. You can configure a
ThreadPoolTaskSchedulerimplementationandassociateitwithaTriggerimplementationtoscheduletask
execution.ThefollowingexamplelistingshowshowThreadPoolTaskSchedulerisconfiguredandused:
Examplelisting8-22–ThreadPoolTaskExecutorconfigurationandusage
------------ThreadPoolTaskSchedulerconfiguration---------------------
<beanid="myScheduler"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler">
<propertyname="poolSize"value="5"/>
</bean>
---------------ThreadPoolTaskSchedulerusage---------------------
importorg.springframework.scheduling.TaskScheduler;
importorg.springframework.scheduling.support.PeriodicTrigger;
@Component
publicclassSample{
@Autowired
@Qualifier("myScheduler")
privateTaskSchedulertaskScheduler;
publicvoidexecuteTask(Runnabletask){
taskScheduler.schedule(task,newPeriodicTrigger(5000));
}
}
In the above example listing, ThreadPoolTaskScheduler’s poolSize property specifies the number of
threadsinthethreadpool.Toscheduleataskforexecution,ThreadPoolTaskScheduler’sschedulemethod
is called, passing the java.lang.Runnable task and a Trigger instance. In the above example listing,
PeriodicTriggerinstanceispassedtoThreadPoolTaskScheduler’sschedulemethod.Theargumenttothe
PeriodicTriggerconstructorspecifiesthetimeinterval(inmilliseconds)betweentaskexecutions.
The <scheduler> element of Spring’s task schema simplifies configuring a ThreadPoolTaskScheduler
instance.TheThreadPoolTaskSchedulerinstancecreatedbythe<scheduler>elementcanbeusedbythe
<scheduled-tasks>elementofSpring’staskschematoscheduleexecutionofbeanmethods.Thefollowing
examplelistingshowshow<scheduler>and<scheduled-tasks>elementsareusedbyMyBankapplication
toexecuteFixedDepositProcessorJob’ssendEmailmethodevery5seconds:
Examplelisting8-23–<scheduler>and<scheduled-tasks>elements
Project–ch08-bankapp
Sourcelocation-src/main/java/sample/spring/chapter08/bankapp/job
<task:schedulerid="emailScheduler"pool-size="10"/>
<task:scheduled-tasksscheduler="emailScheduler">
<task:scheduledref="FixedDepositProcessorJob"method="sendEmail"fixed-rate="5000"/>
</task:scheduled-tasks>
<beanid="FixedDepositProcessorJob"
class="sample.spring.chapter08.bankapp.job.FixedDepositProcessorJob"/>
In theaboveexamplelisting,the<scheduler>elementconfiguresaThreadPoolTaskScheduler instance.
Theidattributeofthe<scheduler>elementspecifiesthenamewithwhichtheThreadPoolTaskScheduler
instanceisaccessedbyotherbeansintheSpringcontainer.The<scheduled-tasks>element’sscheduler
attribute specifies reference to the ThreadPoolTaskScheduler instance that is used for scheduling
executionofbeanmethods.Intheaboveexamplelisting,theThreadPoolTaskSchedulerinstancecreated
bythe<scheduler>elementisreferencedbythe<scheduled-tasks>element’sscheduledattribute.
The<scheduled-tasks>element contains one or more <scheduled>elements. The <scheduled> element
containsinformationaboutthebeanmethodtobeexecutedandthetriggerforthebeanmethodexecution.
TherefattributespecifiesreferencetoaSpringbean,themethodattributespecifiesamethodofthebean
referencedbytherefattribute,andthefixed-rate attribute (an interval-based trigger)specifiesthetime
interval between successive method executions. In example listing 8-23, the <scheduled> element
specifiesthatFixedDepositProcessorJob’ssendEmailmethodisexecutedevery5seconds.
Instead of using fixed-rate attribute of the <scheduled> element, you can use fixed-delay (an interval-
basedtrigger)orcron(acron-basedtrigger)ortrigger(referencetoaTriggerimplementation)attribute,
tospecifyatriggerforthebeanmethodexecution.
Let’snowlookatSpring’s@Asyncand@Scheduledannotations.
@Asyncand@Scheduledannotations
IfyouannotateabeanmethodwithSpring’s@Asyncannotation,itisasynchronouslyexecutedbySpring.
If you annotate a bean method with Spring’s @Scheduled annotation, it is scheduled for execution by
Spring.
Useof@Asyncand@Scheduledannotationsisenabledby<annotation-driven>elementofSpring’stask
schema,asshowninthefollowingexamplelisting:
Examplelisting8-24–Enabling@Asyncand@Scheduledannotations
<task:annotation-drivenexecutor="anExecutor"scheduler="aScheduler"/>
<task:executorid="anExecutor"/>
<task:scheduled-tasksscheduler="aScheduler">
<task:scheduledref="sampleJob"method="doSomething"fixed-rate="5000"/>
</task:scheduled-tasks>
The<annotation-driven>element’sexecutorattributespecifiesreferencetoaSpring’sTaskExecutor(or
Java5’sExecutor)instancethatisusedforexecuting@Asyncannotatedmethods.Theschedulerattribute
specifiesreferencetoaSpring’sTaskScheduler(orJava5’sScheduledExecutorService)instancethatis
usedforexecuting@Scheduledannotatedmethods.
Let’snowlookat@Asyncannotationindetail.
@Asyncannotation
Thefollowingexamplelistinghighlightssomeoftheimportantpointsthatyouneedtoknowwhenusing
@Asyncannotation:
Examplelisting8-25–@Asyncannotationusage
importjava.util.concurrent.Future;
importorg.springframework.scheduling.annotation.Async;
importorg.springframework.scheduling.annotation.AsyncResult;
importorg.springframework.stereotype.Component;
@Component
publicclassSample{
@Async
publicvoiddoA(){.....}
@Async(value="someExecutor")
publicvoiddoB(Stringstr){.....}
@Async
publicFuture<String>doC(){
returnnewAsyncResult<String>("Hello");
}
}
@Asyncannotation’svalueattributespecifiestheSpring’sTaskExecutor(orJava5’sExecutor)instance
to use for asynchronously executing the method. Asthe@Async annotation on the doA method doesn’t
specifytheexecutortouse,Spring’sSimpleAsyncTaskExectorisusedforasynchronouslyexecutingthe
doA method. @Async annotation on the doB method specifies the value attribute’s value as
someExecutor,whichmeansthebeannamedsomeExecutor(oftypeTaskExecutororJava5’sExecutor)is
usedforasynchronouslyexecutingthedoBmethod.@Asyncannotatedmethodscanacceptarguments,like
thedoBmethodintheaboveexamplelisting.@Asyncannotatedmethodscaneitherreturnvoid(likethe
doA and doB methods) or a Future instance (like the doC method). To return a Future instance, you’ll
need to wrap the value that you want to return into an AsyncResult object, and return the AsyncResult
object.
Let’snowlookat@Scheduledannotationindetail.
@Scheduledannotation
Thefollowingexamplelistinghighlightssomeoftheimportantpointsthatyouneedtoknowwhenusing
@Scheduledannotation:
Examplelisting8-26–@Scheduledannotationusage
importorg.springframework.scheduling.annotation.Scheduled;
@Component
publicclassSample{
@Scheduled(cron="009-17**MON-FRI")
publicvoiddoA(){.....}
@Scheduled(fixedRate=5000)
publicvoiddoB(){.....}
}
Amethodannotatedwith@Scheduledannotationmustreturnvoidandmustnotbedefinedtoacceptany
arguments.Youmustspecifycron,fixedRateorfixedDelayattributeof@Scheduledannotation.
Itisimportanttonotethatifthe@Async(or@Scheduled)annotationisspecifiedononeormoremethods
ofaclass,youarerequiredtoincludeCGLIBJARfileinyourapplication’sclasspath.Ifthe@Async(or
@Scheduled) annotation is specified only on the methods defined in an interface, you don’t need to
includeCGLIBJARfile.StartingwithSpring3.2,theCGLIBclassesarepackagedwithinthespring-core
JARfileitself;therefore,youdon’tneedtoexplicitlyspecifythatyourprojectisdependentonCGLIB
JARfile.
NOTEIfyouwanttousetheQuartzScheduler(http://quartz-scheduler.org/)inyourSpringapplication,
youcanusetheintegrationclassesprovidedbySpringthatsimplifyusingtheQuartzScheduler.
Spring simplifies using caching in an application by providing an abstraction on top of
java.util.concurrent.ConcurrentMapandEhcache(http://ehcache.org/).
8-7Caching
Ifyouwanttousecachinginyourapplication,youcanconsiderusingSpring’scacheabstraction.Spring’s
cacheabstractionshieldsdevelopersfromdirectlydealingwiththeunderlyingcachingimplementation’s
API. Starting with Spring 3.2, cache abstraction is available out-of-the-box for
java.util.concurrent.ConcurrentMap,Ehcache and for caching solutions that implement JSR 107 – Java
TemporaryCachingAPI(referredtoasJCACHE).
NOTEIfyouareusingacachingsolutionwhichisnotcurrentlysupportedbySpring’scacheabstraction,
you have the option to either directly use the API of the caching solution or create adapters that map
Spring’scacheabstractiontothecachingsolution.
Spring provides a CacheManager interface that defines methods for managing a collection of Cache
instances. A CacheManager instance acts as a wrapper around the cache manager provided by the
underlying caching solution. For instance, EhCacheCacheManager is a wrapper around Ehcache’s
net.sf.ehcache.CacheManager, JCacheCacheManager is a wrapper around JSR 107 provider’s
javax.cache.CacheManager implementation, and so on. A Cache instance is a wrapper around the
underlying cache, and it provides methods for interacting with the underlying cache. For instance,
EhCacheCache (a Cache implementation) is a wrapper around net.sf.ehcache.Ehcache, and
JCacheCache (a Cache implementation) is a wrapper around JSR 107 provider’s javax.cache.Cache
instance.
Spring also provides a ConcurrentMapCacheManager that you can use if you want to use
java.util.concurrent.ConcurrentMap as the underlying cache. The Cache instance managed by
ConcurrentMapCacheManager is a ConcurrentMapCache. The following diagram summarizes
relationshipbetweenCacheManagerandCacheinterfacesprovidedbySpring’scachingabstraction:
NOTE If you want to use Spring’s caching abstraction for a caching solution that is not currently
supported by Spring’s caching abstraction, all you need to do is to provide CacheManager and Cache
implementationsforthecachingsolution.
Figure8-3ACacheManagerimplementationactsaswrapperaroundthecachemanageroftheunderlying
cachingsolution,andaCacheimplementationprovidesoperationstointeractwiththeunderlyingcache.
TheabovefigureshowsthatCacheManagermanagesCacheinstances.EhCacheCacheManagermanages
EhCacheCache instances (underlying cache store is Ehcache), JCacheCacheManager manages
JCacheCache instances (underlying cache store is a caching solution that implements JSR 107),
ConcurrentMapCacheManager manages ConcurrentMapCache instances (underlying cache store is
java.util.concurrent.ConcurrentMap),andsoon.
Figure 8-3 shows a SimpleCacheManager class that implements CacheManager interface.
SimpleCacheManagerisusefulforsimplecachingscenariosandfortestingpurposes.Forinstance,ifyou
want to use java.util.concurrent.ConcurrentMap as the underlying cache store, you can use
SimpleCacheManager,insteadofConcurrentMapCacheManager,tomanagethecache.
Let’snowlookathowaCacheManagerisconfiguredintheapplicationcontextXMLfile.
ConfiguringaCacheManager
In MyBank application, a collection of java.util.concurrent.ConcurrentMap instances are used as the
underlyingcachestore;therefore,SimpleCacheManagerisusedtomanagethecache.
The following example listing shows how a SimpleCacheManager instance is configured in MyBank
application:
Examplelisting8-27–SimpleCacheManagerconfiguration
Project–ch08-bankapp
Sourcelocation-src/main/resources/META-INF/spring/
<beanid="myCacheManager"
class="org.springframework.cache.support.SimpleCacheManager">
<propertyname="caches">
<set>
<bean
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
<propertyname="name"value="FixedDepositList"/>
</bean>
<bean
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
<propertyname="name"value="FixedDeposit"/>
</bean>
</set>
</property>
</bean>
SimpleCacheManager’s caches property specifies a collection of caches managed by the
SimpleCacheManagerinstance.ConcurrentMapCacheFactoryBeanisaFactoryBeanimplementationthat
simplifies configuring a ConcurrentMapCache instance - a Cache instance that uses a
java.util.concurrent.ConcurrentHashMap instance (an implementation of
java.util.concurrent.ConcurrentMap interface) as the underlying cache store.
ConcurrentMapCacheFactoryBean’snamepropertyspecifiesanameforthecache.Intheaboveexample
listing,theFixedDepositListandFixedDepositcachesaremanagedbytheSimpleCacheManagerinstance.
Let’snowlookathowtouseSpring’scachingannotationsinapplications.
Cachingannotations-@Cacheable,@CacheEvictand@CachePut
AfteryouhaveconfiguredanappropriateCacheManagerforyourapplication,youneedtochoosehow
you want to use Spring’s cache abstraction. You can use Spring’s cache abstraction either by using
caching annotations (like @Cacheable, @CacheEvict and @CachePut) or by using Spring’s cache
schema.AsusingSpring’scacheschemaforcachingresultsinaverboseapplicationcontextXMLfile,
we’llbeonlylookingatusingcachingannotationsfordeclarativecaching.
Tousecachingannotations,youneedtoconfigure<annotation-driven>elementofSpring’scacheschema,
asshownherefortheMyBankapplication:
Examplelisting8-28–Enablecachingannotationsusing<annotation-driven>
Project–ch08-bankapp
Sourcelocation-src/main/resources/META-INF/spring/
<beans.....xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation=".....
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd">
<cache:annotation-drivencache-manager="myCacheManager"/>
.....
</beans>
Intheaboveexamplelisting,Spring’scacheschemaisincludedsothatitselementsareaccessibleinthe
application context XML file. The <annotation-driven>element’s cache-manager attribute refers to the
CacheManager bean that is used for managing the cache. You don’t need to specify the cache-manager
attributeiftheCacheManagerbeanisnamedcacheManager.
Now,thatwehaveenabledcachingannotations,let’slookatdifferentcachingannotations.
@Cacheable
@Cacheableannotationonamethodindicatesthatthevaluereturnedbythemethodiscached.Spring’s
DefaultKeyGeneratorclassisusedbydefaulttogeneratethekeywithwhichthemethod’sreturnvalueis
stored in the cache. DefaultKeyGenerator uses method signature and method arguments to compute the
key. You can use a custom key generator by providing an implementation of Spring’s KeyGenerator
interface,andspecifyingitasthevalueofkey-generatorattributeof<annotation-driven>element.
Thefollowingexamplelistingshowstheusageof@Cacheableannotationtocachethevaluereturnedby
FixedDepositService’sfindFixedDepositsByBankAccountmethodintheMyBankapplication:
Examplelisting8-29–@Cacheableannotation
Project–ch08-bankapp
Sourcelocation-src/main/java/sample/spring/chapter08/bankapp/service
packagesample.spring.chapter08.bankapp.service;
importorg.springframework.cache.annotation.Cacheable;
.....
@Service(value="FixedDepositService")
publicclassFixedDepositServiceImplimplementsFixedDepositService{
.....
@Cacheable(value={"FixedDepositList"})
publicList<FixedDepositDetails>findFixedDepositsByBankAccount(intbankAccountId){
logger.info("findFixedDepositsByBankAccountmethodinvoked");
returnmyFixedDepositDao.findFixedDepositsByBankAccount(bankAccountId);
}
}
@Cacheable annotation’s value attribute specifies the cache region into which the returned value is
cached.Inlisting8-27,wecreatedacacheregionnamedFixedDepositListfortheMyBankapplication.In
the above example listing, the @Cacheable annotation specifies that the value returned by the
findFixedDepositsByBankAccountmethodisstoredintheFixedDepositListcache.Itisimportanttonote
that@Cacheableannotatedmethod is notinvokedif the samesetofargumentvaluesarepassed tothe
method.But,@Cacheableannotatedmethodwillbeinvokedifyoupassadifferentvalueforatleastone
ofthearguments.
@CacheEvict
If you want to evict data from the cache when a method is called, annotate the method with the
@CacheEvict annotation. In the MyBank application, when a new fixed deposit is created, the fixed
depositdetailscachedbyFixedDepositServiceImpl’sfindFixedDepositsByBankAccountmethodmustbe
evictedfromthecache.ThisensuresthatwhenthenexttimefindFixedDepositsByBankAccountmethodis
invoked,thenewlycreatedfixeddepositisalsofetchedfromthedatabase.Thefollowingexamplelisting
showsusageof@CacheEvictannotation:
Examplelisting8-30–@CacheEvictannotation
Project–ch08-bankapp
Sourcelocation-src/main/java/sample/spring/chapter08/bankapp/service
packagesample.spring.chapter08.bankapp.service;
importorg.springframework.cache.annotation.CacheEvict;
.....
@Service(value="FixedDepositService")
publicclassFixedDepositServiceImplimplementsFixedDepositService{
.....
@Transactional("jmsTxManager")
@CacheEvict(value={"FixedDepositList"},allEntries=true,beforeInvocation=true)
publicvoid createFixedDeposit(final FixedDepositDetails fixedDepositDetails) throws Exception{
.....}
.....
}
In the above example listing, the @CacheEvict annotation on the createFixedDeposit method instructs
Spring to remove all the cached entries from the cache region named FixedDepositList. The value
attributespecifiesthecacheregionfromwhichtoevictthecacheditem,andallEntriesattributespecifies
whetherornotallentriesfromthespecifiedcacheregionareevicted.Ifyouwanttoevictaparticular
cacheditem,usethekeyattributetospecifythekeywithwhichtheitemiscached.Youcanalsospecify
conditional eviction of items by using the condition attribute. The condition and key attributes support
specifying values using SpEL (refer section 6-8 of chapter 6 for more details), making it possible to
perform sophisticated cache evictions. The beforeInvocation attribute specifies whether the cache
evictionisperformedbeforeorafterthemethodexecution.AsthevalueofbeforeInvocationattributeis
settotrue,cacheisevictedbeforethecreateFixedDepositmethodisinvoked.
@CachePut
Spring also provides a @CachePut annotation that indicates that a method is always invoked, and the
value returned by the method is put into the cache. @CachePut annotation is different from the
@Cacheable annotation in the sense that @Cacheable annotation instructs Spring to skip the method
invocationifthemethodiscalledwiththesamesetofargumentvalues.
Thefollowingexamplelistingshowsusageof@CachePutannotationbyFixedDepositServiceImplclass
ofMyBankapplication:
Examplelisting8-31–@CachePutannotation
Project–ch08-bankapp
Sourcelocation-src/main/java/sample/spring/chapter08/bankapp/service
packagesample.spring.chapter08.bankapp.service;
importorg.springframework.cache.annotation.CachePut;
importorg.springframework.cache.annotation.Cacheable;
.....
@Service(value="FixedDepositService")
publicclassFixedDepositServiceImplimplementsFixedDepositService{
.....
@CachePut(value={"FixedDeposit"},key="#FixedDepositId")
publicFixedDepositDetailsgetFixedDeposit(intFixedDepositId){
logger.info("getFixedDepositmethodinvokedwithFixedDepositId"+FixedDepositId);
returnmyFixedDepositDao.getFixedDeposit(FixedDepositId);
}
@Cacheable(value={"FixedDeposit"},key="#FixedDepositId")
publicFixedDepositDetailsgetFixedDepositFromCache(intFixedDepositId){
logger.info("getFixedDepositFromCachemethodinvokedwithFixedDepositId"
+FixedDepositId);
thrownewRuntimeException("Thismethodthrowsexceptionbecause"
+"FixedDepositDetailsobjectmustcomefromthecache");
}
.....
}
Intheaboveexamplelisting,thegetFixedDepositmethodisannotatedwith@CachePutannotation,which
meansthatthegetFixedDepositmethodisalwaysinvoked,andthereturnedFixedDepositDetailsobjectis
storedintothecachenamedFixedDeposit.Thevalueattributespecifiesthenameofthecacheintowhich
theFixedDepositDetails objectis stored. The key attribute specifies the key to be used for storing the
returnedFixedDepositDetailsobjectintothecache.Asyoucansee,keyattributemakesuseofSpELto
specifythekey.The#FixedDepositIdvalueofkeyattributereferstotheFixedDepositIdargumentpassed
to the getFixedDeposit method. To summarize, the FixedDepositDetails object returned by the
getFixedDeposit method is stored in the cache named FixedDeposit, and the value of FixedDepositId
methodargumentisusedasthekey.
In example listing 8-31, FixedDepositServiceImpl’s getFixedDepositFromCache method retrieves the
FixedDepositDetailsobjectfromthecachebasedonthekeyattributevaluespecifiedbythe@Cacheable
annotation. Notice that the body of the getFixedDepositFromCache method does nothing but throw a
RuntimeException. The key attribute value refers to the FixedDepositId argument passed to the
getFixedDepositFromCache method. If the FixedDepositDetails object is not found in the cache, the
getFixedDepositFromCachemethodisinvoked,whichwillresultinRuntimeException.
Let’snowlookatwhathappenswhenyouruntheMyBankapplicationofch08-bankappproject.
8-8RunningtheMyBankapplication
BankApp class of MyBank application defines the main method of the application. The main method
accesses methods of FixedDepositService and BankAccountService instances to demonstrate different
featuresthatwediscussedinthischapter.
ThefollowingexamplelistingshowstheMyBankapplication’sBankAppclass:
Examplelisting8-32–BankAppclass
Project–ch08-bankapp
Sourcelocation-src/main/java/sample/spring/chapter08/bankapp
packagesample.spring.chapter08.bankapp;
importorg.springframework.context.ApplicationContext;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
publicclassBankApp{
publicstaticvoidmain(Stringargs[])throwsException{
ApplicationContextcontext=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
BankAccountServicebankAccountService=context.getBean(BankAccountService.class);
BankAccountDetailsbankAccountDetails=newBankAccountDetails();
.....
intbankAccountId=bankAccountService.createBankAccount(bankAccountDetails);
FixedDepositServiceFixedDepositService=context.getBean(FixedDepositService.class);
FixedDepositDetailsfixedDepositDetails=newFixedDepositDetails();
.....
fixedDepositDetails.setEmail("someUser@someDomain.com");
FixedDepositService.createFixedDeposit(fixedDepositDetails);
.....
FixedDepositService.findFixedDepositsByBankAccount(bankAccountId);
FixedDepositService.findFixedDepositsByBankAccount(bankAccountId);
FixedDepositService.createFixedDeposit(fixedDepositDetails);
.....
List<FixedDepositDetails>FixedDepositDetailsList=FixedDepositService
.findFixedDepositsByBankAccount(bankAccountId);
for(FixedDepositDetailsdetail:FixedDepositDetailsList){
FixedDepositService.getFixedDeposit(detail.getFixedDepositId());
}
for(FixedDepositDetailsdetail:FixedDepositDetailsList){
FixedDepositService.getFixedDepositFromCache(detail.getFixedDepositId());
}
.....
}
}
Intheaboveexamplelisting,followingsequenceofactionsareperformedbythemainmethod:
Step 1. First, a bank account is created in the BANK_ACCOUNT_DETAILS table by calling
BankAccountService’screateBankAccountmethod.
Step 2. Corresponding to the newly created bank account, a fixed deposit is created in the
FIXED_DEPOSIT_DETAILS table by calling FixedDepositService’s createFixedDeposit method. You
shouldmakesurethatemailpropertyofFixedDepositDetailsobjectissettotheemailidwhereyoucan
checktheemails.ThecreateFixedDepositmethodsends2JMSmessages(referexamplelisting8-5).One
JMSmessagecontainstheemailidspecifiedbytheFixedDepositDetailsobject’semailproperty,andis
processedbyEmailMessageListener(referexamplelisting8-16)thatsendsanemailtothecustomer.The
otherJMSmessageisprocessedbyFixedDepositMessageListener(referexamplelisting8-11)thatsaves
the fixed deposit details in the FIXED_DEPOSIT_DETAILS table. You should also note that
FixedDepositServiceImpl’screateFixedDepositmethodisannotatedwith@CacheEvictannotation(refer
examplelisting8-30)thatresultsinremovingalltheitemscachedinFixedDepositListcache.
Step3.FixedDepositService’sfindFixedDepositsByBankAccountmethodisinvokedthatretrievesfixed
deposits corresponding to the bank account that we created in Step 1. As the
findFixedDepositsByBankAccount method is annotated with @Cacheable annotation (refer example
listing8-29),fixeddepositsreturnedbythefindFixedDepositsByBankAccountmethodarestoredinthe
cache named FixedDepositList. Listing 8-29 showed that findFixedDepositsByBankAccount method
writesthefollowingmessagetotheconsole‘findFixedDepositsByBankAccountmethodinvoked’.Inthe
aboveexamplelisting,thefindFixedDepositsByBankAccountiscalledtwiceforthesamebankAccountId
argument,butyou’llnoticethatonlyonce‘findFixedDepositsByBankAccountmethodinvoked’iswritten
to the console. This is because the second call to the findFixedDepositsByBankAccount results in
retrieving fixed deposit details from the cache named FixedDepositList, and the
findFixedDepositsByBankAccountmethodisnotexecuted.
Step 4. Corresponding to the bank account created in Step 1, another fixed deposit is created in the
FIXED_DEPOSIT_DETAILStablebycallingFixedDepositService’screateFixedDepositmethod.Now,
the FixedDepositServiceImpl’s createFixedDeposit method is annotated with @CacheEvict annotation
(referexamplelisting8-30)thatresultsinremovingalltheitemscachedinFixedDepositListcache.
Step 5. FixedDepositService’s findFixedDepositsByBankAccount method is invoked once again. This
time findFixedDepositsByBankAccount is executed because the previous call to createFixedDeposit
method (refer Step 4) resulted in evicting all the items from the FixedDepositList cache. At this time,
you’ll once again see ‘findFixedDepositsByBankAccount method invoked’ message written on the
console. The fixed deposits returned by the findFixedDepositsByBankAccount method are cached in
FixedDepositListcachebecausethemethodisannotatedwith@Cacheableannotation.
Step6.ForeachfixeddepositretrievedinStep5,FixedDepositService’sgetFixedDepositmethod(refer
example listing 8-31) is invoked. The getFixedDeposit method accepts the fixed deposit identifier and
returns the fixed depositinformation from the database. The getFixedDeposit method is annotated with
@CachePut,whichmeansitisalwaysinvoked.ThefixeddepositreturnedbythegetFixedDepositmethod
iscachedintheFixedDepositcache.
Step7.For eachfixed depositretrieved in Step 5,FixedDepositService’s getFixedDepositFromCache
method(referexamplelisting8-31)isinvoked.ThegetFixedDepositFromCachemethodacceptsthefixed
depositidentifierandthrowsaRuntimeExceptiononexecution.ThegetFixedDepositFromCachemethod
is annotated with @Cacheable, and is executed only when the fixed deposit is not found in the
FixedDepositcache.AsallthefixeddepositswerecachedbythegetFixedDepositmethodinStep6,the
getFixedDepositFromCachemethodisneverexecuted.
Step8.Every5seconds,theFixedDepositProcessorJob(referexamplelisting8-17)checksifanynew
fixed deposits have been created in the database. If new fixed deposits are found in the database, the
FixedDepositProcessorJobactivatesthefixeddepositandsendsanemailtothecustomer,confirmingthat
thefixeddepositrequesthasbeensuccessfullyprocessed.
8-9Summary
In this chapter, we touched upon some of the frequently used features of Spring. We saw that Spring
simplifiessendingandreceivingJMSmessages,sendingemails,asynchronouslyinvokingbeanmethods,
scheduling bean methods for execution, and caching data. In the next chapter, we’ll look at Spring’s
supportforAOP(Aspect-orientedprogramming).
Chapter9-Aspect-orientedprogramming
9-1Introduction
Aspect-oriented programming (AOP) is a programming approach in which responsibilities that are
distributedacrossmultipleclassesareencapsulatedintoaseparateclass,referredtoasan‘aspect’.The
responsibilities that are distributed across multiple classes are referred to as ‘cross-cutting concerns’.
Logging,transactionmanagement,caching,security,andsoon,areexamplesofcross-cuttingconcerns.
Spring provides an AOP framework that is used internally by Spring for implementing declarative
services, like transaction management (refer chapter 7) and caching (refer chapter 8). Instead of using
Spring AOP framework, you can consider using AspectJ (http://www.eclipse.org/aspectj/) as the AOP
framework for your application. As Spring AOP framework is sufficient for most AOP scenarios, and
providesintegrationwiththeSpringcontainer,thischapterfocusesonSpringAOPframework.
Let’sbeginthischapterbylookingatanexampleusageofAOP.
9-2AsimpleAOPexample
Let’ssaythatforauditingpurposeswewanttocapturetheargumentspassedtothemethodsofclasses
definedintheservicelayerofMyBankapplication.Asimpleapproachtologdetailsofmethodarguments
istowritethelogginglogicinsideeachmethod.But,thiswouldmeanthateachmethodisadditionally
responsible for logging details of method arguments. As the responsibility to log details of method
argumentsisdistributedacrossmultipleclassesandmethods,itrepresentsacross-cuttingconcern.
Toaddressacross-cuttingconcernusingAOP,youneedtofollowthesesteps:
·createaJavaclass(referredtoasanaspect)
·addimplementationofthecross-cuttingconcerntotheJavaclass,and
·usearegularexpressiontospecifythemethodstowhichthecross-cuttingconcernapplies
IntermsofAOPterminology,themethodsofanaspectthatimplementcross-cuttingconcernsarereferred
toasadvices. And, each advice is associated with a pointcut that identifies the methods to which the
adviceapplies.Themethodstowhichanadviceappliesarereferredtoasjoinpoints.
InSpringAOP,youhavetheoptiontodevelopanaspectusingAspectJannotation-styleorXMLschema-
style. InAspectJannotation-style,AspectJannotations,like@Aspect,@Pointcut,@Before, and so on,
are used to develop an aspect. In XML schema-style, elements of Spring’s aop schema are used to
configureaSpringbeanasanaspect.
IMPORTchapter9/ch09-simple-aop(Thech09-simple-aopprojectshowstheMyBankapplicationthat
usesSpringAOPtologdetailsofmethodargumentspassedtothemethodsdefinedbytheclassesinthe
service layerof MyBank application. To runthe application, execute the main method of the BankApp
classofthisproject)
The following example listing shows the logging aspect that logs details of the arguments passed to
servicemethodsinMyBankapplication:
Examplelisting9-1–LoggingAspectclass
Project–ch09-simple-aop
Sourcelocation-src/main/java/sample/spring/chapter09/bankapp/aspects
packagesample.spring.chapter09.bankapp.aspects;
importorg.aspectj.lang.JoinPoint;
importorg.aspectj.lang.annotation.Aspect;
importorg.aspectj.lang.annotation.Before;
importorg.springframework.stereotype.Component;
@Aspect
@Component
publicclassLoggingAspect{
privateLoggerlogger=Logger.getLogger(LoggingAspect.class);
@Before(value="execution(*sample.spring.chapter09.bankapp.service.*Service.*(..))")
publicvoidlog(JoinPointjoinPoint){
logger.info("Entering"
+joinPoint.getTarget().getClass().getSimpleName()+"'s"
+joinPoint.getSignature().getName());
Object[]args=joinPoint.getArgs();
for(inti=0;i<args.length;i++){
logger.info("args["+i+"]-->"+args[i]);
}
}
}
Inexamplelisting9-1:
·AspectJ’s@Aspecttype-levelannotationspecifiesthattheLoggingAspectclassisanAOPaspect
·AspectJ’s@Beforemethod-levelannotationspecifiesthatthelogmethodrepresentsanadvicethat
isappliedbeforethemethodsmatchedbythevalueattributeareexecuted.Refersection9-5tolearn
aboutdifferentadvicetypesthatyoucancreate.
·@Beforeannotation’svalueattributespecifiesapointcutexpressionthatisusedbySpringAOP
frameworktoidentifymethods(referredtoastargetmethods)towhichanadviceapplies.Insection
9-4, we’ll take an in-depth look at pointcut expressions. For now, you can assume that the pointcut
expressionexecution(* sample.spring.chapter09.bankapp.service.*Service.*(..)) specifies that
LoggingAspect’slogmethodisappliedtoallthepublicmethodsdefinedbyclasses(orinterfaces)in
sample.spring.chapter09.bankapp.servicepackage,andwhosenamesendwithService.
· Thelogmethod’sJoinPointargumentrepresentsthetargetmethodtowhich the advice is being
applied.ThelogmethodusesJoinPointinstancetoretrieveinformationabouttheargumentspassedto
thetargetmethod.Inexamplelisting9-1,JoinPoint’sgetArgsmethodisinvokedtoretrievethemethod
argumentsbeingpassedtothetargetmethod.
YouneedtoregisteranaspectwiththeSpringcontainersothattheSpringAOPframeworkismadeaware
oftheaspect. In examplelisting 9-1, theLoggingAspect class isannotated withSpring’s @Component
annotationsothatitisautomaticallyregisteredwiththeSpringcontainer.
The following example listing shows the BankApp class that invokes methods of
BankAccountServiceImpl (implements BankAccountService interface) and FixedDepositServiceImpl
(implementsFixedDepositServiceinterface)classesofMyBankapplication:
Examplelisting9-2–BankAppclass
Project–ch09-simple-aop
Sourcelocation-src/main/java/sample/spring/chapter09/bankapp
packagesample.spring.chapter09.bankapp;
.....
publicclassBankApp{
publicstaticvoidmain(Stringargs[])throwsException{
ApplicationContextcontext=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
BankAccountServicebankAccountService=context.getBean(BankAccountService.class);
BankAccountDetailsbankAccountDetails=newBankAccountDetails();
bankAccountDetails.setBalanceAmount(1000);
bankAccountDetails.setLastTransactionTimestamp(newDate());
bankAccountService.createBankAccount(bankAccountDetails);
FixedDepositServiceFixedDepositService=context.getBean(FixedDepositService.class);
FixedDepositService.createFixedDeposit(newFixedDepositDetails(1,1000,
12,"someemail@somedomain.com"));
}
}
In the above example listing, BankAccountService’s createBankAccount and FixedDepositService’s
createFixedDeposit methods are invoked by BankApp’s main method. If you execute BankApp’s main
method,you’llseethefollowingoutputontheconsole:
INFOLoggingAspect-EnteringBankAccountServiceImpl'screateBankAccount
INFOLoggingAspect-args[0]-->BankAccountDetails[accountId=0,balanceAmount=1000,lastTransactionTimestamp=Sat
Oct2716:48:11IST2012]
INFOBankAccountServiceImpl-createBankAccountmethodinvoked
INFOLoggingAspect-EnteringFixedDepositServiceImpl'screateFixedDeposit
INFOLoggingAspect-args[0]-->id:1,depositamount:1000.0,tenure:12,email:someemail@somedomain.com
INFOFixedDepositServiceImpl-createFixedDepositmethodinvoked
The above output shows that LoggingAspect’s log method is executed before the execution of
BankAccountService’screateBankAccountandFixedDepositService’screateFixedDepositmethod.
InthecontextofLoggingAspect,let’slookathowSpringAOPframeworkworks.
NOTETouseAspectJannotation-styleaspects,ch09-simple-aopprojectdefinesdependencyonspring-
aop,aopalliance,aspectjrtandaspectjweaverJARfiles.Pleaserefertothepom.xmlfileofch09-simple-
aopprojectfordetails.
9-3SpringAOPframework
SpringAOPframeworkisproxy-based;aproxyobjectiscreatedforobjectsthataretargetofanadvice.
Aproxyisanintermediaryobject,introducedbytheAOPframework,betweenthecallingobjectandthe
targetobject.Atruntime,callstothetargetobjectareinterceptedbytheproxy,andadvicesthatapplyto
thetargetmethodareexecutedbytheproxy.InSpringAOP,atargetobjectisabeaninstanceregistered
withtheSpringcontainer.
ThefollowingdiagramshowshowtheLoggingAspect’slogmethod(referexamplelisting9-1)isapplied
tothemethodsofBankAccountServiceandFixedDepositServiceobjects(referexamplelisting9-2):
Figure9-1Theproxyobjectisresponsibleforinterceptingmethodcallstothetargetobjectandexecuting
theadvicesthatapplytothetargetmethod.
TheabovediagramshowsthataproxyiscreatedforbothBankAccountServiceandFixedDepositService
objects. The proxy for BankAccountService intercepts the call to BankAccountService’s
createBankAccount method, and the proxy for FixedDepositService intercepts the call to
FixedDepositService’s createFixedDeposit method. The proxy for BankAccountService first executes
LoggingAspect’slogmethod,followedbyBankAccountService’screateBankAccountmethodinvocation.
Similarly, the proxy for FixedDepositService first executes LoggingAspect’s log method, followed by
FixedDepositService’screateFixedDepositmethodinvocation.
Thetimingoftheexecutionofanadvice(likethelogmethodofLoggingAspectaspect)dependsonthe
typeoftheadvice.InAspectJannotation-style,typeofanadviceisspecifiedbytheAspectJannotationon
theadvice.Forinstance,AspectJ’s@Beforeannotationspecifiesthattheadviceisexecutedbeforethe
invocation of the target method, @After annotation specifies that the advice is executed after the
invocationofthetargetmethod,@Aroundannotationspecifiesthattheadviceisexecutedbothbeforeand
after the execution of the target method, and so on. As LoggingAspect’slog method is annotated with
@Beforeannotation,logmethodisexecutedbeforetheexecutionofthetargetobject’smethod.
Let’snowlookathowSpringAOPframeworkcreatesaproxyobject.
Proxycreation
When using Spring AOP, you have the option to explicitly create AOP proxies via Spring’s
ProxyFactoryBean (refer to org.springframework.aop.framework package) or you can let Spring
automaticallycreateAOPproxies.TheautomaticgenerationofAOPproxiesbySpringAOPisreferredto
asautoproxying.
If you want to use AspectJ annotation-style for creating aspects, you need to enable support for using
AspectJannotation-stylebyspecifyingSpringaopschema’s<aspectj-autoproxy>element.The<aspectj-
autoproxy>elementalsoinstructsSpringAOPframeworktoautomaticallycreateAOPproxiesfortarget
objects.Thefollowingexamplelistingshowsusageof<aspectj-autoproxy>elementinch09-simple-aop
project:
Examplelisting9-3–applicationContext.xml-<aspectj-autoproxy>element
Project–ch09-simple-aop
Sourcelocation-src/main/resources/META-INF/spring
<beans.....
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=".....http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<context:component-scanbase-package="sample.spring"/>
<aop:aspectj-autoproxyproxy-target-class="false"expose-proxy="true"/>
</beans>
The <aspectj-autoproxy> element’s proxy-target-class attribute specifies whether JavaSE- or CGLIB-
basedproxiesarecreatedfortargetobjects,andexpose-proxyattributespecifieswhethertheAOPproxy
itselfisavailabletothetargetobject.Ifexpose-proxy’svalueissettotrue,thetargetobject’smethodcan
accesstheAOPproxybycallingAopContext’scurrentProxystaticmethod.
SpringAOPframeworkcreatesaCGLIB-orJavaSE-basedproxy.Ifthetargetobjectdoesn’timplement
any interface, Spring AOP creates a CGLIB-based proxy. If the target object implements one or more
interfaces, Spring AOP creates a JavaSE-based proxy. If the value of <aspectj-autoproxy> element’s
proxy-target-classattributeissettofalse,itinstructsSpringAOPtocreateaJavaSE-basedproxyifthe
targetobjectimplementsoneormoreinterface.Ifyousetproxy-target-classattribute’svaluetotrue, it
instructs Spring AOP to create CGLIB-based proxies even if a target object implements one or more
interfaces.
NOTEStartingwithSpring3.2,theCGLIBclassesarepackagedwithinthespring-coreJARfileitself;
therefore,youdon’tneedtoexplicitlyincludeCGLIBJARfileinyourapplicationtoallowSpringAOP
frameworktocreateCGLIB-basedproxiesfortargetobjects.
Let’snowlookatascenarioinwhichyou’dprefertosetexpose-proxyattributeof<aspectj-autoproxy>
elementtotrue.
IMPORT chapter 9/ch09-aop-proxy (The ch09-aop-proxy project shows the MyBank application in
which AopProxy’s currentProxy method is used by a target method to retrieve the AOP proxy object
createdbySpringAOPframework.Toruntheapplication,executethemainmethodoftheBankAppclass
ofthisproject)
expose-proxyattribute
The following example listing shows a modified BankAccountServiceImpl class in which the
createBankAccountmethodinvokestheisDuplicateAccountmethodtocheckifabankaccountwithsame
detailsalreadyexistsinthesystem:
Examplelisting9-4–BankAccountServiceImplclass
@Service(value="bankAccountService")
publicclassBankAccountServiceImplimplementsBankAccountService{
@Autowired
privateBankAccountDaobankAccountDao;
@Override
publicintcreateBankAccount(BankAccountDetailsbankAccountDetails){
if(!isDuplicateAccount(bankAccountDetails)){
returnbankAccountDao.createBankAccount(bankAccountDetails);
}else{
thrownewBankAccountAlreadyExistsException("Bankaccountalreadyexists");
}
}
@Override
publicbooleanisDuplicateAccount(BankAccountDetailsbankAccountDetails){.....}
}
The above example listing shows that the createBankAccount method invokes the isDuplicateAccount
methodtocheckifthebankaccountalreadyexistsinthesystem.
Now,thequestionarisesthatwhethertheLoggingAspect’slogmethod(referexamplelisting9-1)willbe
executedwhentheisDuplicateAccountmethodisinvokedbythecreateBankAccountmethod?Eventhough
theisDuplicateAccountmethodmatchesthepointcutexpressionspecifiedby@Beforeannotationonthe
LoggingAspect’slogmethod(referexamplelisting9-1),theLoggingAspect’slogmethodisnotinvoked.
ThisisbecausemethodsinvokedbythetargetobjectonitselfarenotproxiedbytheAOPproxy.Asthe
methodinvocationdoesn’tgothroughtheAOPproxyobject,anyadvicethatisassociatedwiththetarget
methodisnotexecuted.
To ensure that the call to isDuplicateAccount method goes to the target object through the AOP proxy,
retrieve the AOP proxy object in the createBankAccount method and invoke the isDuplicateAccount
methodontheAOPproxyobject.ThefollowingexamplelistingshowshowtoretrieveAOPproxyobject
insidethecreateBankAccountmethod:
Examplelisting9-5–BankAccountServiceImplclass
Project–ch09-aop-proxy
Sourcelocation-src/main/java/sample/spring/chapter09/bankapp/service
packagesample.spring.chapter09.bankapp.service;
importorg.springframework.aop.framework.AopContext;
.....
@Service(value="bankAccountService")
publicclassBankAccountServiceImplimplementsBankAccountService{
.....
@Override
publicintcreateBankAccount(BankAccountDetailsbankAccountDetails){
//--obtaintheproxyandinvoketheisDuplicateAccountmethodviaproxy
booleanisDuplicateAccount=
((BankAccountService)AopContext.currentProxy()).isDuplicateAccount(bankAccountDetails);
if(!isDuplicateAccount){.....}
.....
}
@Override
publicbooleanisDuplicateAccount(BankAccountDetailsbankAccountDetails){.....}
}
Intheaboveexamplelisting,calltoAopContext’scurrentProxymethodreturnstheAOPproxythatmade
thecalltothecreateBankAccountmethod.IfthecreateBankAccountmethodisnotinvokedthroughSpring
AOPframeworkorthevalueofexpose-proxyattributeof<aspectj-autoproxy>elementisfalse,calltothe
currentProxy method will result in throwing java.lang.IllegalStateException. As the AOP proxy
implementsthesameinterfaceasthetargetobject,theaboveexamplelistingshowsthattheAOPproxy
returned by the currentProxy method is cast to BankAccountService type and BankAccountService’s
isDuplicateAccountmethodisinvoked.
If you now go to ch09-aop-proxyproject and execute BankApp’s main method, you’ll notice that
LoggingAspect’s log method is executed when isDuplicateAccount method is invoked by the
createBankAccountmethod.
Let’snowtakeatanin-depthlookatpointcutexpressions.
9-4Pointcutexpressions
WhenusingSpringAOP,apointcutexpressionidentifiesthejoinpointstowhichanadviceisapplied.In
SpringAOP,joinpointsarealwaysbeanmethods.Ifyouwanttoapplyanadvicetofields,constructors,
non-publicmethods,andtoobjectsthatarenotSpringbeans,youshoulduseAspectJinsteadofSpring
AOPframework.IfyouwanttodevelopaspectsusingAspectJannotation-style,youhavetheoptionto
specify a pointcut expression using AspectJ’s @Pointcut annotation or by using AspectJ’s @Before,
@After,andsoon,annotationsthatspecifytheadvicetype.
Pointcut expressions use pointcut designators, like execution, args, within, this, and so on, to find
matchingmethodstowhichanadviceisapplied.Forinstance,inexamplelisting9-1,@Beforeannotation
made useofexecution pointcutdesignator tofind methods towhich the LoggingAspect’s log method is
applied.
Let’snowlookathowpointcutexpressionsarespecifiedusing@Pointcutannotation.
IMPORTchapter9/ch09-aop-pointcuts(Thech09-aop-pointcutsprojectshowstheMyBankapplication
thatusesAspectJ’s@Pointcutannotationtospecifyapointcutexpression.Toruntheapplication,execute
themainmethodoftheBankAppclassofthisproject)
@Pointcutannotation
@Pointcut annotation’s value attribute specifies the pointcut expression. To use @Pointcut annotation,
createanemptymethodandannotateitwith@Pointcutannotation.Theemptymethodmustbedefinedto
returnvoid.Anadvicethatreferstothenameofthe@Pointcutannotatedmethodisappliedtothemethods
matchedbythepointcutexpressionspecifiedbythe@Pointcutannotation.
NOTEUsing@Pointcutannotationisparticularlyusefulif apointcutexpressionis shared bymultiple
advicesinthesameordifferentaspects.
The following example listing shows a modified version of LoggingAspect (refer example listing 9-1)
classthatuses@Pointcutannotation:
Examplelisting9-6–LoggingAspectclass
Project–ch09-aop-pointcuts
Sourcelocation-src/main/java/sample/spring/chapter09/bankapp/aspects
packagesample.spring.chapter09.bankapp.aspects;
importorg.aspectj.lang.annotation.Before;
importorg.aspectj.lang.annotation.Pointcut;
@Aspect
@Component
publicclassLoggingAspect{
@Pointcut(value="execution(*sample.spring.chapter09.bankapp.service.*Service.*(..))")
privatevoidinvokeServiceMethods(){}
@Before(value="invokeServiceMethods()")
publicvoidlog(JoinPointjoinPoint){
logger.info("Entering"+joinPoint.getTarget().getClass().getSimpleName()+"'s"
+joinPoint.getSignature().getName());
.....
}
}
Intheaboveexamplelisting,theinvokeServiceMethodsmethodisannotatedwith@Pointcutannotation,
and@Beforeannotation’svalueattributereferstotheinvokeServiceMethodsmethod.Thismeansthatthe
log method is applied to the methods that match the pointcut expression specified by the @Pointcut
annotationontheinvokeServiceMethodsmethod.
Astheexecutionandargspointcutdesignatorsaremostlyusedwhenspecifyingpointcutexpressions,let’s
lookatexecutionandargspointcutdesignatorsindetail.
executionandargspointcutdesignators
Theexecutionpointcutdesignatorhasthefollowingformat:
execution(<access-modifier-pattern><return-type-pattern> <declaring-type-pattern><method-
name-pattern>(<method-param-pattern>)<throws-pattern>)
If you compare an execution expression to a method declaration, you’ll notice that an execution
expressionissimilartoamethoddeclaration.
Figure9-2Differentpartsofanexecutionexpressionmaptodifferentpartsofamethoddeclaration.
Figure9-2showshowthedifferentpartsofanexecutionexpressionmaptoamethoddeclaration:
Spring AOP framework matches different parts of an execution expression with different parts of a
methoddeclaration(asshownabove)tofindthemethodstowhichanadviceisapplied.The<declaring-
type-pattern>isnotshownintheabovefigurebecause<declaring-type-pattern>isonlyusedwhenyou
wanttorefertomethodscontainedinaparticulartypeorpackage.
Thefollowingtabledescribesdifferentpartsofanexecutionexpression:
Expressionpart Description
access-modifier-pattern
Specifiestheaccessmodifierofthetargetmethod.InSpringAOP,theonlyvaluethatcan
be specified for this expression part is public. This part of execution expression is
optional.
return-type-pattern Specifiesthefully-qualifiednameofthereturntypeofthetarget method.A valueof*
meansthatthereturntypeofamethoddoesn’tmatter.
declaring-type-pattern Specifiesthefully-qualifiednameofthetypethatcontainsthetargetmethod.Thispart
of execution expression is optional. A value of * means that all types (classes and
interfaces)intheapplicationareconsideredbythepointcutexpression.
method-name-pattern Specifies the method name pattern. For instance, a value of save* means that the
methodswhosenamesbeginwithsavearetargetofadvice.
method-param-pattern Specifies themethodparameter pattern. Ifthevalueis (..),itmeans target method can
containanynumberofargumentsornoargumentsatall.
throws-pattern Specifies the exception(s) thrown by the target method. This part of execution
expressionisoptional.
The args pointcut designator specifies the arguments that must be accepted by the target method at
runtime. For instance, if you want pointcut expression to locate methods that accept an instance of
java.util.List at runtime, then the args expression looks like: args(java.util.List). Later in this section,
we’ll see how args pointcut designator can be used to make arguments passed to the target method
availabletoanadvice.
Let’snowlookatsomepointcutexpressionsthatuseexecutionandargspointcutdesignators:
Example1
Figure9-3executionexpressionthatusesamethodnamepattern
The methods matched by the above pointcut expression are the methods whose names start with
createFixed.Thereturntypeisspecifiedas*,whichmeansthetargetmethodmayreturnanytype.The(..)
specifiesthatthetargetmethodmayacceptzeroormorearguments.
Example2
Figure9-4executionexpressionthatspecifiesthetype(classorinterface)containingthetargetmethod(s)
ThemethodsmatchedbytheabovepointcutexpressionarethemethodsdefinedbytheMyServicetypein
samplepackage.
Example3
Figure9-5executionexpressionthatspecifiesanexceptionpatternforthemethod
The methods matched bythe abovepointcut expressionare the methodsof sample.MyService type that
specifyathrowsclause.
Example4
Figure9-6argspointcutdesignatorspecifiestheobjectinstancepassedtothetargetmethod
Intheabovepointcutexpression,combinationsofexecutionandargspointcutdesignatorshavebeenused.
Youcancombinepointcutdesignatorsusing&&and||operatorstocreatecomplexpointcutexpressions.
Themethodsmatchedbytheabovepointcutexpressionarethemethodsdefinedinsample.MyServicetype
thatacceptaninstanceofSomeObjectatruntime.The&&intheabovepointcutexpressionspecifiesthat
thetargetmethodmustmatchtheexpressionsspecifiedbytheexecutionandargspointcutdesignators.
If you want an advice to have access to one or more method arguments passed to the target method,
specifynamesofthemethodargumentsintheargsexpression,asshownhere:
Figure9-7argspointcutdesignatorspecifiesthetargetmethod’sargument(s)thatmustbemadeavailable
totheadvice
Intheabovepointcutexpression,argsexpressionspecifiesthatthetargetmethodmustacceptanargument
oftypeSomeObject,andthatargumentisavailabletoadviceviaxyzparameter.Let’ssee,arealexample
thatmakesuseofthisfeaturetopassargumentstotheadvice.
Passingtargetmethod’sargumentstoanadvice
The following example listing shows a modified version of LoggingAspect in which log method is
executedonlyifthemethodargumentpassedtothetargetmethodisaninstanceofFixedDepositDetails,
andthatFixedDepositDetailsinstanceisalsomadeavailabletothelogmethod:
Examplelisting9-7–LoggingAspectclass–passingtargetmethod’sargumentstoanadvice
importorg.aspectj.lang.annotation.Before;
importorg.aspectj.lang.annotation.Pointcut;
@Aspect
@Component
publicclassLoggingAspect{
.....
@Pointcut(value=
"execution(*sample.spring.chapter09.bankapp.service.*Service.*(..))
&&args(FixedDepositDetails)")
privatevoidinvokeServiceMethods(FixedDepositDetailsFixedDepositDetails){
}
@Before(value="invokeServiceMethods(FixedDepositDetails)")
publicvoidlog(JoinPointjoinPoint,FixedDepositDetailsFixedDepositDetails){
.....
}
}
Intheaboveexamplelisting,theargsexpressionspecifiesthattheFixedDepositDetailsinstancepassedto
thetargetmethodisavailabletologmethod(anadvice)viaFixedDepositDetailsparameter.Astheargs
expressionprovideslogmethodwithaninstanceofFixedDepositDetailsobject,thelogmethodhasbeen
modifiedtoacceptanadditionalargumentoftypeFixedDepositDetails.
Pointcutdesignators,likeexecution,args,within,this,target,andsoon,aredefinedbyAspectJ.Spring
AOPdefinesabeanpointcutdesignatorthatisspecifictoSpringAOPframework.Let’stakeaquicklook
atbeanpointcutdesignator.
beanpointcutdesignator
Thebeanpointcutdesignatorisforlimitingthetargetmethodstothespecifiedbeanid(orname).Youcan
specify the exact bean id or name, or you can specify a pattern. Let’s look at a few examples of bean
pointcutdesignator:
Example1
Figure9-8beanpointcutdesignatorspecifiesthebeanidornamewhosemethodsaretargetoftheadvice
The methods matched by the above pointcut expression are the methods defined by the bean named
someBean.
Example2
Figure9-9beanpointcutdesignatorspecifiesthatanadviceisappliedtothemethodsofthe
beanswhoseidornamebeginwithsomeBean.
In the above pointcut expression, bean pointcut designator specifies that an advice is applied to the
methodsofthebeanswhoseidornamebeginwithsomeBean.
NOTELikeanyotherpointcutdesignator,youcancombinebeanpointcutdesignatorwithotherpointcut
designatorsusing&&and||operatorstoformcomplexpointcutexpressions.
Let’snowlookatpointcutdesignatorsthatperformmatchingbasedonannotations.
Annotations-basedpointcutdesignators
AspectJalsoprovidespointcutdesignators,like@annotation,@target,@withinand@argsthatyoucan
usewithSpringAOPtofindtargetmethods.Let’slookatcoupleofexamplesthatshowusageofthese
pointcutdesignators:
Example1
Figure9-10@annotationpointcutdesignatorspecifiesthatanadviceisappliedtothemethodsannotated
withSpring’sCacheableannotation
The methods matched by the above pointcut expression are the methods annotated with Spring’s
@Cacheableannotation.
Example2
Figure 9-11 @target pointcut designator specifies that advice is applied to the methods of objects
annotatedwithSpring’s@Componentannotation
Themethodsmatchedbytheabovepointcutexpressionarethemethodscontainedinanobjectannotated
withSpring’s@Componentannotation.
Inthissection,welookedatsomeofthepointcutdesignatorsdefinedbyAspectJ.Itisimportanttonote
thatnotallpointcutdesignatorsdefinedbyAspectJaresupportedbySpringAOPframework.Ifyouuse
an unsupported pointcut designator in pointcut expressions, Spring AOP framework throws a
java.lang.IllegalArgumentException. For instance, if you use call, set and get pointcut designators in
pointcutexpressions,SpringAOPwillthrowjava.lang.IllegalArgumentException.
Let’snowlookatdifferentadvicetypesandhowtocreatethem.
9-5Advicetypes
Sofar inthis chapter,we’ve seenexamples of before advice type. A beforeadvice typeis createdby
annotating a method of an aspect with @Before annotation (refer listing 9-1, 9-6 and 9-7). The other
advicetypesthatyoucancreateareafter,afterreturning,afterthrowing,afterandaround.
IMPORTchapter9/ch09-aop-advices (The ch09-aop-advices project shows the MyBank application
thatusesdifferentadvicetypes.Toruntheapplication,executethemainmethodoftheBankAppclassof
thisproject)
Let’snowlookatsalientfeaturesofvariousadvicetypes,andhowtocreatethem.
Beforeadvice
Abefore advice is executed before the target method is executed. If a before advice doesn’t throw an
exception, the target method will always be invoked. You can control whether the target method is
executed or not, by using an around advice (explained later in this section). As discussed earlier,
AspectJ’s@Beforeannotationisusedtoindicatethatanadviceisabeforeadvice.
@BeforeannotatedmethodmaydefineitsfirstargumenttobeoftypeJoinPoint.YoucanusetheJoinPoint
argument inside the advice to retrieve information about the target method. For instance, listing 9-1
showed that the JoinPoint instance can be used to obtain the class name of the target object and the
argumentspassedtothetargetmethod.
Afterreturningadvice
An after returning advice is executed after the target method returns. You should note that an after
returningadviceisnotexecutedifthetargetmethodthrowsanexception.Anafterreturningadviceis
annotated with AspectJ’s @AfterReturning annotation. An afterreturning advice can access the value
returnedbythetargetmethod,andmodifyitbeforeitisreturnedtothecallingobject.
TheSampleAspectclassofch09-aop-advicesprojectrepresentsanAOPaspect.Thefollowingexample
listingshowsthattheSampleAspectclassdefinesanafterreturningadvicethatprintsthevaluereturned
byBankAccountService’screateBankAccountmethod:
Examplelisting9-8–SampleAspectclass–afterreturningadvice
Project–ch09-aop-advices
Sourcelocation-src/main/java/sample/spring/chapter09/bankapp/aspects
packagesample.spring.chapter09.bankapp.aspects;
importorg.aspectj.lang.annotation.AfterReturning;
.....
@Aspect
publicclassSampleAspect{
privateLoggerlogger=Logger.getLogger(SampleAspect.class);
@Pointcut(value="execution(*sample.spring..BankAccountService.createBankAccount(..))")
privatevoidcreateBankAccountMethod(){}
@AfterReturning(value="createBankAccountMethod()",returning="aValue")
publicvoidafterReturningAdvice(JoinPointjoinPoint,intaValue){
logger.info("Valuereturnedby"+joinPoint.getSignature().getName()
+"methodis"+aValue);
}
.....
}
In the above example listing, afterReturningAdvice method represents an after returning advice. The
pointcutexpressionspecifiedbythe@PointcutannotationlimitsthejoinpointtoBankAccountService’s
createBankAccountmethod.The..intheexecutionexpressionspecifiesthatthesample.springpackage
anditssub-packagesaresearchedtofindtheBankAccountServicetype.
Inexamplelisting9-8,SampleAspect’safterReturningAdvicemethodisinvokedaftertheinvocationof
BankAccountService’screateBankAccountmethod.Thereturningattributeof@AfterReturningannotation
specifiesthenamewithwhichthereturnvalueofthetargetmethodisavailabletotheadvice.Intheabove
example listing, the value returned by the createBankAccount method is made available to the
afterReturningAdvicemethodviaaValueargument.ThetypeoftheaValueargumenthasbeenspecifiedas
intbecausethecreateBankAccountmethodreturns an int value. You should note thatif you specify the
returning attribute, the advice is applied only to methods that return the specified type. If an after
returningadviceisappliedtomethodsthatreturndifferentvaluetypes(includingvoid),youcanspecify
argumenttypeofthereturnedvalueasObject.
Asshowninexamplelisting9-8,a@AfterReturningannotatedmethodmaydefineitsfirstargumenttobe
oftypeJoinPointtoaccesstargetmethodinformation.
Afterthrowingadvice
Anafterthrowing advice is executed when the target method throws an exception. An after throwing
advicecanaccesstheexceptionthrownbythetargetmethod.Anafterthrowingadviceisannotatedwith
AspectJ’s@AfterThrowingannotation.
The following example listing shows an after throwing advice that is executed when an exception is
thrownbytargetmethods:
Examplelisting9-9–SampleAspectclass–afterthrowingadvice
Project–ch09-aop-advices
Sourcelocation-src/main/java/sample/spring/chapter09/bankapp/aspects
packagesample.spring.chapter09.bankapp.aspects;
importorg.aspectj.lang.annotation.AfterThrowing;
.....
@Aspect
publicclassSampleAspect{
privateLoggerlogger=Logger.getLogger(SampleAspect.class);
.....
@Pointcut(value="execution(*sample.spring..FixedDepositService.*(..))")
privatevoidexceptionMethods(){}
.....
@AfterThrowing(value="exceptionMethods()",throwing="exception")
publicvoidafterThrowingAdvice(JoinPointjoinPoint,Throwableexception){
logger.info("Exceptionthrownby"+joinPoint.getSignature().getName()
+"Exceptiontypeis:"+exception);
}
}
Intheaboveexamplelisting,SampleAspect’safterThrowingAdvicemethodrepresentsanafterthrowing
advice. The afterThrowingAdvice method is executed when an exception is thrown by any of the
FixedDepositService object’s methods. In the above example listing, the throwing attribute of
@AfterThrowingannotationspecifiesthenamewithwhichtheexceptionthrownbythetargetmethodis
madeavailabletotheafterThrowingAdvice method.As the throwingattribute’svalue is exception, the
exceptionispassed totheafterThrowingAdvicemethodvia argumentnamedexception. Notice thatthe
type of the exception argument is java.lang.Throwable, which means that the afterThrowingAdvice
method is executed for all exceptions thrown by the target method. If you want afterThrowingAdvice
methodisexecutedonlywhenaspecificexceptiontypeisthrownbythetargetmethod,changethetypeof
theexceptionargument.Forinstance,ifyouwanttheafterThrowingAdvicemethodisexecutedonlywhen
the target method throws java.lang.IllegalStateException, specify java.lang.IllegalStateException as the
typeoftheexceptionargument.
Asshowninexamplelisting9-9,@AfterThrowingannotatedmethodmaydefineitsfirstargumenttobeof
typeJoinPointtoaccesstargetmethodinformation.
Afteradvice
Anafteradviceisexecutedafterthetargetmethodisexecuted,irrespectiveofwhetherthetargetmethod
completes normally or throws an exception. An after advice is annotated with AspectJ’s @After
annotation.
The following example listing shows an after advice that is executed for BankAccountService’s
createBankAccountmethod,andforthemethodsdefinedbytheFixedDepositServiceinterface:
Examplelisting9-10–SampleAspectclass–afteradvice
Project–ch09-aop-advices
Sourcelocation-src/main/java/sample/spring/chapter09/bankapp/aspects
packagesample.spring.chapter09.bankapp.aspects;
importorg.aspectj.lang.annotation.After;
.....
@Aspect
publicclassSampleAspect{
privateLoggerlogger=Logger.getLogger(SampleAspect.class);
@Pointcut(value="execution(*sample.spring..BankAccountService.createBankAccount(..))")
privatevoidcreateBankAccountMethod(){}
@Pointcut(value="execution(*sample.spring..FixedDepositService.*(..))")
privatevoidexceptionMethods(){}
.....
@After(value="exceptionMethods()||createBankAccountMethod()")
publicvoidafterAdvice(JoinPointjoinPoint){
logger.info("Afteradviceexecutedfor"+joinPoint.getSignature().getName());
}
}
In the above example listing, SampleAspect’s afterAdvice method represents an after advice. The
afterAdvicemethodisexecutedafterthetargetmethodisexecuted.Noticethatthe@Afterannotation’s
value attribute uses || operator to combine pointcut expressions represented by the
createBankAccountMethodandexceptionMethodsmethodstoformanewpointcutexpression.
Asshowninexamplelisting9-10,@Afterannotatedmethodmaydefineitsfirstargumenttobeoftype
JoinPoint,toaccesstargetmethodinformation.
Aroundadvice
An around advice is executed both before and after the execution of the target method. Unlike other
advices,anaroundadvicecancontrolwhetherthetargetmethodisexecutedornot.Anaroundadviceis
annotatedwithAspectJ’s@Aroundannotation.
The following example listing shows an around advice defined by SampleAspect class of ch09-aop-
advicesproject:
Examplelisting9-11–SampleAspectclass–aroundadvice
Project–ch09-aop-advices
Sourcelocation-src/main/java/sample/spring/chapter09/bankapp/aspects
packagesample.spring.chapter09.bankapp.aspects;
importorg.aspectj.lang.ProceedingJoinPoint;
importorg.aspectj.lang.annotation.Around;
importorg.springframework.util.StopWatch;
.....
@Aspect
publicclassSampleAspect{
.....
@Around(value="execution(*sample.spring..*Service.*(..))")
publicObjectaroundAdvice(ProceedingJoinPointpjp){
Objectobj=null;
StopWatchwatch=newStopWatch();
watch.start();
try{
obj=pjp.proceed();
}catch(Throwablethrowable){
//--performanyactionthatyouwant
}
watch.stop();
logger.info(watch.prettyPrint());
returnobj;
}
}
In the above example listing, the aroundAdvice method represents an around advice. The
ProceedingJoinPointargumenttothearoundAdvicemethodismeantforcontrollingtheinvocationofthe
targetmethod.ItisimportanttonotethatProceedingJoinPointargumentmustbethefirstargumentpassed
to an around advice. When you invoke ProceedingJoinPoint’s proceed method, the target method is
invoked.Thismeansthatifyoudon’tinvoketheProceedingJoinPoint’sproceedmethod,thetargetmethod
isnotinvoked.IfyoupassanObject[]totheproceedmethod,thevaluescontainedintheObject[]are
passedasargumentstothetargetmethod.Ifanaroundadvicechoosesnottoinvokethetargetmethod,the
aroundadvicemayitselfreturnavalue.
As the target method is invoked only when you call ProceedingJoinPoint’s proceed method, around
adviceallowsyoutoperformactionsbeforeandaftertheinvocationofthetargetmethod,andtoshare
information between these action. In example listing 9-11, the aroundAdvice method records the time
taken for the target method to execute. The aroundAdvice method starts a stop watch (represented by
Spring’s StopWatch object) before calling ProceedingJoinPoint’s proceed method, and stops the stop
watchaftercallingProceedingJoinPoint’sproceedmethod.StopWatch’sprettyPrintmethodisthenusedto
printthetimetakenbythetargetmethodtoexecute.
If you want to modify the value returned by the target method, cast the returned value of
ProceedingJoinPoint’s proceed method to the return type of the target method and modify it. A calling
method sees the value returned by the around advice; therefore, you must define the return type of an
advicemethodasObjectorthetypethatisreturnedbythetargetmethod.Anadvicemethodhastheoption
toreturnthevaluereturnedby thetargetmethod, ortoreturnadifferentvaluealtogether.Forinstance,
insteadofinvokingthetargetmethod,anaroundadvicemayinspecttheargument(s)beingpassedtothe
targetmethodandreturnavaluefromthecacheifacacheentryexistsforthesamesetofarguments.
SofarwehavelookedatexamplesthatshowedhowtouseAspectJannotation-styletocreateaspects.
Let’snowlookathowtousearegularSpringbeanasanAOPaspect.
9-6SpringAOP-XMLschema-style
In XML schema-style, a regular Spring bean acts as an aspect. A method defined in an aspect is
associatedwithanadvicetypeandapointcutexpressionusingSpring’saopschema.
IMPORT chapter 9/ch09-aop-xml-schema (The ch09-aop-xml-schema project is same as ch09-aop-
advices project, except that ch09-aop-xml-schema’s SampleAspect class is a simple Java class that
doesn’tuseAspectJ’sannotations)
The following example listing shows the SampleAspect class of ch09-aop-xml-schema project that
definesadvices:
Examplelisting9-12–SampleAspectclass
Project–ch09-aop-xml-schema
Sourcelocation-src/main/java/sample/spring/chapter09/bankapp/aspects
packagesample.spring.chapter09.bankapp.aspects;
.....
publicclassSampleAspect{
.....
publicvoidafterReturningAdvice(JoinPointjoinPoint,intaValue){
logger.info("Valuereturnedby"+joinPoint.getSignature().getName()+"methodis"+aValue);
}
publicvoidafterThrowingAdvice(JoinPointjoinPoint,Throwableexception){
logger.info("Exceptionthrownby"+joinPoint.getSignature().getName()
+"Exceptiontypeis:"+exception);
}
.....
}
The above example listing shows that the SampleAspect class defines methods that represent AOP
advices.NoticethattheSampleAspectclassisnotannotatedwith@Aspectannotationandthemethods
arenotannotatedwith@After,@AfterReturning,andsoon,annotations.
Let’snowlookat how <config>elementofSpring’s aopschema is usedtoconfigure aregular Spring
beanasanAOPaspect.
ConfiguringanAOPaspect
InXMLschema-style,AOP-specificconfigurationsareenclosedwithin<config>elementofSpring’saop
schema.And,anAOPaspectisconfiguredusing<aspect>sub-elementof<config>element.
The following example listing shows how the SampleAspect class is configured using <aspect> sub-
elementof<config>element:
Examplelisting9-13–applicationContext.xml–Spring’saopschemausage
Project–ch09-aop-xml-schema
Sourcelocation-src/main/resources/META-INF/spring
<beans.....xmlns:aop="http://www.springframework.org/schema/aop".....>
.....
<beanid="sampleAspect"
class="sample.spring.chapter09.bankapp.aspects.SampleAspect"/>
<aop:configproxy-target-class="false"expose-proxy="true">
<aop:aspectid="sampleAspect"ref="sampleAspect">
.....
</aop:aspect>
</aop:config>
</beans>
As the <config> element relies on autoproxying, the <config> element defines proxy-target-class and
expose-proxy attributes. If you remember, the same attributes were defined by <aspectj-autoproxy>
elementof Spring’s aopschema. Refer section 9-3to knowmore about proxy-target-class and expose-
proxyattributes.
In example listing 9-13, the sampleAspect bean definition defines SampleAspect class as a bean. The
<aspect> element configures the sampleAspect bean as an AOP aspect. The <aspect> element’s id
attributespecifiesauniqueidentifierforanaspect,andtherefattributespecifiestheSpringbeanthatyou
wanttoconfigureasanAOPaspect.
Now,thatwehaveconfiguredanAOPaspect,let’slookathowtomapmethodsdefinedinanAOPaspect
todifferentadvicetypesandpointcutexpressions.
Configuringanadvice
You configure an advice using one of the following sub-elements of <aspect> element: <before> (for
configuring a before advice type), <after-returning> (for configuring an after returning advice type),
<after-throwing>(forconfiguringanafterthrowingadvicetype),<after>(forconfiguringanafteradvice
type)and<around>(forconfiguringanaroundadvicetype).
Let’snowlookathowtheadvicesdefinedintheSampleAspectclassofch09-aop-xml-schemaproject
areconfiguredintheapplicationcontextXMLfile.
Configuringanafterreturningadvice
The following figure shows how the SampleAspect’s afterReturningAdvice method is configured as an
afterreturningadviceusing<after-returning>element:
Figure 9-12 afterReturningAdvice method of SampleAspect class is configured as an after returning
adviceusing<after-returning>elementofSpring’saopschema
The <after-returning> element’s method attribute specifies the name of the method which you want to
configure as an after returning advice. The returning attribute serves the same purpose as the
@AfterReturning annotation’s returning attribute; it makes the returned value from the target method
available to the advice. The pointcut attribute specifies the pointcut expression used for finding the
methodstowhichtheadviceisapplied.
Configuringanafterthrowingadvice
The following figure shows how the SampleAspect’safterThrowingAdvice method is configured as an
afterthrowingadviceusing<after-throwing>element:
Figure 9-13 afterThrowingAdvice method of SampleAspect class is configured as an after throwing
adviceusing<after-throwing>elementofSpring’saopschema
The <after-throwing> element’s method attribute specifies the name of the method which you want to
configure as an after throwing advice. The throwing attribute serves the same purpose as the
@AfterThrowing annotation’s throwing attribute; it makes the exception thrown by the target method
available to the advice. The pointcut attribute specifies the pointcut expression used for finding the
methodstowhichtheadviceisapplied.
Theotheradvicetypes(before,afterandaround)areconfiguredthesamewayastheafterreturningand
afterthrowingadvicesthatwejustsaw.
Let’snowlookatdifferentwaysinwhichyoucanassociateapointcutexpressionwithanadvice.
Associatingapointcutexpressionwithanadvice
The <after>, <after-returning>, <after-throwing>, <before> and <around> elements of Spring’s aop
schemadefineapointcutattributethatyoucanusetospecifythepointcutexpressionassociatedwiththe
advice.Ifyouwanttosharepointcutexpressionsbetweendifferentadvices,youcanusethe<pointcut>
sub-elementofthe<config>elementtodefinepointcutexpressions.
The following example listing shows that the <pointcut> element is used for defining pointcut
expressions:
Examplelisting9-14–applicationcontextXML-<pointcut>element
<beans.....xmlns:aop="http://www.springframework.org/schema/aop".....>
.....
<beanid="sampleAspect"
class="sample.spring.chapter09.bankapp.aspects.SampleAspect"/>
<aop:configproxy-target-class="false"expose-proxy="true">
<aop:pointcutexpression="execution(*sample.spring..*Service.*(..))"id="services"/>
<aop:aspectid="sampleAspect"ref="sampleAspect">
<aop:aftermethod="afterAdvice"pointcut-ref="services"/>
<aop:aroundmethod="aroundAdvice"pointcut-ref="services"/>
</aop:aspect>
</aop:config>
</beans>
In the above example listing, the <pointcut> element specifies a pointcut expression. The expression
attributespecifiesthepointcutexpression,andtheidattributespecifiesauniqueidentifierforthepointcut
expression. The pointcut expression defined by a <pointcut> element is referenced by <after>, <after-
returning>, and so on, advice type elements using pointcut-ref attribute. For instance, in the above
examplelisting,<after>and<around>elementsusepointcut-refattributetorefertotheservicespointcut
expressions.
9-7Summary
Inthis chapter, welookedatAOPconceptsandhowSpring AOPcanbeused toaddresscross-cutting
concernsinSpringapplications.WesawhowtocreateaspectsusingAspectJannotation-styleandXML
schema-style.Wealsodiscussedhowtocreateandconfiguredifferentadvicetypes.Wetoucheduponthe
pointcut expressions that you can create to find matching methods in the application. For a more
comprehensive coverage of Spring AOP please refer to Spring reference documentation. In the next
chapter, we’ll look at how to develop web applications using Spring Web MVC module of Spring
Framework.
Chapter10–SpringWebMVCbasics
10-1Introduction
The Spring Web MVC module of Spring Framework provides an MVC (Model-View-Controller)
frameworkthatyoucanusefordevelopingservlet-basedwebapplications.SpringWebMVCisanon-
intrusiveframeworkthatprovidesaclearseparationofconcernsbetweenapplicationobjectsthatform
theweblayer.Forinstance,acontrollerobjectisusedforprocessingtherequest,avalidatorobjectis
used for performing validation, and a command object is used for storing form data, and so on. It is
important to note that none of these application objects implement or extend from any Spring-specific
interfaceorclass.
In this chapter, we’ll first look at the directory structure that will be followed by all the sample web
projectsdiscussedinthischapter.We’llthenlookatasimple‘HelloWorld’webapplicationdeveloped
usingSpringWebMVC.Intherestofthischapter,we’lllookatsomeoftheSpringWebMVCannotations
inthecontextofourMyBankwebapplication.Thischaptersetsthestagefordiscussingmoreadvanced
SpringWebMVCfeaturesinthenextchapter.
IMPORTchapter10/ch10-helloworld(Thisprojectshowsasimple‘HelloWorld’webapplicationthat
usesSpringWebMVC.ReferappendixAtolearnhowtodeploysamplewebprojectsonTomcatserver.
Once you have deployed the application, go to the following URL: http://localhost:8080/ch10-
helloworld/helloworld/sayhello. If the application is deployed successfully, it will show you ‘Hello
World!!’message.)
10-2Directorystructureofsamplewebprojects
Figure10-1describestheimportantdirectoriesofch10-helloworldwebproject.Someoftheimportant
pointsthatyouneedtorememberare:
§Thesrc/main/resources/META-INF/springfoldercontainstherootwebapplication context XML
filethatdefinesbeansthataresharedbyalltheservletsandfiltersofthewebapplication.Theroot
web application context XML file typically defines data sources, services, DAOs, transaction
managers, and so on. The root web application context XML file is loaded by Spring’s
ContextLoaderListener (ajavax.servlet.ServletContextListener implementation). Refer section 10-
10tolearnabouthowContextLoaderListenerisconfiguredinweb.xmlfile.
§Thesrc/main/webapp/WEB-INF/springfoldercontainsthewebapplicationcontextXMLfilethat
definesbeansthatformpartoftheweblayeroftheapplication.ThewebapplicationcontextXML
filetypicallydefinescontrollers(alsoreferredtoashandlers),handlermappings,viewresolvers,
exceptionresolvers,andsoon.We’lllearnabouttheseobjectslaterinthischapter.
§ThebeansdefinedintherootwebapplicationcontextXMLfileareavailabletothebeansdefined
inthewebapplicationcontextXMLfile.Thismeans,abeandefinedinthewebapplicationcontext
XMLfilecanbedependentonabeandefinedintherootwebapplicationcontextXMLfile,butnot
theotherwayround.
Figure10-1Directorystructureofch10-helloworldproject
Let’snowlookattheconfigurationfilesandtheclassesthatformthech10-helloworldproject.
10-3Understandingthe‘HelloWorld’webapplication
Ifyouright-clickonthech10-helloworldprojectinyourEclipseIDEandselectBuildPathàConfigure
Build Path option, you’ll notice that the project depends on spring-beans, spring-context, spring-core,
spring-expression,spring-webandspring-webmvcJARfiles.TheseJARfilesarerequiredforbuildinga
basicSpringWebMVCapplication.
Thefollowingtable describestheconfigurationfilesand the Javasourcefiles thatconstitute thech10-
helloworldproject.Laterinthissection,we’lltakeacloserlookatthesefilesandclasses.
Configuration file or Java
sourcefile Description
HelloWorldController.java
SpringWebMVCcontrollerthatisresponsibleforrequesthandling.
You’ll find this file inside sample.spring.chapter10.web package of src/main/java
folder.
helloworld.jsp JSPfilethatshowsthe‘HelloWorld!!’message
You’llfindthisfileinsidesrc/main/webapp/WEB-INF/jspfolder
myapp-config.xml
Web application context XM L file that contains bean definitions for controllers,
handlermappings,andsoon.
You’llfindthisfileinsidesrc/main/webapp/WEB-INF/springfolder
web.xml Webapplicationdeploymentdescriptor
You’llfindthisfileinsidesrc/main/webapp/WEB-INFfolder
Apartfromthefilesshownintheabovetable,thech10-helloworldprojectalsocontainslog4j.properties
file that contains Log4j configuration, and pom.xml file that goes as input to the maven build tool. To
know more about these files refer to Log4j (http://logging.apache.org/log4j/1.2/) and Maven
(http://maven.apache.org/index.html)documentation.
Let’snowtakeacloserlookateachofthefilesdescribedintheabovetable.
HelloWorldController.java–HelloWorldwebapplication’scontrollerclass
In Spring Web MVC applications, the request handling logic is contained in controller classes. The
followingexamplelistingshowstheHelloWorldControllercontrollerclassofch10-helloworldproject:
Examplelisting10-1–HelloWorldControllerclass
Project–ch10-helloworld
Sourcelocation-src/main/java/sample/spring/chapter10/web
packagesample.spring.chapter10.web;
importorg.springframework.web.servlet.ModelAndView;
importorg.springframework.web.servlet.mvc.Controller;
.....
publicclassHelloWorldControllerimplementsController{
@Override
publicModelAndViewhandleRequest(HttpServletRequestrequest,
HttpServletResponseresponse)throwsException{
Map<String,String>modelData=newHashMap<String,String>();
modelData.put("msg","HelloWorld!!");
returnnewModelAndView("helloworld",modelData);
}
}
The above example listing shows that the HelloWorldController class implements Spring’s
Controller interface. The Controller interface defines a handleRequest method, which you need to
implement to provide the request handling logic. The handleRequest method returns a ModelAndView
objectthatcontainsthefollowinginformation:
§thedata(referredtoasmodeldata)tobeshowntotheuser,and
§logicalnameoftheJSPpage(referredtoasview)thatshowsthemodeldata
Themodeldataisusuallyrepresentedasajava.util.Maptypeobject,andeachentryinthejava.util.Map
object represents a modelattribute. The name of the view (the JSP page) to be shown to the user is
specifiedasaStringvalue.
Example listing 10-1 shows that the HelloWorldController’s handleRequest method returns a
ModelAndView object that contains helloworld (a String value) as the view name and modelData (a
java.util.Maptypeobject)asthemodeldata.ThemodelDatacontainsamsgmodelattributewhosevalue
isthe‘HelloWorld!!’message.We’llsoonseethatthemsgmodelattributeisusedbythehelloworld
view(aJSPpage)toshowthe‘HelloWorld!!’messagetotheusers.
The following diagram summarizes how HelloWorldController’s handleRequest method renders a JSP
page:
Figure10-2SpringWebMVCframeworkinvokestheHelloWorldController’shandleRequestmethodand
usesthereturnedModelAndViewobjecttorenderthehelloworld.jsppage
TheabovefigureshowsthattheSpringWebMVCframeworkinterceptsanincomingHTTPrequestand
invokes the HelloWorldController’s handleRequest method. The handleRequest method returns a
ModelAndView object that contains the model data and the view information. After receiving the
ModelAndViewobjectfromthehandleRequestmethod,theSpringWebMVCframeworkdispatchesthe
HTTPrequesttothehelloworld.jsppageandmakesthemodelattributesavailabletothehelloworld.jsp
pageasrequestattributes.
NOTE Spring Web MVC makes the model attributes available to the view technology (like JSP and
Velocity) ina format that is suitable forthe view technology.For instance, if you are using JSPas the
viewtechnology,modelattributesaremadeavailabletotheJSPpagesasrequestattributes.
helloworld.jsp–JSPpagethatshowsthe‘HelloWorld!!’message
Thefollowingexamplelistingshowsthehelloworld.jsppageofch10-helloworldproject:
Examplelisting10-2–helloworld.jspJSPpage
Project–ch10-helloworld
Sourcelocation-src/main/webapp/WEB-INF/jsp
<%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%>
<c:outvalue="${msg}"/>
Intheaboveexamplelisting,<c:out>printsthevalueofmsgrequestattribute.Themsgrequestattribute
refers to the msg model attribute returned by HelloWorldController’s handleRequest method (refer
examplelisting10-1).Asthevalueofmsgmodelattributeis‘HelloWorld!!’,helloworld.jspJSPpage
shows‘HelloWorld!!’message.
myapp-config.xml–WebapplicationcontextXMLfile
Thefollowingexamplelistingshowsthebeansconfiguredinmyapp-config.xmlfileofch10-helloworld
project:
Examplelisting10-3–myapp-config.xml
Project–ch10-helloworld
Sourcelocation-src/main/webapp/WEB-INF/spring
<beansxmlns="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">
<beanname="helloWorldController"
class="sample.spring.chapter10.web.HelloWorldController"/>
<beanid="handlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<propertyname="urlMap">
<map>
<entrykey="/sayhello"value-ref="helloWorldController"/>
</map>
</property>
</bean>
<beanid="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<propertyname="prefix"value="/WEB-INF/jsp/"/>
<propertyname="suffix"value=".jsp"/>
</bean>
</beans>
The above example listing shows that apart from the HelloWorldController, Spring’s
SimpleUrlHandlerMappingandInternalResourceViewResolverbeansarealsoconfiguredinthemyapp-
config.xmlfile.
SimpleUrlHandlerMapping bean (an implementation of Spring’s HandlerMapping interface) maps an
incomingHTTPrequesttothecontrollerresponsibleforhandlingtherequest.SimpleUrlHandlerMapping
bean uses the URL path to map a request to a controller. The urlMap property (of type java.util.Map)
specifies URL path to controller bean mapping. In example listing 10-3, the "/sayhello" URL path
(specifiedbythekeyattribute)ismappedtotheHelloWorldControllerbean(specifiedbythevalue-ref
attribute).YoushouldnotethattheURLpathspecifiedbythekeyattributeisrelativetotheURLpathto
which Spring’s DispatcherServlet (a servlet) is mapped in the web application deployment descriptor.
DispatcherServletisdiscussedlaterinthissection.
InternalResourceViewResolverbean(animplementationofSpring’sViewResolverinterface)locatesthe
actualview(like,JSPorservlet)basedontheviewnamecontainedintheModelAndViewobject.The
actual view is located by prepending the value of prefix property and appending the value of suffix
propertytotheviewname.Theexamplelisting10-3showsthatthevalueofprefixpropertyis/WEB-
INF/jsp, and the valueofsuffixpropertyis.jsp. As the HelloWorldController’shandleRequest method
returnsaModelAndViewobjectwhichcontainshelloworldastheviewname,theactualviewis/WEB-
INF/jsp/helloworld.jsp(astringthatisobtainedbyprepending/WEB-INF/jspandappending.jsptothe
helloworldviewname).
The following figure shows the role played by SimpleUrlHandlerMapping and
InternalResourceViewResolverbeansinthe‘HelloWorld’webapplication:
Figure 10-3 SimpleUrlHandlerMapping locates the controller to be invoked and
InternalResourceViewResolverresolvestheactualviewbasedontheviewname
SimpleUrlHandlerMapping and InternalResourceViewResolver beans are automatically detected by
Spring Web MVC and used for finding the controller for request handling and resolving views,
respectively.
web.xml–Webapplicationdeploymentdescriptor
In Spring Web MVC based applications, requests are intercepted by a DispatcherServlet (a servlet
providedbySpringWebMVC)thatisresponsiblefordispatchingrequeststotheappropriatecontroller.
The following example listing shows the configuration of DispatcherServlet in web.xml file of ch10-
helloworldproject:
Examplelisting10-4–web.xml
Project–ch10-helloworld
Sourcelocation-src/main/webapp/WEB-INF/spring
<web-appxmlns="java.sun.com/xml/ns/javaee"
xmlns:xsi="w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="java.sun.com/xml/ns/javaeejava.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/myapp-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/helloworld/*</url-pattern>
</servlet-mapping>
</web-app>
A DispatcherServlet is associated with a web application context XML file which is identified by the
contextConfigLocation servlet initialization parameter. In the above example listing, the
contextConfigLocationinitializationparameterreferstothemyapp-config.xmlfile(referexamplelisting
10-3).
If you don’t specify the contextConfigLocation parameter, the DispatcherServlet looks for the web
application context XML file named <name-of-DispatcherServlet>-servlet.xml file in the WEB-INF
directory of the web application. Here, the value of <name-of-DispatcherServlet> is the servlet name
specified by the <servlet-name> sub-element of <servlet> that configures the DispatcherServlet. For
instance, if we had not specified the contextConfigLocation parameter in example listing 10-3, the
DispatcherServletwouldhavelookedforafilenamedhello-servlet.xmlintheWEB-INFdirectory.
TheHandlerMappingandViewResolverbeansdefinedinthewebapplicationcontextXMLfileareused
by the DispatcherServlet for request processing. DispatcherServlet uses the HandlerMapping
implementation for finding the appropriate controller for the request, and uses the ViewResolver
implementationforresolvingtheactualviewbasedontheviewnamereturnedbythecontroller.
Inthecontextof‘HelloWorld’webapplication,thefollowingfiguresummarizestheroleplayedbythe
DispatcherServletservletinrequestprocessing:
Figure10-4DispatcherServletusesHandlerMappingandViewResolverbeansforrequestprocessing.
The above figure shows that the following sequence of activities are performed by Spring Web MVC
duringrequestprocessing:
§requestisfirstinterceptedbytheDispatcherServletservlet
§DispatcherServletusestheHandlerMappingbean(whichisSimpleUrlHandlerMappingbeanincase
of‘HelloWorld’webapplication)tofindanappropriatecontrollerforhandlingtherequest
§ DispatcherServlet calls the request handling method of the controller (which is
HelloWorldController’shandleRequestmethodincaseof‘HelloWorld’webapplication)
§DispatcherServletsendstheviewnamereturnedbythecontrollertotheViewResolverbean(which
isInternalResourceViewResolverbeanincaseof‘HelloWorld’webapplication)tofindtheactual
view(JSPorservlet)toberendered
§ DispatcherServlet dispatches the request to the actual view (JSP or servlet). The model data
returnedbythecontrolleraremadeavailabletotheviewasrequestattributes.
The DispatcherServlet of ‘Hello World’ web application is mapped to /helloworld/* pattern (refer
examplelisting10-4),andSimpleUrlHandlerMappingmaps/sayhelloURLpathtoHelloWorldController
bean (refer example listing 10-3). If you access the URL http://localhost:8080/ch10-
helloworld/helloworld/sayhello, it results in invocation of handleRequest method of
HelloWorldController controller. The following figure shows how Spring Web MVC maps the URL
http://localhost:8080/ch10-helloworld/helloworld/sayhellototheHelloWorldControllercontroller:
Figure10-5HowtheURLpathhttp://localhost:8080/ch10-helloworld/helloworld/sayhelloismappedto
theHelloWorldControllerbySpringWebMVC
Intheabovefigure,the/ch10-helloworldpartoftheURLrepresentsthecontextpathofthe‘HelloWorld’
webapplication,the/helloworldpartoftheURLmapstotheDispatcherServletservlet(referexample
listing 10-4), and the /sayhello part of the URL maps to the HelloWorldController controller (refer
examplelisting10-3).
In this section, we saw how a simple ‘Hello World’ web application is developed using Spring Web
MVC.Let’snowtakeacloserlookattheDispatcherServletservletthatactsafrontcontrollerinaSpring
WebMVCapplication.
10-4DispatcherServlet–thefrontcontroller
Intheprevioussection,wesawthattheDispatcherServletactsasafrontcontrollerthatinteractswiththe
HandlerMapping andViewResolver beans defined in the web application context XML file to process
requests.Inthissection,we’lllookathowDispatcherServletworksbehindthescenes.
Atthetimeofinitialization,aDispatcherServletloadsthecorrespondingwebapplicationcontextXML
file(whichcouldbespecifiedviacontextConfigLocationinitializationparameter,orisnamedas<name-
of-DispatcherServlet>-servlet.xmlfileandplacedintheWEB-INFdirectory),andcreatesaninstanceof
Spring’sWebApplicationContextobject.WebApplicationContextisasub-interfaceofApplicationContext
interface that provides features that are specific to web applications. For instance, beans in the
WebApplicationContext can have additional scopes, like request and session. You can think of
WebApplicationContext object as an object that represents a Spring container instance in Spring Web
MVCapplications.
Thefollowingtabledescribestheadditionalscopesthatyoucanspecifyforbeansconfiguredintheweb
applicationcontextXMLfile:
Beanscope Description
request
SpringcontainercreatesanewbeaninstanceforeveryHTTPrequest.Thebeaninstanceisdestroyed
bytheSpringcontainerwhentheHTTPrequestcompletes.
This scope is valid only for ApplicationContext implementations that are applicable in web
application scenarios. For instance, if you are using XmlWebApplicationContext or
AnnotationConfigWebApplicationContext,onlythenyoucanspecifytherequestscopeforabean.
session
SpringcontainercreatesanewbeaninstancewhenanHTTPSessioniscreated.Thebeaninstanceis
destroyedbytheSpringcontainerwhentheHTTPSessionisdestroyed.
This scope is valid only for ApplicationContext implementations that are applicable in web
application scenarios. For instance, if you are using XmlWebApplicationContext or
AnnotationConfigWebApplicationContext,onlythenyoucanspecifythesessionscopeforabean.
globalS ession Thisscopeisapplicableonlyincaseofportletapplications.
Ifyourwebapplicationconsistsofmultiplemodules,youmaydefineaDispatcherServletforeachofthe
modules in the web.xml file. In such a scenario, each DispatcherServlet has its own web application
contextXMLfilethatcontainsbeans(likecontrollers,viewresolvers,andsoon)specifictothatmodule.
YoushouldnotethatthesebeansarenotsharedbetweenDispatcherServletinstances.Thebeansthatare
sharedbetweenDispatcherServletinstancesaredefinedintherootwebapplicationcontextXMLfile.As
mentionedearlier,therootwebapplicationcontextXMLfiledefinesdatasources,servicesandDAOs,
andsoon,thataretypicallysharedbydifferentmodulesofawebapplication.Refertosection10-10to
learnabouthowtherootwebapplicationcontextXMLfileisloaded.
ThefollowingfigureshowsrelationshipbetweenbeansdefinedbythewebapplicationcontextXMLfile
associatedwithaDispatcherServletandthebeansdefinedbytherootwebapplicationcontextXMLfile:
Figure 10-6 Beans in the root WebApplicationContext are inherited by the WebApplicationContext
instanceassociatedwithaDispatcherServlet
In the above figure, servlet1, servlet2 and servlet3 are the names of DispatcherServlet instances
configured in the web.xml file. And, servlet1-servlet.xml,servlet2-servlet.xml and servlet3-servlet.xml
arewebapplicationcontextXMLfilesthatareloadedbyservlet1,servlet2andservlet3, respectively.
When DispatcherServlet instances are initialized, an instance of WebApplicationContext is created
corresponding to each servlet1-servlet.xml, servlet2-servlet.xml and servlet3-servlet.xml files and
associated with the DispatcherServlet instance. A WebApplicationContext instance is also created
correspondingtotherootwebapplicationcontextXMLfile,root-servlet.xml.Thebeanscontainedinthe
root WebApplicationContext instance are available to all the WebApplicationContext instances
associatedwithDispatcherServlets.
Let’snowlookathowacontrolleroranyotherSpringbeandefinedinawebapplicationcontextXML
filecanaccessServletContextandServletConfigobjects.
AccessingServletContextandServletConfigobjects
In some scenarios, beans defined in the web application context XML file may require access to the
ServletContextorServletConfigobjectassociatedwiththewebapplication.
ServletContextisaServletAPIobjectthatabeancanusetocommunicatewiththeservletcontainer.For
instance,youcanuseittogetandsetcontextattributes,obtaincontextinitializationparameters,andsoon.
If a bean class implements Spring’s ServletContextAware interface (a callback interface), the Spring
containerprovidesthebeaninstancewithaninstanceofServletContextobject.
ServletConfig isaServletAPIobjectthatabeancanusetoobtain configuration informationaboutthe
DispatcherServlet that intercepted the request. For instance, you can use it to obtain initialization
parameterspassedtotheDispatcherServletandthenamewithwhichtheDispatcherServletisconfigured
inweb.xml.IfabeanclassimplementsSpring’sServletConfigAwareinterface(acallbackinterface),the
SpringcontainerprovidesthebeaninstancewithaninstanceofServletConfigobject.
The following example listing shows a bean class that implements ServletContextAware and the
ServletConfigAwareinterface:
Examplelisting10-5–ServletContextAwareandServletConfigAwareusage
importjavax.servlet.ServletConfig;
importjavax.servlet.ServletContext;
importorg.springframework.web.context.ServletConfigAware;
importorg.springframework.web.context.ServletContextAware;
publicclassABeanimplementsServletContextAware,ServletConfigAware{
privateServletContextservletContext;
privateServletConfigservletConfig;
@Override
publicvoidsetServletContext(ServletContextservletContext){
this.servletContext=servletContext;
}
@Override
publicvoidsetServletConfig(ServletConfigservletConfig){
this.servletConfig=servletConfig;
}
publicvoiddoSomething(){
//--useServletContextandServletConfigobjects
}
}
The above example listing shows that the ABean class implements ServletContextAware and
ServletConfigAware interface. The ServletContextAware interface defines a setServletContext method
whichisinvokedbytheSpringcontainertoprovideABeaninstancewithaninstanceofServletContext
object. The ServletConfigAware interface defines a setServletConfig method which is invoked by the
SpringcontainertoprovideABeaninstancewithaninstanceofServletConfigobject.
WesawearlierthatyoucancreateacontrollerbyimplementingtheControllerinterface.Let’snowlook
at@Controllerand@RequestMappingannotationsthatsimplifydevelopingcontrollers.
10-5 Developing controllers using @Controller and
@RequestMappingannotations
Spring Web MVC provides classes, like MultiActionController, UrlFilenameViewController,
AbstractController,andsoon,thatyoucanextendtocreateyourcontrollerimplementation.Ifyouextend
aSpring-specificclassorimplementaSpring-specificinterfacetocreateacontroller,thecontrollerclass
becomes tightly coupled with Spring. Spring 2.5 introduced annotations like @Controller,
@RequestMapping, @ModelAttribute, and so on, that allow you to create controllers with flexible
methodsignatures. In this section,we’ll look at differentSpring Web MVC annotations for developing
annotatedcontrollers.
Let’sfirstlookata‘HelloWorld’webapplicationthatusesanannotatedcontrollertoshowthe‘Hello
World!!’message.
IMPORTchapter 10/ch10-annotation-helloworld (This project shows a simple ‘Hello World’ web
applicationthatusesanannotatedcontrollertoshow‘HelloWorld!!’message.Ifyoudeploytheproject
on Tomcat server and access the URL http://localhost:8080/ch10-annotation-
helloworld/helloworld/saySomething/sayhello,you’llseethe‘HelloWorld!!’message.)
Developinga‘HelloWorld’webapplicationusinganannotatedcontroller
Thech10-annotation-helloworldprojectissimilartoch10-helloworld, except that the ch10-annotation-
helloworld project uses an annotated controller to show ‘Hello World !!’ message. The web.xml and
helloworld.jspfilesinboththeprojectsareexactlythesame,butHelloWorldController.javaandmyapp-
config.xmlfilesaredifferent.Forthisreason,we’llrestrictourdiscussiontoHelloWorldController.java
andmyapp-config.xmlfilesinthissection.
Let’sfirstlookathowtocreateacontrollerusing@Controllerand@RequestMappingannotations.
@Controllerand@RequestMappingannotations
You designate a particular class as a Spring Web MVC controller by annotating it with @Controller
annotation. And, you use @RequestMapping annotation to map an incoming request to the appropriate
methodofacontroller.
The following example listing shows the HelloWorldController class that uses @Controller and
@RequestMappingannotations:
Examplelisting10-6–HelloWorldControllerclass-@Controllerand@RequestMappingusage
packagesample.spring.chapter10.web;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.servlet.ModelAndView;
.....
@Controller(value="sayHelloController")
@RequestMapping("/saySomething")
publicclassHelloWorldController{
@RequestMapping("/sayhello")
publicModelAndViewsayHello(){
Map<String,String>modelData=newHashMap<String,String>();
modelData.put("msg","HelloWorld!!");
returnnewModelAndView("helloworld",modelData);
}
}
In the above example listing, the HelloWorldController class is annotated with @Controller and
@RequestMappingannotations,andthesayHellomethodisannotatedwith@RequestMappingannotation.
@Controllerannotationisaspecializedformof@Componentannotation(referchapter6)thatindicates
thattheHelloWorldControllerisacontrollercomponent.
Like @Service (refer chapter 6) and @Repository (refer chapter 7) annotated classes, @Controller
annotated classes are automatically registered with the Spring container; you don’t need to explicitly
define a @Controller annotated class in the web application context XML file. The value attribute of
@ControllerannotationspecifiesthenamewithwhichtheclassisregisteredwiththeSpringcontainer.
Thevalueattributeservesthesamepurposeasthe<bean>element’sidattribute.Ifthevalueattributeis
not specified,thename (beginning with lowercasefirst letter)of the classis usedtoregister the class
withtheSpringcontainer.
@RequestMappingannotationmapsincomingwebrequeststoappropriatecontrollersand/orcontroller
methods.@RequestMappingannotationatthetype-levelmapsarequesttotheappropriatecontroller.For
instance,@RequestMapping("/saySomething")onHelloWorldControllerclassindicatesthatallrequests
to/saySomethingrequestpatharehandledbytheHelloWorldControllercontroller.
@RequestMapping at the method-level narrows down the @RequestMapping at the type-level to a
specific method in the controller class. For instance, @RequestMapping("/sayhello") annotation on
sayHellomethodinexamplelisting10-6specifiesthatthesayHellomethodisinvokedwhentherequest
pathis/saySomething/sayhello.NoticethattheHelloWorldController’ssayHellomethoddoesn’taccept
anyargumentsandreturnsaModelAndViewobject.Thisispossiblebecauseannotatedcontrollerscan
have flexible method signatures. In section 10-7, we’ll look at possible arguments and return types
@RequestMappingannotatedmethodscandefine.
@RequestMapping annotation at the type-level usually specifies a request path or a path pattern. And,
@RequestMapping annotation at the method-level usually specifies an HTTP method or a request
parametertofurthernarrowdownthemappingspecifiedbythetype-level@RequestMappingannotation.
The following figure shows how http://localhost:8080/ch10-annotation-
helloworld/helloworld/saySomething/sayhello URL will resultin invocationof HelloWorldController’s
sayHellomethodbySpringWebMVC:
Figure10-7HowarequestURLismappedtoanappropriate@RequestMappingannotatedmethodofa
controller
Theabovefigure shows howaparticularrequestURLresults ininvocation ofHelloWorldController’s
sayHellomethod.
Let’snowlookathowannotation-drivendevelopmentofSpringWebMVCcontrollersisenabledinan
application.
EnablingSpringWebMVCannotations
TouseannotatedcontrollersinyourSpringWebMVCapplication,youneedtoenableSpringWebMVC
annotations using <annotation-driven> element of Spring’s mvc schema, as shown in the following
examplelisting:
Examplelisting10-7–myapp-config.xml
Project–ch10-annotation-helloworld
Sourcelocation-src/main/webapp/WEB-INF/spring
<beans.....
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation=".....http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd.....">
<mvc:annotation-driven/>
<context:component-scanbase-package="sample.spring.chapter10.web"/>
<beanid="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<propertyname="prefix"value="/WEB-INF/jsp/"/>
<propertyname="suffix"value=".jsp"/>
</bean>
</beans>
In the aboveexample listing,<mvc:annotation-driven>element ofSpring’s mvc schema enables use of
Spring Web MVC annotations in implementing controllers. Also, <component-scan> element (refer
section6-2formoredetails)ofcontextschemaisusedtoautomaticallyregister@Controllerannotated
classeswiththeSpringcontainer.
Inthissection,wesawhowtodevelopasimple‘HelloWorld’webapplicationusing@Controllerand
@RequestMappingannotations.Let’snowlookattherequirementsoftheMyBankwebapplicationthat
we’lldevelopinthischapterusingSpringWebMVCannotations.
10-6MyBankwebapplication’srequirements
ThefollowingfigureshowsthehomepageofMyBankwebapplicationthatdisplaysalistofcurrently
activefixeddepositsinthesystem:
Figure10-8MyBankwebapplication’shomepageshowsfixeddepositdetails.Thewebpageprovides
theoptiontoclose,editandcreateafixeddeposit.
In the above figure, the ID column shows the unique identifier for a fixed deposit. The ID value is
assignedtoafixeddepositwhenitiscreatedbyauser.CloseandEdithyperlinksallowausertoremove
oreditdetailsofafixeddeposit.TheCreatenewFixedDepositbuttonshowsthe‘Openfixeddeposit’
formforenteringdetailsofthefixeddeposittobeopened,asshowninthefollowingfigure:
Figure10-9‘Openfixeddeposit’formforopeningfixeddeposits.Amount,TenureandEmailfieldsare
mandatory.
Intheabovefigure,clickingtheSavebuttonsavesthefixeddepositdetailsinthedatastore,andGoBack
hyperlinktakestheuserbacktothewebpagethatshowsthefixeddepositlist(referfigure10-8).The
above figure shows that appropriate error messages are displayed if the entered data doesn’t meet the
constraintssetonAmount,TenureandEmailfields.
WhenyouclicktheEdithyperlinkinfigure10-8,aformsimilartofigure10-9isshownformodifying
details of the selected fixed deposit. And, clicking the Close hyperlink in figure 10-8 removes the
selectedfixeddepositfromthelistoffixeddeposits.
Now,thatweknowtheMyBankwebapplicationrequirements,let’slookathowweimplementitusing
SpringWebMVCannotations.
10-7 Spring Web MVC annotations - @RequestMapping and
@RequestParam
Insection10-5,wesawthatwecanuse@Controllerand@RequestMapping annotations todevelop a
simple controller. Inthis section,we’ll take acloser look at @RequestMapping and other Spring Web
MVCannotationsthatsimplifydevelopingannotatedcontrollers.
IMPORTchapter10/ch10-bankapp(This project shows the MyBank web application that allows its
user to manage fixed deposits. If you deploy the project on Tomcat server and access the URL
http://localhost:8080/ch10-bankapp,you’llseethelistoffixeddeposits(asshowninfigure10-8)inthe
system.)
Let’sbeginbylookingatthe@RequestMappingannotation.
Mappingrequeststocontrollersorcontrollermethodsusing@RequestMapping
Insection10-5,wesawthatthe@RequestMapping annotation isused atthetypeandmethod-level to
map requests to controllers and its methods. In this section, we’ll first look at how Spring Web MVC
mapsawebrequesttoaparticularcontrollermethodthatuses@RequestMappingannotation.We’llthen
look at the attributes of @RequestMapping annotation, and the arguments and return types that
@RequestMappingannotatedmethodscanhave.
@RequestMappingannotationandRequestMappingHandlerMapping
Thefollowingexample listing shows@RequestMapping annotation usage inSomeController (a Spring
WebMVCcontroller)class:
Examplelisting10-8–SomeControllerclass-@RequestMappingusage
@Controller
@RequestMapping("/type_Level_Url")
publicclassSomeController{
@RequestMapping("/methodA_Url")
publicModelAndViewmethodA(){.....}
@RequestMapping("/methodB_Url")
publicModelAndViewmethodB(){.....}
}
The <annotation-driven> element of Spring’s mvc schema creates an instance of
RequestMappingHandlerMapping(aHandlerMappingimplementation)thatisresponsibleformappinga
web request to an appropriate @RequestMapping annotated method. RequestMappingHandlerMapping
considers controller methods as endpoints, and is responsible for uniquely mapping a request to a
controller method based on the @RequestMapping annotations at type- and method-level. In case of
SomeController, if the request path is /type_Level_Url/methodA_Url, methodA is invoked, and if the
request path is /type_Level_Url/methodB_Url, methodB is invoked. You should note that if a request
cannotbemappeduniquelytoacontrollermethod,thenaHTTP404(whichmeans,resourcenotfound)
statuscodeisreturned.
Theattributesof@RequestMappingannotationareusedtonarrowdownthemappingofarequesttoa
particular controlleroracontrollermethod.Youcanspecifytheseattributesatbothtype-andmethod-
level@RequestMappingannotations.Let’snowlookattheattributesof@RequestMappingannotation.
Mappingrequestsbasedonrequestpath
@RequestMapping’svalueattributespecifiestherequestpathtowhichacontrollerorcontrollermethod
is mapped. You can specify the request path without explicitly specifying the value attribute in the
@RequestMapping annotation. For instance, you can specify @RequestMapping(value =
"/type_Level_Url")as@RequestMapping("/type_Level_Url").
YoucanalsospecifyAnt-stylepathpatternsasthevalueofvalueattribute.Forinstance,youcanspecify
patterns,like/myUrl/*,/myUrl/**and/myUrl/*.do,asthevalueofvalueattribute.Thefollowingexample
listingshowsa@RequestMappingannotationthatspecifies/myUrl/**asthepathpattern:
Examplelisting10-9–SomeControllerclass–Ant-stylerequestpathpatternusage
@Controller
@RequestMapping("/myUrl/**")
publicclassSomeController{.....}
Intheaboveexamplelisting,@RequestMapping("/myUrl/**")annotationatthetype-levelspecifiesthat
theSomeControllercontrollerhandlesallrequeststhatbeginwith/myUrlpath.Forinstance,requeststo
/myUrl/abc,/myUrl/xyzand/myUrl/123/somethingpathsarehandledbySomeControllercontroller.
MappingrequestsbasedonHTTPmethods
@RequestMapping’s method attribute specifies the HTTP method that is handled by the controller or
controller method. So, if the method attribute specifies an HTTP GET method, the controller or the
controllermethodhandlesonlyHTTPGETrequests.
The following example listing shows the FixedDepositController’s listFixedDeposits method that is
responsibleforrenderingthelistoffixeddepositsinthesystem:
Examplelisting10-10–@RequestMapping’smethodattributeusage
Project–ch10-bankapp
Sourcelocation-src/main/java/sample/spring/chapter10/web
packagesample.spring.chapter10.web;
importorg.springframework.web.bind.annotation.RequestMethod;
.....
@Controller
@RequestMapping(value="/fixedDeposit")
publicclassFixedDepositController{
.....
@RequestMapping(value="/list",method=RequestMethod.GET)
publicModelAndViewlistFixedDeposits(){.....}
.....
}
In the above example listing, @RequestMapping annotation on the listFixedDeposits method specifies
value of method attribute as RequestMethod.GET. The RequestMethod is an enum that defines HTTP
request methods, like GET,POST,PUT,DELETE, and so on. As the value of the method attribute is
RequestMethod.GET,thelistFixedDepositsmethodisinvoked onlyif an HTTP GET requestis sentto
/fixedDeposit/list path. For instance, if you send an HTTP POST request to /fixedDeposit/list path,
applicationwillreturnanHTTP405(whichmeans,theHTTPmethodisnotsupported)statuscode.
You can also specify an array of HTTP methods as the value of method attribute, as shown in the
followingexamplelisting:
Examplelisting10-11–SpecifyingmultipleHTTPmethodsasthevalueofmethodattribute
@Controller
@RequestMapping(value="/sample")
publicclassMyController{
@RequestMapping(value="/action"method={RequestMethod.GET,RequestMethod.POST})
publicModelAndViewaction(){.....}
}
In the above example listing, the action method is annotated with @RequestMapping annotation whose
methodattribute’s value is { RequestMethod.GET,RequestMethod.POST}. This means that the action
methodisinvokedifanHTTPGETorPOSTrequestissentto/sample/actionpath.
Mappingrequestsbasedonrequestparameters
@RequestMapping’sparamsattributetypicallyspecifiesthenameandvalueoftherequestparameterthat
must be present in the request. The following example listing shows the FixedDepositController’s
showOpenFixedDepositForm method that is responsible for showing the form for creating a fixed
deposit:
Examplelisting10-12–@RequestMapping’sparamsattributeusage
Project–ch10-bankapp
Sourcelocation-src/main/java/sample/spring/chapter10/web
packagesample.spring.chapter10.web;
importorg.springframework.web.bind.annotation.RequestMethod;
.....
@Controller
@RequestMapping(value="/fixedDeposit")
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=createFDForm",method=RequestMethod.POST)
publicModelAndViewshowOpenFixedDepositForm(){.....}
.....
}
Intheaboveexamplelisting,@RequestMappingannotationontheshowOpenFixedDepositFormmethod
specifies the value of params attribute as fdAction=createFDForm. As the FixedDepositController is
mapped to /fixedDeposit path, the showOpenFixedDepositForm method is invoked if an HTTP POST
requestcontainingrequestparameternamedfdActionwithvaluecreateFDFormissentto/fixedDeposit
path.
Ifyouwanttomaprequeststoacontrollerorcontrollermethodbasedonthevaluesofmultiplerequest
parameters, you can specify an array of request parameter name-value pairs as the value of params
attribute,asshowninthefollowingexamplelisting:
Examplelisting10-13–Specifyingmultiplerequestparametername-valuepairsasthevalueofparams
attribute
@RequestMapping(params={"x=a","y=b"})
publicvoidperform(){.....}
Intheaboveexamplelisting,theperformmethodisinvokedonlyiftherequestcontainsparametersnamed
xandywithvaluesaandb,respectively.
You can also map requests to a controller or controller method based on the existence of a request
parameterintherequest.Allyouneedtodoistosimplyspecifythenameoftherequestparameterasthe
value of params attribute. For instance, the perform method shown here is invoked irrespective of the
valueofrequestparameterx:
Examplelisting10-14–performmethodisinvokedifrequestparameterxisfound
@RequestMapping(params="x")
publicvoidperform(){.....}
To map requests to a controller or controller method if a request parameter does not exist, use the !
operator. For example, the following perform method is invoked if request parameter named x is not
foundintherequest:
Examplelisting10-15–performmethodisinvokedifrequestparameterxisnotfound
@RequestMapping(params="!x")
publicvoidperform(){.....}
You can use != operator to map requests to a controller or controller method if the value of a request
parameterisnotequaltothespecifiedvalue,asshownhere:
Examplelisting10-16–performmethodisinvokedifthevalueofrequestparameterxisnotequaltoa
@RequestMapping(params="x!=a")
publicvoidperform(){.....}
Intheaboveexamplelisting,performmethodisinvokedonlyiftherequestcontainsarequestparameter
namedx,andthevalueofxisnotequaltoa.
MappingrequestsbasedontheMIMEtypeoftherequest
TheContent-TyperequestheaderspecifiestheMIMEtypeoftherequest.@RequestMapping’sconsumes
attributespecifiestheMIMEtypeoftherequestthatacontrolleroracontrollermethodhandles.So,ifthe
valueofconsumesattributematchesthevalueoftheContent-Typerequestheader,therequestismapped
tothatparticularcontrollerorcontrollermethod.
The following example listing shows that the perform method is invoked if the Content-Type request
header’svalueisapplication/json:
Example listing 10-17 – perform method is invoked if the value of Content-Type header is
application/json
@RequestMapping(consumes="application/json")
publicvoidperform(){.....}
Aswiththeparamsattribute,youcanuse!operatortospecifytheconditionthataContent-Typeheader
valueisnotpresent.Forinstance,thefollowingperformmethodisinvokediftheContent-Typeheader’s
valueisnotapplication/json:
Example listing 10-18 – perform method is invoked if the value of Content-Type header is not
application/json
@RequestMapping(consumes="!application/json")
publicvoidperform(){.....}
Youcanspecifyanarrayofvaluesintheconsumesattribute,inwhichcasetherequestismappedtothe
controllerorthecontrollermethodiftheContent-Typevaluematchesoneofthevaluesspecifiedbythe
consumesattribute.Inthefollowingexamplelisting,theperformmethodisinvokediftheContent-Typeis
application/jsonortext/plain:
Examplelisting10-19–performmethodisinvokedifContent-Typeisapplication/jsonortext/plain
@RequestMapping(consumes={"application/json","text/plain")
publicvoidperform(){.....}
MappingrequestsbasedontheacceptableMIMEtypeoftheresponse
The Accept request header specifies the acceptable MIME type of the response. @RequestMapping’s
produces attribute specifies the acceptable MIME type of the response. So, if the value of produces
attributevaluematchestheAcceptrequestheader,therequestismappedtothatparticularcontrolleror
controllermethod.
ThefollowingexamplelistingshowsthattheperformmethodisinvokediftheAcceptrequestheader’s
valueisapplication/json:
Examplelisting10-20–performmethodisinvokedifthevalueofAcceptheaderisapplication/json
@RequestMapping(produces="application/json")
publicvoidperform(){.....}
As with the consumes attribute, you can use ! operator to specify the condition that an Accept header
valueisnotpresentintherequest.Ifyouspecifyanarrayofvaluesfortheproducesattribute,requestis
mappedtothecontrollerorthecontrollermethodiftheAcceptheadervaluematchesoneofthevalues
specifiedbytheproducesattribute.
Mappingrequestsbasedonarequestheadervalue
To map requests based on request headers, you can use @RequestMapping’s headers attribute. The
followingexamplelistingshowsthattherequestismappedtotheperformmethodifthevalueofContent-
Typeheaderistext/plain:
Examplelisting10-21–performmethodisinvokedifthevalueofContent-Typeheaderistext/plain
@RequestMapping(headers="Content-Type=text/plain")
publicvoidperform(){.....}
Aswiththeparamsattribute,youcanuse!and!=operatorswhilespecifyingvalueofheadersattribute.
Forinstance,thefollowingexamplelistingshowsthattherequestismappedtotheperformmethodifthe
valueofContent-Typeheaderisnotequaltoapplication/json,theCache-Controlheaderdoesn’texistin
therequest,andtheFromheaderexistsintherequestwithanyvalue:
Examplelisting10-22–Using!and!=operatorsforspecifyingvalueofheadersattribute
@RequestMapping(headers={"Content-Type!=application/json","!Cache-Control","From"})
publicvoidperform(){.....}
Now,thatwehavelookedattheattributesof@RequestMappingannotation,let’slookatthearguments
thatyoucanpassto@RequestMappingannotatedmethods.
@RequestMappingannotatedmethodsarguments
@RequestMappingannotatedmethodscanhaveflexiblemethodsignatures.Theargumenttypesthatcan
be passed to @RequestMapping annotated methods include HttpServletRequest, HttpSession,
java.security.Principal, org.springframework.validation.BindingResult,
org.springframework.web.bind.support.SessionStatus,org.springframework.ui.Model,andsoon.Toview
acompletelistofargumentsthatcanbepassedto@RequestMappingannotatedmethod,pleasereferto
@RequestMappingJavadoc.
As we discuss different Spring Web MVC features in this book, we’ll come across scenarios which
requireustopassdifferentargumenttypesto@RequestMappingannotatedmethods.Fornow,we’lllook
atascenarioinwhichweneedtosendHttpServletRequestobjectasanargument.
ThefollowingexamplelistingshowstheFixedDepositController’sviewFixedDepositDetailsmethodthat
acceptsanargumentoftypeHttpServletRequest:
Examplelisting10-23–FixedDepositControllerclass-passingHttpServletRequestargument
Project–ch10-bankapp
Sourcelocation-src/main/java/sample/spring/chapter10/web
packagesample.spring.chapter10.web;
importjavax.servlet.http.HttpServletRequest;
.....
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=view",method=RequestMethod.GET)
publicModelAndViewviewFixedDepositDetails(HttpServletRequestrequest){
FixedDepositDetailsfixedDepositDetails=fixedDepositService
.getFixedDeposit(Integer.parseInt(request.getParameter("fixedDepositId")));
.....
}
.....
}
TheviewFixedDepositDetailsmethodisinvokedwhenyouclicktheEdithyperlink corresponding toa
fixeddeposit(referfigure10-8).HttpServletRequestisusedbytheviewFixedDepositDetailsmethodto
obtainthefixedDepositIdrequestparameterthatuniquelyidentifiesafixeddepositinthesystem.
Let’snowlookatthereturntypesthataresupportedfor@RequestMappingannotatedmethods.
@RequestMappingannotatedmethodsreturntypes
The supported return types for @RequestMapping annotated methods include ModelAndView,
org.springframework.web.servlet.View,String,java.util.concurrent.Callable,void,andsoon.Toviewa
complete list of return types supported for @RequestMapping annotated methods, please refer to
@RequestMappingJavadoc.
As we discuss different Spring Web MVC features in this book, we’ll come across scenarios which
require@RequestMapping annotated methods to have different return types. In this section, we’ll only
lookatexamplesthatshowmethodsthathaveStringorModelAndViewasreturntypes.
ThefollowingexamplelistingshowsFixedDepositController’sshowOpenFixedDepositFormmethodthat
renderstheHTMLformforopeninganewfixeddeposit(referfigure10-9):
Examplelisting10-24–FixedDepositControllerclass-ModelAndViewreturntypeexample
Project–ch10-bankapp
Sourcelocation-src/main/java/sample/spring/chapter10/web
packagesample.spring.chapter10.web;
importorg.springframework.ui.ModelMap;
.....
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=createFDForm",method=RequestMethod.POST)
publicModelAndViewshowOpenFixedDepositForm(){
FixedDepositDetailsfixedDepositDetails=newFixedDepositDetails();
fixedDepositDetails.setEmail("Youmustenteravalidemail");
ModelMapmodelData=newModelMap();
modelData.addAttribute(fixedDepositDetails);
returnnewModelAndView("createFixedDepositForm",modelData);
}
.....
}
TheshowOpenFixedDepositForm method returns a ModelAndView object that contains an instance of
FixedDepositDetailsasamodelattributeandcreateFixedDepositFormstringvalueastheviewname.
If you compare the above example listing with 10-1 and 10-6, you’ll notice that the
showOpenFixedDepositForm method uses Spring’s ModelMap object instead of java.util.Map to store
model attributes. ModelMap is an implementation of java.util.Map interface that allows you to store
modelattributeswithoutexplicitlyspecifyingtheirnames.ModelMapautomaticallygeneratesthenameof
themodelattributebasedon apre-definedstrategy.Forinstance, ifyouaddacustomJavaobjectasa
modelattribute,thename(beginningwithlowercasefirstletter)oftheobject’sclassisusedasthename
ofthemodelattribute.Intheaboveexamplelisting,whenaninstanceofFixedDepositDetailsisaddedto
theModelMap,itisstoredintheModelMapwiththenamefixedDepositDetails.
Whena@RequestMappingannotatedmethodreturnsastringvalue,itisconsideredasthenameofthe
viewthatisresolvedtoanactualview(like,JSPpageorservlet)bytheViewResolverconfiguredforthe
web application. The following example listing shows the configuration of
InternalResourceViewResolverinch10-bankappproject:
Examplelisting10-25–bankapp-config.xml–ViewResolverconfiguration
Project–ch10-bankapp
Sourcelocation-src/main/webapp/WEB-INF/spring
<beanid="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<propertyname="prefix"value="/WEB-INF/jsp/"/>
<propertyname="suffix"value=".jsp"/>
</bean>
The above configuration suggests that when a string value xyz is returned, it is resolved to /WEB-
INF/jsp/xyz.jsp.Refersection10-3tolearnmoreabouttheInternalResourceViewResolverconfiguration
shownabove.
If the string value returned by the @RequestMapping annotated method has the prefix redirect:, it is
treated as a redirect URL and not as a view name. The following example listing shows
FixedDepositController’scloseFixedDepositmethodthatisresponsibleforclosingafixeddepositwhen
auserclickstheClosebutton(referfigure10-9):
Examplelisting10-26–FixedDepositControllerclass-Stringreturntypeexample
Project–ch10-bankapp
Sourcelocation-src/main/java/sample/spring/chapter10/web
@RequestMapping(params="fdAction=close",method=RequestMethod.GET)
publicStringcloseFixedDeposit(.....intfdId){
fixedDepositService.closeFixedDeposit(fdId);
return"redirect:/fixedDeposit/list";
}
FixedDepositController’s closeFixedDeposit method closes the fixed deposit identified by the fdId
argumentandreturnsredirect:/fixedDeposit/liststringvalue.Asthereturnedstringvalueisprefixedwith
redirect:,theuserisredirectedtothe/fixedDeposit/listURLthatshowsthelistoffixeddeposits(refer
figure10-8).
Let’snowlookatthe@RequestParamannotationthatallowsyoutoassignarequestparametervaluetoa
controllermethodargument.
Passingrequestparameterstocontrollermethodsusing@RequestParam
Wesawinexamplelisting10-23thatwecanpassHttpServletRequestobjecttoacontrollermethodand
useittoretrieverequestparameters.InsteadofpassingHttpServletRequestobjecttoacontrollermethod,
you can annotate a method argument with @RequestParam annotation to assign value of a request
parametertothemethodargument.
NOTEYoushouldnotethatthe@RequestParamannotationcanonlybeusedifthemethodisannotated
with@RequestMappingor@ModelAttribute(explainedinchapter11)annotation.
ThefollowingexamplelistingshowsFixedDepositController’scloseFixedDepositmethodthatisinvoked
whenauserclickstheClosebutton(referfigure10-8)tocloseafixeddeposit:
Examplelisting10-27–FixedDepositControllerclass-@RequestParamusage
Project–ch10-bankapp
Sourcelocation-src/main/java/sample/spring/chapter10/web
packagesample.spring.chapter10.web;
importorg.springframework.web.bind.annotation.RequestParam;
.....
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=close",method=RequestMethod.GET)
publicStringcloseFixedDeposit(@RequestParam(value="fixedDepositId")intfdId){
fixedDepositService.closeFixedDeposit(fdId);
return"redirect:/fixedDeposit/list";
}
.....
}
@RequestParam’svalueattributespecifiesthenameoftherequestparameterwhosevalueisassignedto
themethodargument.Intheaboveexamplelisting,@RequestParamannotationisusedtoassignthevalue
offixedDepositId request parameter to fdId method argument. As the type of the fdId argument is int,
SpringisresponsibleforconvertingthefixedDepositIdrequestparametertointtype.Bydefault,Spring
automaticallyprovidestypeconversionforsimpleJavatypes,likeint,long,java.util.Date,andsoon.To
convert request parameters to custom Java types (like Address), you need to register custom
PropertyEditors with Spring’s WebDataBinder instance or org.springframework.format.Formatters with
Spring’sFormattingConversionService instance. We’ll learnmore about WebDataBinder in chapter 11,
andFormatterandFormattingConversionServiceinchapter13.
Let’snowlookathowyoucanaccessalltherequestparametersinacontrollermethod.
Passingalltherequestparameterstoacontrollermethod
Topassalltherequestparameterstoacontrollermethod,defineanargumentoftypeMap<String,String>
orMultiValueMap<String,String>(anobjectprovidedbySpringthatimplementsjava.util.Mapinterface)
andannotateitwith@RequestParamannotation.
ThefollowingexamplelistingshowsFixedDepositController’sopenFixedDepositmethodthatcreatesa
fixed deposit when a user enters fixed deposit details and clicks the Save button on the ‘Open fixed
deposit’formforopeningfixeddeposits(referfigure10-9):
Examplelisting10-28–FixedDepositControllerclass–accessingallrequestparameters
Project–ch10-bankapp
Sourcelocation-src/main/java/sample/spring/chapter10/web
packagesample.spring.chapter10.web;
importjava.util.Map;
.....
@RequestMapping(value="/fixedDeposit")
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=create",method=RequestMethod.POST)
publicModelAndViewopenFixedDeposit(@RequestParamMap<String,String>params){
StringdepositAmount=params.get("depositAmount");
Stringtenure=params.get("tenure");
.....
}
}
In the above example listing, params argument of type Map<String, String> is annotated with
@RequestParamannotation.Noticethatthevalueattributeof@RequestParamannotationisnotspecified.
If@RequestParam’svalueattributeisnotspecifiedandthetypeofthemethodargumentisMap<String,
String> or MultiValueMap<String, String>, Spring copies all the requests parameters into the method
argument.Eachrequestparameter’svalueisstoredintheMap(orMultiValueMap)withthenameofthe
requestparameterasthekey.
The following example listing shows FixedDepositController’s editFixedDeposit method that is
responsibleformakingchangestoanexistingfixeddeposit:
Examplelisting10-29–FixedDepositControllerclass–accessingallrequestparameters
Project–ch10-bankapp
Sourcelocation-src/main/java/sample/spring/chapter10/web
packagesample.spring.chapter10.web;
importorg.springframework.util.MultiValueMap;
.....
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=edit",method=RequestMethod.POST)
publicModelAndVieweditFixedDeposit(@RequestParamMultiValueMap<String,String>params)
{
StringdepositAmount=params.get("depositAmount").get(0);
Stringtenure=params.get("tenure").get(0);
.....
}
}
In the above example listing, editFixedDeposit’s params argument is of type MultiValueMap<String,
String>,andisannotatedwith@RequestParamannotation.IfanobjectisoftypeMultiValueMap<K,V>,
thenitmeansthatKisthetypeofthekeyandList<V>isthetypeofthevalue.Astheparamsargumentis
oftypeMultiValueMap<String, String>, it means that the key is of type String and the value is of type
List<String>. When storing request parameters in MultiValueMap<String, String> type, Spring uses
request parameter’s name as key and the value of the request parameter is added to the List<String>
value.MultiValueMapisparticularlyusefulifyouhavemultiplerequestparameterswiththesamename.
AsthevaluecorrespondingtoarequestparameterisoftypeList<String>,callingparams.get(Stringkey)
returnsaList<String>type.Forthisreason,get(0)iscalledonthereturnedList<String>togetthevalue
ofrequestparametersdepositAmount,tenure,andsoon.Alternatively,youcanusegetFirst(String key)
methodofMultiValueMaptoobtainthefirstelementfromtheList<String>value.
Let’snowtakeacloserlookatthevariousattributesof@RequestParamannotation.
Specifyingrequestparameternameusingvalueattribute
Wesawearlierthat@RequestParam’svalueattributespecifiesthenameoftherequestparameterwhose
valueisassignedtothemethodargument.Ifyoudon’tspecifythenameofarequestparameter,method
argumentnameisconsideredasthenameoftherequestparametername.Forinstance,inthefollowing
examplelisting,valueofrequestparameternamedparamisassignedtotheparamargument:
Examplelisting10-30–@RequestParamusage-unspecifiedrequestparametername
@RequestMapping(.....)
publicStringdoSomething(@RequestParamStringparam){.....}
Intheaboveexamplelisting,@RequestParamdoesn’tspecifythenameoftherequestparameterwhose
value is assigned to the param argument; therefore, param is considered as the name of the request
parameter.
Specifyingrequestparameterisoptionalormandatorybyusingrequiredattribute
Bydefault,requestparameterspecifiedbythe@RequestParamannotationismandatory;ifthespecified
request parameter is not found in the request, an exception is thrown. You can specify that the request
parameterisoptionalbysettingthevalueofrequiredattributetofalse,asshownhere:
Examplelisting10-31–@RequestParam’srequiredattribute
@RequestMapping(.....)
publicStringperform(@RequestParam(value="myparam",required=false)Stringparam){.....}
Intheaboveexamplelisting,@RequestParam’srequiredattributevalueissettofalse,whichmeansthat
themyparam requestparameterisoptional. Now, if the myparam requestparameter is not foundinthe
request,it’llnotresultinanexception.Instead,anullvalueisassignedtotheparammethodargument.
SpecifyingdefaultvalueforarequestparameterusingdefaultValueattribute
@RequestParam’sdefaultValueattributespecifiesthedefaultvalueforarequestparameter.Iftherequest
parameterspecifiedby@RequestParam’svalueattributeisnotfoundintherequest,thevaluespecified
by the defaultValue attribute is assigned to the method argument. The following example listing shows
usageofdefaultValueattribute:
Examplelisting10-32–@RequestParam’sdefaultValueattribute
@RequestMapping(.....)
publicStringperform(@RequestParam(value="location",defaultValue="earth")Stringparam){
.....
}
Intheaboveexamplelisting,ifrequestparameternamedlocationisnotfoundintherequest,thevalue
earthisassignedtotheparammethodargument.
In this section, we looked at @RequestMapping and @RequestParam annotations to create the
FixedDepositController of MyBank application. Let’s now look at how validation of form data is
performedintheFixedDepositControllerclass.
10-8Validation
WesawearlierthatFixedDepositController’sshowOpenFixedDepositFormmethod(referexamplelisting
10-24) renders createFixedDepositForm.jsp JSP page that shows the form for opening a new fixed
deposit. When the form is submitted, the data entered in the form is validated by
FixedDepositController’sopenFixedDepositmethod(referexamplelisting10-28).Iferrorsarereported
during validation, the createFixedDepositForm.jsp JSP page is rendered again with validation error
messagesandtheoriginalformdatathatwasenteredbytheuser(referfigure10-9).
Thefollowingexamplelistingshowsthe<form>elementofcreateFixedDepositForm.jspJSPpage:
Examplelisting10-33–createFixedDepositForm.jsp–<form>element
Project–ch10-bankapp
Sourcelocation-src/main/webapp/WEB-INF/jsp
<formname="createFixedDepositForm"method="POST"
action="${pageContext.request.contextPath}/fixedDeposit?fdAction=create">
.....
<inputtype="submit"value="Save"/>
</form>
Intheaboveexamplelisting,<form>element’smethodattributespecifiesPOSTastheHTTPmethod,and
actionattributespecifies/fixedDeposit?fdAction=createastheURLtowhichtheformissubmittedwhen
the user clicks the Save button. Submission of the form results in the invocation of
FixedDepositController’sopenFixedDepositmethod.
ThefollowingexamplelistingshowshowthevalidationisperformedbytheopenFixedDepositmethod,
andhowtheoriginalformdataenteredbytheuserisshownagainincaseofvalidationerrors:
Examplelisting10-34–FixedDepositController’sopenFixedDepositmethod
Project–ch10-bankapp
Sourcelocation-src/main/java/sample/spring/chapter10/web
packagesample.spring.chapter10.web;
.....
importorg.apache.commons.lang3.math.NumberUtils;
@RequestMapping(value="/fixedDeposit")
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=create",method=RequestMethod.POST)
publicModelAndViewopenFixedDeposit(@RequestParamMap<String,String>params){
StringdepositAmount=params.get("depositAmount");
.....
Map<String,Object>modelData=newHashMap<String,Object>();
if(!NumberUtils.isNumber(depositAmount)){
modelData.put("error.depositAmount","enteravalidnumber");
}elseif(NumberUtils.toInt(depositAmount)<1000){
modelData.put("error.depositAmount","mustbegreaterthanorequalto1000");
}
.....
FixedDepositDetailsfixedDepositDetails=newFixedDepositDetails();
fixedDepositDetails.setDepositAmount(depositAmount);
.....
if(modelData.size()>0){//--thismeanstherearevalidationerrors
modelData.put("fixedDepositDetails",fixedDepositDetails);
returnnewModelAndView("createFixedDepositForm",modelData);
}else{
fixedDepositService.saveFixedDeposit(fixedDepositDetails);
returnnewModelAndView("redirect:/fixedDeposit/list");
}
}
.....
}
TheopenFixedDepositmethodvalidatesdepositamount,tenureandemailinformationenteredbytheuser.
Notice that to simplify validation of data, NumberUtils class of Apache Commons Lang
(http://commons.apache.org/proper/commons-lang/)libraryhasbeenused.ThemodelDatavariableisa
java.util.MapobjectthatstoresmodelattributesthatwewanttopasstothecreateFixedDepositForm.jsp
JSPpageincaseofvalidationerrors.
As we want to show validation error messages and the original form data if validation fails, the
validationerrormessagesandtheoriginalformdataarestoredinmodelData.Forinstance,ifthedeposit
amount entered by the user fails validation, an appropriate validation error message is stored in the
modelDatawithnameerror.depositAmount.Thevaluesenteredbytheuseraresetonanewinstanceof
FixedDepositDetails object. If validation errors are reported, the newly created FixedDepositDetails
instanceisaddedtothemodelDatawithnamefixedDepositDetails,andthecreateFixedDepositForm.jsp
JSP page is rendered. Alternatively, if no validation errors are reported, the newly created
FixedDepositDetailsobjectissavedinthedatasource,andthepagethatshowsthecompletelistoffixed
depositsisrendered.
AsweareusingFixedDepositDetailsobject tostore theoriginalform data enteredbytheuser, allthe
attributesofFixedDepositDetailshavebeendefinedoftypeString,asshownhere:
Examplelisting10-35–FixedDepositDetailsclass
Project–ch10-bankapp
Sourcelocation-src/main/java/sample/spring/chapter10/domain
packagesample.spring.chapter10.domain;
publicclassFixedDepositDetails{
privatelongid;//--idvalueissetbythesystem
privateStringdepositAmount;
privateStringtenure;
privateStringemail;
//--gettersandsettersforfields
.....
}
AsdepositAmountandtenurefieldsaredefinedoftypeString,wehadtowriteextralogictoconvertthem
intonumericvaluesforperformingnumericalcomparisons.Inchapter11,we’lllookathowSpringWeb
MVCsimplifiesbindingformdatatoformbackingobjects(likeFixedDepositDetails)andre-displaying
theoriginalformdataincaseofvalidationerrors.
The following fragments from the createFixedDepositForm.jsp JSP page demonstrate how validation
errormessagesandtheoriginalformdataaredisplayedintheMyBankapplication:
Examplelisting10-36–createFixedDepositForm.jsp
Project–ch10-bankapp
Sourcelocation-src/main/webapp/WEB-INF/jsp
<%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%>
<formname="createFixedDepositForm"method="POST"
action="${pageContext.request.contextPath}/fixedDeposit?fdAction=create">
.....
<tdclass="td"><b>Amount(inUSD):</b></td>
<tdclass="td">
<inputtype="text"name="depositAmount"
value="${requestScope.fixedDepositDetails.depositAmount}"/>
<fontstyle="color:#C11B17;">
<c:outvalue="${requestScope['error.depositAmount']}"/></font>
</td>
.....
<inputtype="submit"value="Save"/>
</form>
In the above example listing, the value of depositAmount form field is specified as
${requestScope.fixedDepositDetails.depositAmount}. In the openFixedDeposit method (refer example
listing10-34),weaddedaFixedDepositDetailsinstanceasamodelattributenamedfixedDepositDetails;
therefore,the${requestScope.fixedDepositDetails.depositAmount}expressionshows theoriginalvalue
thattheuserenteredforthedepositAmountfield.
The expression ${requestScope['error.depositAmount']} refers to the error.depositAmount request
attribute. In the openFixedDeposit method (refer example listing 10-34), we saw that the
error.depositAmountcontainsvalidationerrormessagecorrespondingtothefixeddepositamountentered
bytheuser;therefore,the<c:outvalue="${requestScope['error.depositAmount']}"/>elementshowsthe
validationerrormessagecorrespondingtothefixeddepositamountenteredbytheuser.
Let’snowlookathowtohandleexceptionsinSpringWebMVCapplications.
10-9Handlingexceptionsusing@ExceptionHandlerannotation
@ExceptionHandlerannotationisusedinanannotatedcontrollertoidentifythemethodresponsiblefor
handling exceptions thrown by the controller. Spring’s HandlerExceptionResolver is responsible for
mapping an exception to an appropriate controller method responsible for handling the exception. You
should note that the <annotation-driven> element of Spring’s mvc schema configures an instance of
ExceptionHandlerExceptionResolver (a HandlerExceptionResolver implementation) that maps an
exceptiontoanappropriate@ExceptionHandlerannotatedmethod.
Thefollowingexamplelistingshowsusageof@ExceptionHandlerannotationinch10-bankappproject:
Examplelisting10-37–@ExceptionHandlerannotationusage
Project–ch10-bankapp
Sourcelocation-src/main/java/sample/spring/chapter10/web
packagesample.spring.chapter10.web;
importorg.springframework.web.bind.annotation.ExceptionHandler;
.....
@Controller
@RequestMapping(value="/fixedDeposit")
publicclassFixedDepositController{
.....
@ExceptionHandler
publicStringhandleException(Exceptionex){
return"error";
}
}
TheaboveexamplelistingshowsthattheFixedDepositController’shandleExceptionmethodisannotated
with@ExceptionHandlerannotation.ThismeansthatthehandleExceptionmethodisinvokedbySpring
Web MVC to handle exceptions thrown during execution of FixedDepositController controller.
@ExceptionHandler methods typically render an error page containing error details. An
@ExceptionHandler annotation’s value attribute specifies the list of exceptions that the
@ExceptionHandlerannotatedmethodhandles.Ifthevalueattributeisnotspecified,theexceptiontypes
specified as method arguments are handled by the @ExceptionHandler annotated method. In the above
examplelisting,thehandleExceptionmethodhandlesexceptionsoftypejava.lang.Exception.
Like@RequestMappingmethods,@ExceptionHandlermethodscanhaveflexiblemethodsignatures.The
return types supported for @ExceptionHandler methods include ModelAndView, View, String, void,
Model, and so on. The argument types supported for @ExceptionHandler methods include
HttpServletRequest,HttpServletResponse,HttpSession,andsoon.Referto@ExceptionHandlerJavadoc
forthecompletelistofsupportedargumentsandreturntypes.
The view information returned by an @ExceptionHandler annotated method is used by the
DispatcherServlettorenderanappropriateerrorpage.Forinstance,inexamplelisting10-37,theerror
stringvaluereturnedbythehandleExceptionmethodisusedbytheDispatcherServlettorender/WEB-
INF/jsp/error.jsppage.Ifthe@ExceptionHandlermethoddoesn’treturnanyviewinformation(thatis,the
return type is void or Model), Spring’s RequestToViewNameTranslator class (refer section 11-2 of
chapter11fordetails)isusedtodeterminetheviewtoberendered.
You can define multiple @ExceptionHandler annotated methods in your controller class for handling
differentexceptiontypes.Thevalueattributeof@ExceptionHandlerannotationallowsyoutospecifythe
exception types that are handled by the method. The following example listing shows that the
myExceptionHandler method handles exceptions of type IOException and FileNotFoundException, and
myOtherExceptionHandlermethodhandlesexceptionsoftypeTimeoutException:
Examplelisting10-38–Specifyingthetypeofexceptionshandledbyan@ExceptionHandlermethod
@Controller
.....
publicclassMyController{
.....
@ExceptionHandler(value={IOException.class,FileNotFoundException.class})
publicStringmyExceptionHandler(){
return"someError";
}
@ExceptionHandler(value=TimeoutException.class)
publicStringmyOtherExceptionHandler(){
return"otherError";
}
}
IfMyControllerthrowsanexceptionoftypeIOExceptionorFileNotFoundException(oranexceptionthat
isasubtypeofIOExceptionorFileNotFoundException),themyExceptionHandlermethodisinvokedto
handletheexception.IfMyControllerthrowsanexceptionoftypeTimeoutException(oranexceptionthat
is a subtype of TimeoutException), the myOtherExceptionHandler method is invoked to handle the
exception.
Let’snowlookathowSpring’sContextLoaderListenerisusedtoloadrootwebapplicationcontextXML
file(s).
10-11LoadingrootwebapplicationcontextXMLfile(s)
Asmentionedatthebeginningofthischapter,therootwebapplicationcontextfiledefinesbeansthatare
shared by all the servlets and filters of the web application. The following example listing shows the
configurationofContextLoaderListener:
Examplelisting10-39–ContextLoaderListenerconfiguration
Project–ch10-bankapp
Sourcelocation-src/main/webapp/WEB-INF/web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/META-INF/spring/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
In the above example listing, <listener> element configures the ContextLoaderListener (a
ServletContextListener) that is responsible for loading the root web application context XML file(s)
specified by the contextConfigLocation servlet context initialization parameter. The <context-param>
element is used to specify a servlet context initialization parameter. ContextLoaderListener creates an
instanceoftherootWebApplicationContextwithwhichthebeansloadedfromtherootwebapplication
contextXMLfile(s)areregistered.
In the above example listing, contextConfigLocation parameter specifies /META-
INF/spring/applicationContext.xml file as the root web application context XML file. You can specify
multipleapplicationcontextXMLfilesseparatedbycommaornewlineorwhitespaceorsemicolon.If
you don’t specify the contextConfigLocation parameter, the ContextLoaderListener treats /WEB-
INF/applicationContext.xmlfileastherootwebapplicationcontextXMLfile.
10-12Summary
Inthischapter,welookedatsomeoftheimportantobjectsofasimpleSpringWebMVCapplication.We
also looked at how to use @Controller, @RequestMapping, @RequestParam and @ExceptionHandler
annotations to create annotated controllers. In the next chapter, we’ll look at how Spring transparently
bindsrequestparameterstoformbackingobjectsandperformsvalidation.
Chapter11–ValidationanddatabindinginSpringWebMVC
11-1Introduction
In the previous chapter, we looked at the MyBank web application that was developed using
@Controller, @RequestMapping and @RequestParam annotations. We saw that the form data was
retrievedfromtherequest(referexamplelisting10-23,10-28and10-29)andexplicitlysetontheform
backing object (which was FixedDepositDetails object). Also, the validation logic was written in the
controllermethoditself(referexamplelisting10-34).
Inthischapter,we’lldiscuss:
·@ModelAttributeand@SessionAttributesannotationsthatareusefulwhendealingwithmodel
attributes
·howSpring’sWebDataBindersimplifiesbindingformdatatoformbackingobjects
· validating form backing objects using Spring Validation API and JSR 303’s constraint
annotations
·Spring’sformtaglibrarythatsimplifieswritingJSPpages
Let’sfirstlookatthe@ModelAttributeannotationthatisusedforaddingandretrievingmodelattributes
toandfromSpring’sModelobject.
11-2 Adding and retrieving model attributes using
@ModelAttributeannotation
Inthepreviouschapter,wesawthata@RequestMappingmethodstoresmodelattributesinaHashMap
(or ModelMap) instance and returns these model attributes via ModelAndView object. The model
attributesreturnedbya@RequestMappingmethodarestoredinSpring’sModelobject.
Amodelattributemayrepresentaformbackingobjectorareferencedata.FixedDepositDetailsobjectin
theMyBankwebapplicationisanexampleofaformbackingobject;whentheformforopeninganew
fixed deposit is submitted, the information contained in the form is stored in the FixedDepositDetails
object. Typically, domain objects or entities in an application are used as form backing objects.
Referencedatareferstotheadditionalinformation(otherthantheformbackingobject)requiredbythe
view.Forinstance,ifyouaddausercategory(likemilitarypersonnel,seniorcitizen,andsoon)toeach
fixeddeposit,theformforopeningnewfixeddepositswouldneedtoshowacomboboxdisplayingthe
listofcategories.Thelistofcategorieswouldbethereferencedataneededfordisplayingtheformfor
openingnewfixeddeposits.
@ModelAttribute annotation is used on methods and method arguments to store and retrieve model
attributesfromSpring’sModelobject,respectively.@ModelAttributeannotationonamethodindicates
thatthemethodaddsoneormoremodelattributestotheModelobject.And,@ModelAttributeannotation
on a method argument is used to retrieve a model attribute from the Model object and assign it to the
methodargument.
IMPORTchapter 11/ch11-bankapp (This project shows the MyBank web application that uses
@ModelAttribute annotation and Spring’s form tag library. The MyBank web application functionality
offered by ch11-bankapp and ch10-bankapp projects is the same. If you deploy the project on Tomcat
serverandaccesstheURLhttp://localhost:8080/ch11-bankapp,you’llseethelistoffixeddepositsinthe
system.)
Let’sfirstlookat@ModelAttributeannotatedmethods.
Addingmodelattributesusingmethod-level@ModelAttributeannotation
ThefollowingexamplelistingshowsFixedDepositController’sgetNewFixedDepositDetailsmethodthat
isannotatedwith@ModelAttributeannotation:
Examplelisting11-1–@ModelAttributeannotationusageatmethodlevel
Project–ch11-bankapp
Sourcelocation-src/main/java/sample/spring/chapter11/web
packagesample.spring.chapter11.web;
importorg.springframework.web.bind.annotation.ModelAttribute;
importsample.spring.chapter11.domain.FixedDepositDetails;
.....
@Controller
@RequestMapping(value="/fixedDeposit")
.....
publicclassFixedDepositController{
privatestaticLoggerlogger=Logger.getLogger(FixedDepositController.class);
.....
@ModelAttribute(value="newFixedDepositDetails")
publicFixedDepositDetailsgetNewFixedDepositDetails(){
FixedDepositDetailsfixedDepositDetails=newFixedDepositDetails();
fixedDepositDetails.setEmail("Youmustenteravalidemail");
logger.info("getNewFixedDepositDetails()method:Returninganewinstanceof
FixedDepositDetails");
returnfixedDepositDetails;
}
.....
}
The getNewFixedDepositDetails method creates and returns a new instance of FixedDepositDetails
object. As the getNewFixedDepositDetails method is annotated with @ModelAttribute annotation, the
returnedFixedDepositDetailsinstanceisaddedtotheModelobject.@ModelAttribute’svalueattribute
specifiesthatthereturnedFixedDepositDetailsobjectisstoredwithnamenewFixedDepositDetailsinthe
Model object. Notice that the getNewFixedDepositDetails method logs the following message -
‘getNewFixedDepositDetails()method:ReturninganewinstanceofFixedDepositDetails’.
NOTEYoushouldnotethatthescopeofmodelattributesisrequest.Thismeansthatthemodelattributes
arelostwhenarequestcompletes,orifarequestisredirected.
Later in this section, we’ll see how the createFixedDepositForm.jsp JSP page (refer
src/main/webapp/WEB-INF/jsp/createFixedDepositForm.jspfile)ofch11-bankappprojectusesSpring’s
form tag library to access the FixedDepositDetails object named newFixedDepositDetails from the
Modelobject.
Ifyoudon’tspecify@ModelAttribute’svalueattribute,thereturnedobjectisstoredintheModelobject
usingthesimplenameofthereturnedobject’stype.Inthefollowingexamplelisting,theSampleobject
returnedbythegetSamplemethodisstoredwithnamesampleintheModelobject:
Examplelisting11-2–@ModelAttributeusage–valueattributeisnotspecified
importorg.springframework.ui.Model;
.....
publicclassSampleController{
@ModelAttribute
publicSamplegetSample(){
returnnewSample();
}
}
A@ModelAttributeannotatedmethodacceptssametypesofargumentsasa@RequestMappingmethod.
Thefollowingexamplelistingshowsa@ModelAttributeannotatedmethodthatacceptsanargumentof
typeHttpServletRequest:
Examplelisting11-3–@ModelAttributeannotatedmethodthatacceptsHttpServletRequestasargument
@ModelAttribute(value="myObject")
publicSomeObjectdoSomething(HttpServletRequestrequest){.....}
In chapter 10, we saw that the @RequestParam annotation is used to pass request parameters to a
@RequestMapping annotated method. @RequestParam annotation can also be used to pass request
parameterstoa@ModelAttributeannotatedmethod,asshowninthefollowingexamplelisting:
Examplelisting11-4–Passingrequestparameterstoa@ModelAttributeannotatedmethod
@ModelAttribute(value="myObject")
publicSomeObjectdoSomething(@RequestParam("someArg")Stringmyarg){.....}
As@RequestMappingand@ModelAttributeannotatedmethodscanacceptModelobjectsasargument,
youcandirectlyaddmodelattributestotheModelobjectina@ModelAttributeor@RequestMapping
annotated method. The following example listing shows a @ModelAttribute method that directly adds
modelattributestotheModelobject:
Examplelisting11-5–AddingmodelattributesdirectlytoModelobject
importorg.springframework.ui.Model;
.....
publicclassSampleWebController{
@ModelAttribute
publicvoiddoSomething(Modelmodel){
model.addAttribute("myobject",newMyObject());
model.addAttribute("otherobject",newOtherObject());
}
}
Intheaboveexamplelisting,theModelobjectispassedasanargumenttothedoSomethingmethodthat
directly adds model attributes to the Model object. As the doSomething method adds model attributes
directly to the Model object, the doSomething method’s return type is specified as void, and the
@ModelAttribute’svalueattributeisnotspecified.
It is possible to have a single method annotated with both @RequestMapping and @ModelAttribute
annotations. The following example listing shows FixedDepositController’s listFixedDeposits method
thatisannotatedwithboth@RequestMappingand@ModelAttributeannotations:
Examplelisting11-6–@ModelAttributeand@RequestMappingannotationsonthesamemethod
Project–ch11-bankapp
Sourcelocation-src/main/java/sample/spring/chapter11/web
packagesample.spring.chapter11.web;
.....
@Controller
@RequestMapping(value="/fixedDeposit")
.....
publicclassFixedDepositController{
privatestaticLoggerlogger=Logger.getLogger(FixedDepositController.class);
@RequestMapping(value="/list",method=RequestMethod.GET)
@ModelAttribute(value="fdList")
publicList<FixedDepositDetails>listFixedDeposits(){
logger.info("listFixedDeposits()method:Gettinglistoffixeddeposits");
returnfixedDepositService.getFixedDeposits();
}
.....
}
The listFixedDeposits method renders the list.jsp JSP page (refer src/main/webapp/WEB-
INF/jsp/fixedDeposit/list.jsp file of ch11-bankapp project) that shows the list of fixed deposits in the
system.Whenamethodisannotatedwithboth@RequestMappingand@ModelAttributeannotations,the
value returned by the method is considered as a model attribute, and not as a view name. In such a
scenario,viewnameisdeterminedbySpring’sRequestToViewNameTranslatorclassthatdeterminesthe
view to render based on the request URI of the incoming request. Later in this chapter, we’ll discuss
RequestToViewNameTranslator in detail. In example listing 11-6, notice that the listFixedDeposits
methodlogsthefollowingmessage–‘listFixedDeposits()method:Gettinglistoffixeddeposits’.
Itisimportanttonotethatyoucandefinemultiplemethodsannotatedwith@ModelAttributeannotationin
acontroller.Whenarequestisdispatchedtoa@RequestMappingannotatedmethodofacontroller,all
the @ModelAttribute annotated methods of that controller are invoked before the @RequestMapping
annotated method is invoked. The following example listing shows a controller that defines
@RequestMappingand@ModelAttributeannotatedmethods:
Examplelisting11-7–@RequestMappingmethodisinvokedafterallthe@ModelAttributemethodsare
invoked
@RequestMapping("/mycontroller")
publicclassMyController{
@RequestMapping("/perform")
publicStringperform(){.....}
@ModelAttribute(value="a")
publicAgetA(){.....}
@ModelAttribute(value="b")
publicBgetB(){.....}
}
Intheaboveexamplelisting,ifarequestismappedtoMyController’sperformmethod,SpringWebMVC
willfirstinvokegetAandgetBmethods,followedbyinvokingtheperformmethod.
Ifa methodis annotatedwithboth @RequestMappingand@ModelAttributeannotations, the methodis
invoked only once for processing the request. The following example listing shows a controller that
definesamethodthatisannotatedwithboth@RequestMappingand@ModelAttributeannotations:
Examplelisting11-8–Methodannotatedwithboth@RequestMappingand@ModelAttributeannotations
isinvokedonlyonceforprocessingtherequest
@RequestMapping("/mycontroller")
publicclassMyController{
@RequestMapping("/perform")
@ModelAttribute
publicStringperform(){.....}
@ModelAttribute(value="a")
publicAgetA(){.....}
@ModelAttribute(value="b")
publicBgetB(){.....}
}
Intheaboveexamplelisting,ifarequestismappedtoMyController’sperformmethod,SpringWebMVC
will first invoke getA and getB methods, followed by invoking the perform method. As the perform
method is annotated with both @RequestMapping and @ModelAttribute annotations, Spring’s
RequestToViewNameTranslator class is used for determining the name of the view to render after the
performmethodisexecuted.
If you now deploy the ch11-bankapp project on Tomcat and go to http://localhost:8080/ch11-
bankapp/fixedDeposit/listURL,you’llseeawebpageshowingthelistoffixeddeposits.Also,you’llsee
thefollowingsequenceofmessagesontheconsole:
INFOsample.spring.chapter11.web.FixedDepositController–getNewFixedDepositDetails()method:Returninganewinstanceof
FixedDepositDetails
INFOsample.spring.chapter11.web.FixedDepositController–listFixedDeposits()method:Gettinglistoffixeddeposits
The above output shows that the getNewFixedDepositDetails method (which is annotated with
@ModelAttributeannotation)isinvokedfirst,followedbythelistFixedDeposits(whichisannotatedwith
both@ModelAttributeand@RequestMappingannotation).
Let’s now look at how model attributes are retrieved from the Model object using @ModelAttribute
annotationonamethodargument.
Retrievingmodelattributesusing@ModelAttributeannotation
You can use @ModelAttribute annotation on arguments of a @RequestMapping annotated method to
retrievemodelattributesfromtheModelobject.
The following example listing shows FixedDepositController’s openFixedDeposit method that uses
@ModelAttributeannotationtoretrievenewFixedDepositDetailsobjectfromtheModelobject:
Examplelisting11-9–@ModelAttributeannotationonamethodargument
Project–ch11-bankapp
Sourcelocation-src/main/java/sample/spring/chapter11/web
packagesample.spring.chapter11.web;
.....
@Controller
@RequestMapping(value="/fixedDeposit")
.....
publicclassFixedDepositController{
.....
@ModelAttribute(value="newFixedDepositDetails")
publicFixedDepositDetailsgetNewFixedDepositDetails(){
.....
logger.info("getNewFixedDepositDetails()method:Returninganewinstanceof
FixedDepositDetails");
.....
}
.....
@RequestMapping(params="fdAction=create",method=RequestMethod.POST)
publicStringopenFixedDeposit(
@ModelAttribute(value="newFixedDepositDetails")
FixedDepositDetailsfixedDepositDetails,.....){
.....
fixedDepositService.saveFixedDeposit(fixedDepositDetails);
logger.info("openFixedDeposit()method:Fixeddepositdetailssuccessfullysaved.
Redirectingtoshowthelistoffixeddeposits.");
.....
}
}
.....
}
Intheaboveexamplelisting,@ModelAttributeannotatedgetNewFixedDepositDetailsmethodisinvoked
before @RequestMapping annotated openFixedDeposit method. When the getNewFixedDepositDetails
methodisinvoked,thereturnedFixedDepositDetails instance is stored inthe Model object with name
newFixedDepositDetails. Now, the openFixedDeposit method’s fixedDepositDetails argument is
annotated with @ModelAttribute(value="newFixedDepositDetails"); therefore, the
newFixedDepositDetails object is obtained from the Model object and assigned to the
fixedDepositDetailsargument.
If you look at the FixedDepositController’s openFixedDeposit method, you’ll notice that we have not
writtenanylogicto obtain valuesoftenure, amountand email fieldsfrom therequestandpopulatethe
newFixedDepositDetailsinstance.ThisisbecausetheSpring’sWebDataBinderobject(explainedlaterin
this chapter) is responsible for transparently retrieving request parameters from the request and
populating the fields (with matching names) of newFixedDepositDetails instance. For instance, if a
requestparameternamedtenureisfoundintherequest,WebDataBindersetsthevalueoftenurefieldof
newFixedDepositDetailsinstancetothevalueoftenurerequestparameter.
Figure 11-1 summarizes the sequence of actions that are performed by Spring when a request is
dispatchedtoFixedDepositController’sopenFixedDepositmethod.
Figure 11-1 Order in which @ModelAttribute and @RequestMapping annotated methods of
FixedDepositControllerareinvoked
Intheabovefigure,theRequestMappingHandlerAdapterobjectofSpringWebMVCisresponsiblefor
invoking @ModelAttribute and @RequestMapping annotated methods of a controller. At first, the
getNewFixedDepositDetailsmethodisinvokedandthereturnedFixedDepositDetailsinstanceisstoredin
the Model object with name newFixedDepositDetails. Next, the newFixedDepositDetails instance is
retrievedfromtheModelandpassedasanargumenttotheopenFixedDepositmethod.
Let’snowlookatwhattimesduringtheprocessingofarequesta@ModelAttributeannotatedmethodis
invoked.
Requestprocessingand@ModelAttributeannotatedmethods
In example listing 11-6, we saw that the execution of listFixedDeposits method logs the following
message:
listFixedDeposits()method:Gettinglistoffixeddeposits
In example listing 11-9, we saw that the execution of getNewFixedDepositDetails method logs the
followingmessage:
getNewFixedDepositDetails()method:ReturninganewinstanceofFixedDepositDetails
And,theopenFixedDepositmethodlogsthefollowingmessage:
openFixedDeposit() method: Fixed deposit details successfully saved. Redirecting to show the list of
fixeddeposits
To see the order in which the listFixedDeposits, getNewFixedDepositDetails and openFixedDeposit
methodsareinvoked,deploythech11-bankappprojectandfollowthesesteps:
1. Go to http://localhost:8080/ch11-bankapp/fixedDeposit/list URL. You’ll see the list of fixed
depositsinthesystemandthe‘CreatenewFixedDeposit’button(referfigure10-8ofchapter10).
2.Clickthe‘CreatenewFixedDeposit’buttonthatshowstheHTMLformforopeninganewfixed
deposit(referfigure10-9ofchapter10).
3.Enterfixeddepositdetailsandclickthe‘Save’button.Ifnovalidationerrors are found inthe
entered data, the fixeddepositdetailsaresuccessfullysavedand the list offixeddepositsinthe
system(whichincludesthenewlycreatedfixeddeposit)isdisplayedonceagain.
The following table describes the actions performed by you and the corresponding messages that are
printedbytheMyBankapplicationontheconsole:
Action Messagesprintedontheconsole
Gotohttp://localhost:8080/ch11-
bankapp/fixedDeposit/listURL
getNewFixedDepositDetails() method: Returning a new instance of
FixedDepositDetails
listFixedDeposits()method:Gettinglistoffixeddeposits
Clickthe‘CreatenewFixedDeposit’
button
getNewFixedDepositDetails() method: Returning a new instance of
FixedDepositDetails
showOpenFixedDepositForm()method:Showingformforopeninganewfixed
deposit
Enter fixed deposit details and click
the‘Save’button
getNewFixedDepositDetails() method: Returning a new instance of
FixedDepositDetails
openFixedDeposit() method: Fixed deposit details successfully saved.
Redirectingtoshowthelistoffixeddeposits.
getNewFixedDepositDetails() method: Returning a new instance of
FixedDepositDetails
listFixedDeposits()method:Gettinglistoffixeddeposits
Theabovetableshowsthatthe@ModelAttributeannotatedgetNewFixedDepositDetailsmethodiscalled
beforeeachinvocationof@RequestMappingannotatedmethodoftheFixedDepositControllerclass.As
the getNewFixedDepositDetails method creates a new instance of FixedDepositDetails object, a new
instance of FixedDepositDetails object is created each time a request is handled by the
FixedDepositController.
Ifa@ModelAttributeannotatedmethodfiresSQLqueriesorinvokesanexternalwebservicetopopulate
the modelattribute returned bythe method,multiple invocations of@ModelAttribute annotated method
willadverselyaffecttheperformanceoftheapplication.Laterinthischapter,we’llseethatyoucanuse
@SessionAttributes annotation to avoid multiple invocations of a @ModelAttribute annotated method.
@SessionAttributes annotation instructs Spring to cache the object returned by the @ModelAttribute
annotatedmethod.
Let’s now look at a scenario in which the model attribute referred by the @ModelAttribute annotated
methodargumentisnotfoundintheModelobject.
Behaviorof@ModelAttributeannotatedmethodarguments
We saw earlier that the @ModelAttribute annotation can be used on a method argument to retrieve a
modelattributefromtheModelobject.Ifthemodelattributespecifiedbythe@ModelAttributeannotation
is not found in the Model, Spring automatically creates a new instance of the method argument type,
assigns itto the method argument and also puts it intothe Model object. To allow Spring to create an
instance of the method argument type, the Java class of the method argument type must provide a no-
argumentconstructor.
Let’sconsiderthefollowingSomeControllercontrollerthatdefinesasingle@RequestMappingmethod,
doSomething:
Examplelisting11-10–@ModelAttributeargumentisnotavailableintheModelobject
@Controller
@RequestMapping(value="/some")
publicclassSomeController{
.....
@RequestMapping("/do")
publicvoiddoSomething(@ModelAttribute("myObj")MyObjectmyObject){
logger.info(myObject);
.....
}
}
The above example listing shows that the SomeController class doesn’t define any @ModelAttribute
annotatedmethodthataddsanobjectnamedmyObjoftypeMyObjectintheModel.Forthisreason,when
arequestfordoSomethingmethodisreceived,SpringcreatesaninstanceofMyObject,assignsittothe
myObjectargumentandalsoputsthenewlycreatedMyObjectinstanceintotheModelobject.
Let’snowlookatSpring’sRequestToViewNameTranslatorobject.
RequestToViewNameTranslator
RequestToViewNameTranslatordeterminestheviewtoberenderedwhena@RequestMappingannotated
methoddoesn’texplicitlyspecifytheviewtoberendered.
We saw earlier that when a @RequestMapping method is also annotated with @ModelAttribute
annotation,thevaluereturnedby themethodisconsideredasamodelattribute.Insuch asituation,the
RequestToViewNameTranslatorobjectisresponsiblefordeterminingtheviewtoberenderedbasedon
the incoming web request. Similarly, if a @RequestMapping annotated method returns void,
org.springframework.ui.Model or java.util.Map, the RequestToViewNameTranslator object determines
theviewtoberendered.
DefaultRequestToViewNameTranslator is an implementation of RequestToViewNameTranslator that is
usedbydefaultbyDispatcherServlet todetermine theview toberendered when no view is explicitly
returnedbya@RequestMappingmethod.DefaultRequestToViewNameTranslatorusestherequestURIto
determine the name of the logical view to render. DefaultRequestToViewNameTranslator removes the
leadingandtrailingslashesandthefileextensionfromtheURItodeterminetheviewname.Forinstance,
iftheURLishttp://localhost:8080/doSomething.htm,theviewnamebecomesdoSomething.
In case of MyBank web application, the FixedDepositController’s listFixedDeposits method (refer
examplelisting11-6orFixedDepositController.javafileofch11-bankappproject)isannotatedwithboth
@RequestMapping and @ModelAttribute; therefore, RequestToViewNameTranslator is used by the
DispatcherServlettodeterminetheviewtorender.AsthelistFixedDepositsmethodismappedtorequest
URI/fixedDeposit/list,RequestToViewNameTranslatorreturns/fixedDeposit/listastheviewname.The
ViewResolver configured in the web application context XML file of MyBank web application (refer
bankapp-config.xml file of ch11-bankapp project) maps /fixedDeposit/list view name to /WEB-
INF/jsp/fixedDeposit/list.jspJSPview.
Let’snowlookat@SessionAttributesannotation.
11-3Cachingmodelattributesusing@SessionAttributesannotation
In the previous section, we saw that all the @ModelAttribute annotated methods of a controller are
alwaysinvokedbeforethe@RequestMappingannotatedmethod.Thisbehaviormaynotbeacceptablein
situations in which @ModelAttribute methods obtain data from the database or from an external web
service to populate the model attribute. In such scenarios, you can annotate your controller class with
@SessionAttributesannotationthatspecifiesthemodelattributesthatarestoredinHttpSessionbetween
requests.
If @SessionAttributes annotation is used, a @ModelAttribute annotated method is invoked only if the
model attribute specified by the @ModelAttribute annotation is not found in the HttpSession. Also,
@ModelAttribute annotation on a method argument will result in creation of a new instance of model
attributeonlyifthemodelattributeisnotfoundintheHttpSession.
IMPORTchapter11/ch11-session-attributes(Thisprojectshowsamodifiedversionofch11-bankapp
projectthatuses@SessionAttributesannotationtotemporarilystoremodelattributesinHttpSession.The
MyBankwebapplicationfunctionalityofferedbych11-session-attributesandch10-bankappprojectsare
the same. If you deploy the project on Tomcat server and access the URL http://localhost:8080/ch11-
session-attributes,you’llseethelistoffixeddepositsinthesystem.)
Thefollowingexamplelistingshowsusageof@SessionAttributesannotationinch11-session-attributes
project to temporarily store newFixedDepositDetails and editableFixedDepositDetails model attributes
inHttpSession:
Examplelisting11-11–@SessionAttributesannotationusage
Project–ch11-session-attributes
Sourcelocation-src/main/java/sample/spring/chapter11/web
packagesample.spring.chapter11.web;
importorg.springframework.web.bind.annotation.SessionAttributes;
.....
@SessionAttributes(value={"newFixedDepositDetails","editableFixedDepositDetails"})
publicclassFixedDepositController{
.....
@ModelAttribute(value="newFixedDepositDetails")
publicFixedDepositDetailsgetNewFixedDepositDetails(){
FixedDepositDetailsfixedDepositDetails=newFixedDepositDetails();
fixedDepositDetails.setEmail("Youmustenteravalidemail");
returnfixedDepositDetails;
}
.....
@RequestMapping(params="fdAction=create",method=RequestMethod.POST)
publicStringopenFixedDeposit(
@ModelAttribute(value="newFixedDepositDetails")FixedDepositDetails
fixedDepositDetails,
.....){.....}
.....
@RequestMapping(params="fdAction=view",method=RequestMethod.GET)
publicModelAndViewviewFixedDepositDetails(
@RequestParam(value="fixedDepositId")intfixedDepositId){
FixedDepositDetailsfixedDepositDetails=fixedDepositService
.getFixedDeposit(fixedDepositId);
Map<String,Object>modelMap=newHashMap<String,Object>();
modelMap.put("editableFixedDepositDetails",fixedDepositDetails);
.....
returnnewModelAndView("editFixedDepositForm",modelMap);
}
}
@SessionAttributes annotation’s value attribute specifies names of the model attributes that are
temporarily stored in HttpSession. In the above example listing, model attributes named
newFixedDepositDetails and editableFixedDepositDetails are stored in HttpSession between requests.
The newFixedDepositDetails model attribute is returned by @ModelAttribute annotated
getNewFixedDepositDetailsmethod,andtheeditableFixedDepositDetailsmodelattributeisreturnedby
the@RequestMappingannotatedviewFixedDepositDetailsmethod.
A controller contributes model attributes via @ModelAttribute annotated methods, @RequestMapping
methods (that return ModelAndView, Model or Map), and by directly adding model attributes to the
Modelobject.Themodelattributescontributedbythecontrollerthroughanyapproacharecandidatefor
storageintheHttpSessionby@SessionAttributesannotation.
When using @SessionAttributes annotation, you should ensure that the model attributes stored in the
HttpSession are removed when they are no longer required. For instance, the newFixedDepositDetails
model attribute represents an instance of FixedDepositDetails that is used by the ‘Open fixed deposit’
form to show the default value(s) of Email form field as ‘You must enter a valid email’ (refer
getNewFixedDepositDetails method in example listing 11-11). Also, when the user clicks the ‘Save’
button on the ‘Open fixed deposit’ form, the fixed deposit details entered by the user are set on the
newFixedDepositDetails instance (refer openFixedDepositmethod in example listing 11-11). After the
fixed deposit is successfully created, the newFixedDepositDetails instance is no longer required;
therefore, it must be removed from the HttpSession. Similarly, editableFixedDepositDetails model
attributeisnotrequiredafteryouhavesuccessfullymodifieddetailsofafixeddeposit.
You can instruct Spring to remove all the model attributes stored in HttpSession by calling
setComplete method of Spring’s SessionStatus object. The following example listing shows
FixedDepositController’sopenFixedDeposit and editFixedDeposit methods that invoke SessionStatus’s
setCompletemethodafterafixeddepositissuccessfullycreatedormodified:
Examplelisting11-12–RemovingmodelattributesfromHttpSessionusingSessionStatusobject
Project–ch11-session-attributes
Sourcelocation-src/main/java/sample/spring/chapter11/web
packagesample.spring.chapter11.web;
importorg.springframework.web.bind.support.SessionStatus;
.....
@SessionAttributes(value={"newFixedDepositDetails","editableFixedDepositDetails"})
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=create",method=RequestMethod.POST)
publicStringopenFixedDeposit(
@ModelAttribute(value="newFixedDepositDetails")FixedDepositDetailsfixedDepositDetails,
.....,SessionStatussessionStatus){
fixedDepositService.saveFixedDeposit(fixedDepositDetails);
sessionStatus.setComplete();
}
}
@RequestMapping(params="fdAction=edit",method=RequestMethod.POST)
publicStringeditFixedDeposit(
@ModelAttribute("editableFixedDepositDetails")FixedDepositDetailsfixedDepositDetails,
.....,SessionStatussessionStatus){
fixedDepositService.editFixedDeposit(fixedDepositDetails);
sessionStatus.setComplete();
.....
}
}
.....
}
TheaboveexamplelistingshowsthatbothopenFixedDepositandeditFixedDepositmethodsaredefined
toacceptanargumentoftype SessionStatus. Whena@RequestMapping annotated method specifies an
argumentoftypeSessionStatus,SpringsuppliesaninstanceofSessionStatustothemethod.Thecallto
setComplete method instructs Spring to remove the current controller’s model attributes from the
HttpSessionobject.
In examplelisting 11-11and11-12, we saw thatthe @SessionAttributes’s value attribute specifies the
namesofmodelattributesthataretemporarilystoredinHttpSession.Ifyouwantthatonlycertaintypesof
modelattributesarestoredinHttpSession,youcanuse@SessionAttributes’stypesattribute.Forinstance,
the following @SessionAttributes annotation specifies that attributes named x and y, and all model
attributesthatareoftypeMyObject,aretemporarilystoredinHttpSession:
@SessionAttributes(value={"x","y"},types={MyObject.class})
You can see the order in which listFixedDeposits, getNewFixedDepositDetails and openFixedDeposit
methodsareinvokedbydeployingch11-session-attributesproject andperformtheactions described in
thefollowingtable:
Action Messagesprintedontheconsole
Gotohttp://localhost:8080/ch11-
session-attributes/fixedDeposit/list
URL
getNewFixedDepositDetails()method:Returninganewinstanceof
FixedDepositDetails
listFixedDeposits()method:Gettinglistoffixeddeposits
Clickthe‘CreatenewFixedDeposit’
button
showOpenFixedDepositForm()method:Showingformforopeninganewfixed
deposit
Enterfixeddepositdetailsandclick
the‘Save’button
openFixedDeposit()method:Fixeddepositdetailssuccessfullysaved.
Redirectingtoshowthelistoffixeddeposits.
getNewFixedDepositDetails()method:Returninganewinstanceof
FixedDepositDetails
listFixedDeposits()method:Gettinglistoffixeddeposits
In ch11-bankapp project, we saw that the @ModelAttribute annotated getNewFixedDepositDetails
method of FixedDepositController was invoked each time a request was dispatched to
FixedDepositController.TheabovetableshowsthatthegetNewFixedDepositDetailsmethodisinvoked
when request is handled by the FixedDepositController for the first time. As the openFixedDeposit
method removes the model attributes stored in the HttpSession, request to listFixedDeposits method
resultsininvocationofgetNewFixedDepositDetailsmethodonceagain.
Now,thatwehaveseenhowtouse@ModelAttributeand@SessionAttributesannotations,let’slookat
howdatabindingisperformedinSpringWebMVCapplications.
11-4DatabindingsupportinSpring
WhenaformissubmittedinaSpringWebMVCapplication,requestparameterscontainedintherequest
areautomaticallysetonthemodelattributethatactsastheformbackingobject.Thisprocessofsetting
requestparametersontheformbackingobjectisreferredtoasdatabinding.Inthissection,we’lllookat
Spring’sWebDataBinderinstancethatbindsrequestparameterstoformbackingobjects.
IMPORTchapter 11/ch11-data-binding (This project shows a modified version of ch11-session-
attributesprojectthatshowshowtoregisterPropertyEditorimplementationswithSpringcontainer.Ifyou
deploytheprojectonTomcatserverandaccesstheURLhttp://localhost:8080/ch11-data-binding,you’ll
seethelistoffixeddepositsinthesystem.)
ThefollowingexamplelistingshowstheFixedDepositDetailsclassofch11-data-bindingproject:
Examplelisting11-13–FixedDepositDetailsclass
Project–ch11-data-binding
Sourcelocation-src/main/java/sample/spring/chapter11/web
packagesample.spring.chapter11.domain;
importjava.util.Date;
publicclassFixedDepositDetails{
.....
privatelongdepositAmount;
privateDatematurityDate;
.....
publicvoidsetDepositAmount(longdepositAmount){
this.depositAmount=depositAmount;
}
publicvoidsetMaturityDate(DatematurityDate){
this.maturityDate=maturityDate;
}
.....
}
The above example listing shows that the depositAmount and maturityDate fields are of type long and
java.util.Date,respectively.ThevaluesofdepositAmountandmaturityDatefieldsaresetwhenthe‘Open
fixeddeposit’formofch11-data-bindingprojectissubmitted.Thefollowingfigureshowsthe‘Openfixed
deposit’formofch11-data-bindingprojectthatisusedforopeningnewfixeddeposits:
Figure11-2‘Openfixeddeposit’formforopeningnewfixeddeposits
Intheabovefigure,‘Amount(inUSD)’and‘Maturitydate’formfieldscorrespondtodepositAmountand
maturityDate fields of FixedDepositDetails class (refer example listing 11-13). One of the important
thingstonoteisthatthe‘Maturitydate’fieldacceptsadateintheformat‘MM-dd-yyyy’,like01-27-2013.
AsdepositAmountfieldisoftypelong,andmaturityDateisoftypejava.util.Date,Spring’sdatabinding
mechanism is responsible for doing the type conversion from String to the type defined by the
FixedDepositDetailsinstance.
ThefollowingexamplelistingshowsFixedDepositController’sopenFixedDepositmethodthatisinvoked
whenauserfillsthe‘Openfixeddeposit’formandclicksthe‘Save’button(referfigure11-2):
Examplelisting11-14–FixedDepositController-Automaticdatabindingexample
Project–ch11-data-binding
Sourcelocation-src/main/java/sample/spring/chapter11/web
packagesample.spring.chapter11.web;
@Controller
.....
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=create",method=RequestMethod.POST)
publicStringopenFixedDeposit(
@ModelAttribute(value = "newFixedDepositDetails") FixedDepositDetails
fixedDepositDetails,
BindingResultbindingResult,SessionStatussessionStatus){
....
}
.....
}
In the above example listing, the @ModelAttribute annotated FixedDepositDetails argument represents
theformbackingobjectonwhichtherequestparametersaresetwhenthe‘Openfixeddeposit’formis
submitted. Spring’s WebDataBinder instance binds request parameters to the FixedDepositDetails
instance.
Let’snowlookathowWebDataBinderperformsdatabinding.
WebDataBinder–databinderforwebrequestparameters
WebDataBinderusestherequestparameternametofindthecorrespondingJavaBean-stylesettermethod
ontheformbackingobject.IfaJavaBean-stylesettermethodisfound,WebDataBinderinvokesthesetter
methodandpassestherequestparametervalueasanargumenttothesettermethod.Ifthesettermethodis
defined to accept a non-String type argument, WebDataBinder uses an appropriate PropertyEditor to
performthetypeconversion.
The following example listing shows the MyObject class that acts as a form backing object in an
application:
Examplelisting11-15–MyObjectclass–aformbackingobject
publicclassMyObject{
privateStringx;
privateNy;
.....
publicvoidsetX(Stringx){
this.x=x;
}
publicvoidsetY(Ny){
this.y=y;
}
}
TheaboveexamplelistingshowsthattheMyObjectclassdefinespropertiesnamedxandyoftypeString
andN,respectively.
The following figure shows how WebDataBinder binds request parameters named x and y to x and y
propertiesofMyObjectinstance:
Figure11-3WebDataBinderperformsdatabindingbyusingregisteredPropertyEditorstoperformtype
conversion
TheabovefigureshowsthattheWebDataBinderusesaPropertyEditortoconvertStringvaluebtotype
N,beforecallingthesetYmethodofMyObjectinstance.
Springprovidesacoupleofbuilt-inPropertyEditorimplementationsthatareusedbyWebDataBinderfor
converting String type request parameter value to the type defined by the form backing object. For
instance,CustomNumberEditor,FileEditor,CustomDateEditor are some of the built-in PropertyEditors
provided by Spring. For a complete list of built-in PropertyEditors, refer to
org.springframework.beans.propertyeditorspackage.
CustomNumberEditorisusedforconvertingaStringvaluetoajava.lang.Numbertype,likeInteger,Long,
Double,andsoon.CustomDateEditorisusedforconvertingaStringvaluetoajava.util.Datetype.You
canpassajava.text.DateFormatinstancetoCustomDateEditortospecifythedateformattobeusedfor
parsing and rendering dates. Both these PropertyEditors are required in ch11-data-binding project
because we need to convert request parameter values to depositAmount (which is of type long) and
maturityDate (which is of type java.util.Date). CustomNumberEditor is pre-registered with the
WebDataBinderinstancebutyouneedtoexplicitlyregisterCustomDateEditor.
Let’s now look at how you can configure a WebDataBinder instance and register a PropertyEditor
implementationwithit.
ConfiguringaWebDataBinderinstance
YoucanconfigureaWebDataBinderinstanceby:
·definingan@InitBinderannotatedmethodinthecontrollerclass
·configuringaWebBindingInitializerimplementationinthewebapplicationcontextXMLfile
·definingan@InitBinderannotatedmethodina@ControllerAdviceannotatedclass
Let’s look at each of the above mentioned approach for configuring a WebDataBinder instance and
registeringaPropertyEditorwithit.
Definingan@InitBinderannotatedmethodinthecontrollerclass
An@InitBinderannotatedmethodinacontrollerclassspecifiesthatthemethodinitializesaninstanceof
WebDataBinderthatwillbeusedbythecontrollerduringdatabinding.Thevalueattributeof@InitBinder
annotationspecifiesthename(s)ofthemodelattributetowhichtheinitializedWebDataBinderinstance
applies.
ThefollowingexamplelistingshowsFixedDepositController’sinitBinder_Newmethodthatisannotated
with@InitBinder:
Examplelisting11-16–FixedDepositController-@InitBinderannotationusage
Project–ch11-data-binding
Sourcelocation-src/main/java/sample/spring/chapter11/web
packagesample.spring.chapter11.web;
importjava.text.SimpleDateFormat;
importorg.springframework.beans.propertyeditors.CustomDateEditor;
importorg.springframework.web.bind.WebDataBinder;
importorg.springframework.web.bind.annotation.InitBinder;
@Controller
.....
publicclassFixedDepositController{
.....
@ModelAttribute(value="newFixedDepositDetails")
publicFixedDepositDetailsgetNewFixedDepositDetails(){.....}
@InitBinder(value="newFixedDepositDetails")
publicvoidinitBinder_New(WebDataBinderwebDataBinder){
webDataBinder.registerCustomEditor(Date.class,
newCustomDateEditor(newSimpleDateFormat("MM-dd-yyyy"),false));
}
.....
}
In the above example listing, the @InitBinder annotation’s value attribute is set to
newFixedDepositDetails,whichmeansthattheWebDataBinderinitializedbytheinitBinder_Newmethod
applies only to the newFixedDepositDetails model attribute. An @InitBinder annotated method can
acceptsamesetofarguments(likeHttpServletRequest,SessionStatus,andsoon)thatcanbepassedtoa
@RequestMappingannotatedmethod.But,an@InitBinderannotated methodcan’tbedefinedto accept
modelattributesandBindingResult(orErrors)objectsasarguments.Typically,WebDataBinderinstance,
alongwith Spring’sWebRequestor java.util.Locale instance,ispassedtoan@InitBinder method. You
shouldnotethatthereturntypeofan@InitBindermethodmustbevoid.
WebDataBinder’s registerCustomEditor method is used for registering a PropertyEditor with the
WebDataBinderinstance.Inexamplelisting11-16,initBinder_NewmethodregistersCustomDateEditor
(aPropertyEditor)withtheWebDataBinderinstance.
You can define an @InitBinder annotated method for each model attribute of a controller, or you can
defineasingle@InitBinderannotatedmethodthatappliestoallthemodelattributesofthecontroller.If
youdon’tspecifythevalueattributeof@InitBinderannotation,theWebDataBinderinstanceinitializedby
themethodisapplicabletoallthemodelattributesofthecontroller.
ConfiguringaWebBindingInitializerimplementation
AWebDataBinder instance is first initialized by RequestMappingHandlerAdapter, followed by further
initializationbyWebBindingInitializerand@InitBindermethods.
The <annotation-driven> element of Spring’s mvc schema creates an instance of Spring’s
RequestMappingHandlerAdapterthatinitializestheWebDataBinder.Youcansupplyanimplementationof
Spring’s WebBindingInitializer interface to RequestMappingHandlerAdapter to further initialize
WebDataBinderinstances.Youcanadditionallyuse@InitBindermethodsinacontrollerclasstofurther
initializeWebDataBinderinstances.
The following figure shows the sequence in which RequestMappingHandlerAdapter,
WebBindingInitializerand@InitBindermethodsinitializeaWebDataBinderinstance:
Figure 11-4 The sequence in which a WebDataBinder instance is initialized by
RequestMappingHandlerAdapter,WebBindingInitializerand@InitBindermethodsofacontrollerclass
WebDataBinderinitializationbyan@InitBindermethod ofa controllerclass is applicable only tothat
controller’smodelattributes.Forinstance,ifyouusean@InitBindermethodincontrollerX to set the
CustomDateEditorpropertyeditorontheWebDataBinderinstance,thentheCustomDateEditor property
editor will be available only to the model attributes of controller X during data binding. In MyBank
application, the CustomDateEditor was required only by the model attributes of the
FixedDepositController; therefore, we used @InitBinder annotated methods in the
FixedDepositControllerclasstoregisterCustomDateEditorwithWebDataBinderinstance.
Spring’s WebBindingInitializer is a callback interface whose implementation is responsible for
initializingaWebDataBinderwiththeconfigurationthatappliestoallthecontrollers(andtherebytoall
the model attributes) in the application. Let’s look at how to configure a custom WebBindingInitializer
whenusing<annotation-driven>elementofSpring’smvcschema.
The <annotation-driven> element of Spring’s mvc schema creates and registers
RequestMappingHandlerAdapterandRequestMappingHandlerMappingobjectswiththeSpringcontainer.
The other objects that are configured by <annotation-driven> element are LocalValidatorFactoryBean
(explained in section 11-5) and FormattingConversionServiceFactoryBean (explained in section 13-5).
The <annotation-driven> element provides couple of attributes that help you customize
RequestMappingHandlerAdapterandRequestMappingHandlerMappingobjects.Ifthecustomizationyou
want to make to RequestMappingHandlerAdapter or RequestMappingHandlerMapping object is not
providedbythe<annotation-driven>element,theonlyoptionistoremove<annotation-driven>element
and explicitly configure RequestMappingHandlerAdapter and RequestMappingHandlerMapping objects
inthewebapplicationcontextXMLfile.As<annotation-driven>elementdoesn’tprovideanyoptionto
supply a custom WebBindingInitializer instance to the RequestMappingHandlerAdapter object, you’ll
have to explicitly configure RequestMappingHandlerAdapter and RequestMappingHandlerMapping
objectsinthewebapplicationcontextXMLfile.
The following example listing shows howyoucanuse Spring’s ConfigurableWebBindingInitializer (an
implementationofWebBindingInitializer)tomakeCustomDateEditorpropertyeditoravailabletoallthe
controllersintheMyBankapplication:
Examplelisting11-17–WebBindingInitializerconfiguration
<beanid="handlerAdapter"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<propertyname="webBindingInitializer"ref="myInitializer"/>
</bean>
<beanid="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"
/>
<beanid="myInitializer"
class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<propertyname="propertyEditorRegistrars">
<list>
<beanclass="mypackage.MyPropertyEditorRegistrar"/>
</list>
</property>
</bean>
The above example listing shows that RequestMappingHandlerAdapter and
RequestMappingHandlerMappingbeansareexplicitlydefinedinthewebapplicationcontextXMLfile.
The RequestMappingHandlerAdapter’s webBindingInitializer property refers to the
ConfigurableWebBindingInitializer bean that implements WebBindingInitializer interface.
ConfigurableWebBindingInitializer’spropertyEditorRegistrarspropertyspecifiesclassesthatregisterone
or more PropertyEditors with WebDataBinder. The following example listing shows how
MyPropertyEditorRegistrarclassregistersCustomDateEditorpropertyeditorwithWebDataBinder:
Examplelisting11-18–MyPropertyEditorRegistrarclass
importorg.springframework.beans.PropertyEditorRegistrar;
importorg.springframework.beans.PropertyEditorRegistry;
importorg.springframework.beans.propertyeditors.CustomDateEditor;
publicclassMyPropertyEditorRegistrarimplementsPropertyEditorRegistrar{
@Override
publicvoidregisterCustomEditors(PropertyEditorRegistryregistry){
registry.registerCustomEditor(Date.class,newCustomDateEditor(
newSimpleDateFormat("MM-dd-yyyy"),false));
}
}
The above example listing shows that the MyPropertyEditorRegistrar class implements Spring’s
PropertyEditorRegistrar interface, and provides implementation for registerCustomEditors method
defined in the PropertyEditorRegistrar interface. The PropertyEditorRegistry instance passed to the
registerCustomEditors method is used for registering property editors. PropertyEditorRegistry’s
registerCustomEditor method is used for registering a PropertyEditor implementation with the
WebDataBinder.Intheaboveexamplelisting,PropertyEditorRegistry’sregisterCustomEditorisusedfor
registeringtheCustomDateEditorpropertyeditorwiththeWebDataBinder.
As we saw, using WebBindingInitializer for initializing WebDataBinder is quite an involved task. A
simpler alternative to using WebBindingInitializer is to define @InitBinder annotated methods in a
@ControllerAdviceannotatedclass.
Definingan@InitBindermethodina@ControllerAdviceannotatedclass
Like @Service, @Controller and @Repository annotations, @ControllerAdvice annotation is a
specializedformof@Componentannotation.The@ControllerAdviceannotationonaclassindicatesthat
the class provides support to controllers. You can define @InitBinder, @ModelAttribute and
@ExceptionHandler annotated methods in the @ControllerAdvice annotated class, and these annotated
methods apply to all the annotated controllers in the application. As with @Service, @Controller and
@Repositoryannotations,<classpath-scanning>elementofSpring’scontextschemaautomaticallydetects
andregisters@ControllerAdviceannotatedclasseswiththeSpringcontainer.
Ifyounoticethatyouareduplicating@InitBinder,@ModelAttributeand@ExceptionHandlermethodsin
multiple controllers, then considerdefiningsuch methodsina@ControllerAdvice annotated class. For
instance, if you want to initialize the WebDataBinder with the configuration that applies tomultiple
controllersintheapplication,thendefinean@InitBindermethodina@ControllerAdviceannotatedclass
insteadofdefiningan@InitBindermethodinmultiplecontrollerclasses.
ThefollowingtablesummarizesthethreeapproachesthatwediscussedforinitializingWebDataBinder:
@InitBindermethodincontroller
class WebBindingInitializer @InitBinder method in
@ControllerAdviceclass
Requires defining an @InitBinder
methodinacontroller
Requires explicitly configuring
RequestM appingHandlerAdapterintheweb
applicationcontextXM Lfile
Requires defining an @InitBinder
method in a @ControllerAdvice
annotatedclass
WebDataBinderinitializationapplies
only to the controller that contains
the@InitBindermethod
WebDataBinder initialization applies to all
theannotatedcontrollersintheapplication
WebDataBinder initialization applies
toalltheannotatedcontrollersinthe
application
Let’snowlookathowyoucanallowordisallowfieldsofamodelattributefromparticipatinginthedata
bindingprocess.
Allowingordisallowingfieldsfromdatabindingprocess
WebDataBinder allows you to specify fields of a model attribute that are allowed or disallowed from
participatinginthedatabindingprocess.Itisstronglyrecommendedthatyouspecifythefieldsofamodel
attribute that are allowed or disallowed from the data binding processes, as failing to do so may
compromisethesecurityofyourapplication.Let’slookatascenarioinwhichwewouldliketoallowor
disallowfieldsfromdatabinding.
InMyBankapplication,whenauserselectsafixeddepositforediting,thedetailsoftheselectedfixed
depositareloadedfromthedatastoreandtemporarilycachedintheHttpSession.Theusermakeschanges
tothefixeddepositandsavesthechanges.Thefollowingexamplelistingshowsthe@RequestMapping
methodsthatareresponsibleforloadingtheselectedfixeddepositandsavingtheupdatedfixeddeposit
information:
Examplelisting11-19–FixedDepositController
Project–ch11-data-binding
Sourcelocation-src/main/java/sample/spring/chapter11/web
packagesample.spring.chapter11.web;
.....
@SessionAttributes(value={"newFixedDepositDetails","editableFixedDepositDetails"})
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=view",method=RequestMethod.GET)
publicModelAndViewviewFixedDepositDetails(
@RequestParam(value="fixedDepositId")intfixedDepositId){
FixedDepositDetailsfixedDepositDetails=fixedDepositService
.getFixedDeposit(fixedDepositId);
Map<String,Object>modelMap=newHashMap<String,Object>();
modelMap.put("editableFixedDepositDetails",fixedDepositDetails);
.....
returnnewModelAndView("editFixedDepositForm",modelMap);
}
.....
@RequestMapping(params="fdAction=edit",method=RequestMethod.POST)
publicStringeditFixedDeposit(
@ModelAttribute("editableFixedDepositDetails")FixedDepositDetailsfixedDepositDetails,){
.....
}
}
In MyBank application, a fixed deposit is uniquely identified by the id field of FixedDepositDetails
object (refer FixedDepositDetails class of ch11-data-binding project). When a user selects a fixed
deposit for editing, the id field value is passed to the viewFixedDepositDetails method via the
fixedDepositIdrequestparameter.TheviewFixedDepositDetailsmethodusesthevalueoffixedDepositId
requestparametertoloadfixeddepositdetailsandshowthemonthe‘Editfixeddeposit’form,asshown
inthefollowingfigure:
Figure11-5‘Editfixeddeposit’formforeditinganexistingfixeddeposit
Astheidvalue(thatcorrespondstoidattributeofFixedDepositDetailsobject)uniquelyidentifiesafixed
depositinthesystem,the‘Editfixeddeposit’formdoesn’tprovideanymechanismtochangeit.Whenthe
user clicks the ‘Save’ button, the FixedDepositController’s editFixedDeposit method is invoked. The
editFixedDepositmethodsavesthechangestothefixeddepositdetail.
WhenFixedDepositController’seditFixedDepositmethodisinvoked,theWebDataBinderinstancebinds
request parameter values to the fields of editableFixedDepositDetails model attribute – the
FixedDepositDetailsobjectthatwasloadedbyviewFixedDepositDetailsmethodandtemporarilystored
inHttpSession(refer@SessionAttributesannotationinexamplelisting11-19).Ifamalicioususersendsa
requestparameternamedidwithvalue10,thentheWebDataBinderwillblindlygoaheadandsettheid
attributeofFixedDepositDetailsobjectto10duringdatabinding.Thisisnotdesirablebecausechanging
idattributeofaFixedDepositDetailsobjectwillcompromiseapplicationdata.
WebDataBinderprovidessetAllowedFieldsandsetDisallowedFieldsmethodsthatyoucanusetosetthe
namesofmodelattributefieldsthatcanandcannotparticipateinthedatabindingprocess.Thefollowing
examplelistingshowstheFixedDepositController’sinitBinder_Editmethodthatspecifiesthattheidfield
ofeditableFixedDepositDetailsmodelattributemustnotparticipateinthedatabindingprocess:
Examplelisting11-20–FixedDepositController–WebDataBinder’ssetDisallowedFieldsmethod
Project–ch11-data-binding
Sourcelocation-src/main/java/sample/spring/chapter11/web
packagesample.spring.chapter11.web;
.....
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=edit",method=RequestMethod.POST)
publicStringeditFixedDeposit(
@ModelAttribute("editableFixedDepositDetails")FixedDepositDetailsfixedDepositDetails,.....)
{
.....
}
.....
@InitBinder(value="editableFixedDepositDetails")
publicvoidinitBinder_Edit(WebDataBinderwebDataBinder){
webDataBinder.registerCustomEditor(Date.class,newCustomDateEditor(
newSimpleDateFormat("MM-dd-yyyy"),false));
webDataBinder.setDisallowedFields("id");
}
}
In the above example listing, the initBinder_Edit method initializes WebDataBinder instance for the
editableFixedDepositDetails model attribute. As the setDisallowedFields method specifies that the id
fieldofeditableFixedDepositDetailsmodelattributeisdisallowedtoparticipateinthebindingprocess,
theidfieldisnotsetevenifarequestparameternamedidiscontainedintherequest.
Let’snowlookatSpring’sBindingResultobjectthatexposeserrorsthatoccurduring databindingand
validation.
InspectingdatabindingandvalidationerrorsusingBindingResultobject
Spring’sBindingResultobjectprovidesacontrollermethodwiththeresultsofbindingrequestparameters
tothemodelattribute’sfields.Forinstance,ifanytypeconversionerroroccursduringdatabinding,they
arereportedbytheBindingResultobject.
ThefollowingexamplelistingshowsFixedDepositController’sopenFixedDepositmethodthatcreatesa
fixeddepositonlyifnoerrorsarereportedbytheBindingResultobject:
Example listing 11-21 – FixedDepositController – checking for binding and validation errors using
BindingResult
Project–ch11-data-binding
Sourcelocation-src/main/java/sample/spring/chapter11/web
packagesample.spring.chapter11.web;
importorg.springframework.validation.BindingResult;
importorg.springframework.web.bind.annotation.ModelAttribute;
.....
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=create",method=RequestMethod.POST)
publicStringopenFixedDeposit(
@ModelAttribute(value="newFixedDepositDetails")FixedDepositDetails
fixedDepositDetails,
BindingResultbindingResult,SessionStatussessionStatus){
.....
if(bindingResult.hasErrors()){
return"createFixedDepositForm";
}else{
fixedDepositService.saveFixedDeposit(fixedDepositDetails);
sessionStatus.setComplete();
return"redirect:/fixedDeposit/list";
}
}
.....
}
In the above example listing, the BindingResult’s hasErrors method returns true if the BindingResult
object holds one or more data binding or validation errors. In section 11-5, we’ll see how validation
errors are stored in the BindingResult object. If errors are reported by the BindingResult object, the
openFixedDepositmethodrendersthe‘Createfixeddeposit’formwithappropriateerrormessages.Ifno
errorsarereported,thefixeddepositdetailsaresavedinthedatastore.
YoushouldnotethattheBindingResultargumentmust immediatelyfollowthemodelattributeargument
whoseBindingResultobjectyouwanttoaccessinthecontrollermethod.Forinstance,inexamplelisting
11-21,theBindingResultargumentimmediatelyfollowsthenewFixedDepositDetailsmodelattribute.The
followingexamplelistingshowsanincorrectorderingofthemodelattributeandtheBindingResultobject
fortheopenFixedDepositmethod:
Examplelisting11-22–IncorrectorderingofthemodelattributeandtheBindingResultobject
.....
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=create",method=RequestMethod.POST)
publicStringopenFixedDeposit(
@ModelAttribute(value = "newFixedDepositDetails") FixedDepositDetails
fixedDepositDetails,
SessionStatussessionStatus,BindingResultbindingResult){
.....
}
.....
}
In the above example listing, the ordering of the newFixedDepositDetails model attribute and the
BindingResultobjectisincorrectbecausetheSessionStatusargumentisdefinedbetweenthem.
Ifacontrollermethodacceptsmultiplemodelattributes,theBindingResultobjectcorrespondingtoeach
modelattributeisspecifiedimmediatelyaftereachmodelattributeargument,asshowninthefollowing
examplelisting:
Examplelisting11-23–MultiplemodelattributesandtheirBindingResultobjects
@RequestMapping
publicStringdoSomething(
@ModelAttribute(value="a")AObjectaObj,BindingResultbindingResultA,
@ModelAttribute(value="b")BObjectbObj,BindingResultbindingResultB,){
.....
}
Theaboveexamplelistingshowsthatbothmodelattributesaandbare immediatelyfollowed bytheir
correspondingBindingResultobjects.
Now,thatwehaveseenthedatabindingprocess,let’slookathowvalidationisperformedinSpringWeb
MVCapplications.
11-5ValidationsupportinSpring
Intheprevioussection,wesawthattheWebDataBinderbindsrequestparameterstomodelattributes.The
nextstepinrequestprocessingistovalidatemodelattributes.InSpringWebMVCapplications,youcan
validate model attributes using Spring Validation API (discussed in section 6-9 of chapter 6) or by
specifyingJSR303(BeanValidationAPI)constraints(discussedinsection6-10ofchapter6)onfields
ofmodelattributes.
NOTE In this chapter, Spring Validation API and JSR 303 (Bean Validation API) have been used to
validateformbackingobjects(whicharemodelattributes)intheweblayeroftheapplication.Youshould
notethatbothJSR303(BeanValidationAPI)andSpringValidationAPIcanbeusedtovalidateobjects
inanyapplicationlayer.
Let’sfirstlookathowtovalidatemodelattributesusingSpringValidationAPI’sValidatorinterface.
ValidatingmodelattributesusingSpring’sValidatorinterface
ThefollowingexamplelistingshowstheFixedDepositDetailsValidatorclassofMyBankapplicationthat
validatesFixedDepositDetailsobject:
Examplelisting11-24–FixedDepositDetailsValidator–Spring’sValidatorinterfaceusage
Project–ch11-data-binding
Sourcelocation-src/main/java/sample/spring/chapter11/web
packagesample.spring.chapter11.web;
importorg.springframework.validation.*;
importsample.spring.chapter11.domain.FixedDepositDetails;
publicclassFixedDepositDetailsValidatorimplementsValidator{
publicbooleansupports(Class<?>clazz){
returnFixedDepositDetails.class.isAssignableFrom(clazz);
}
publicvoidvalidate(Objecttarget,Errorserrors){
FixedDepositDetailsfixedDepositDetails=(FixedDepositDetails)target;
longdepositAmount=fixedDepositDetails.getDepositAmount();
.....
if(depositAmount<1000){
errors.rejectValue("depositAmount","error.depositAmount.less",
"mustbegreaterthanorequalto1000");
}
if(email==null||"".equalsIgnoreCase(email)){
ValidationUtils.rejectIfEmptyOrWhitespace(errors,"email","error.email.blank",
"mustnotbeblank");
}
.....
}
}
Spring’sValidator interface defines supports and validate methods. The supports method checks if the
supplied object instance (represented by the clazz attribute) can be validated. If the supports method
returns true, the validate method is used to validate the object. In the above example listing, the
FixedDepositDetailsValidator’s supports method checks if the supplied object instance is of type
FixedDepositDetails. If the supports method returns true, the FixedDepositDetailsValidator’s validate
method validates the object. The validate method accepts the object instance to be validated, and an
Errorsinstance.Errorsinstance storesandexposeserrorsthatoccurduring validation.Errors instance
provides multiple reject and rejectValue methods to register errors with the Errors instance. The
rejectValuemethodsareusedtoreportfield-levelerrors,andrejectmethodsareusedtoreporterrorsthat
apply to the object being validated. Spring’s ValidationUtils class is a utility class that provides
conveniencemethodstoinvokeaValidator,andforrejectingemptyfields.
The following figure describes the parameters that were passed to the rejectValue method in example
listing11-24toreportavalidationerrorcorrespondingtoFixedDepositDetails’sdepositAmountfield:
Figure11-6DescriptionofparametersthatarepassedtorejectValuemethodofErrorsinstancetoreport
validationerrorcorrespondingtodepositAmountfieldofFixedDepositDetails
Theabovefigureshowsthatfieldname,errorcode(whichisbasicallyamessagekey)andadefaulterror
messageispassedtotherejectValuemethod.Inchapter13,we’llseehowthemessagekeysareusedby
JSPpagestoshowmessagesfromresourcebundles.
Youcanvalidatemodelattributesby:
§explicitlyinvokingvalidatemethodonValidatorimplementation
§settingValidatorimplementationonWebDataBinder,andannotatingthemodelattributeargumentin
the@RequestMappingmethodwithJSR303’s@Validannotation
Let’slookateachoftheabovementionedapproachesindetail.
Validatingmodelattributesbyexplicitlycallingvalidatemethod
The following example listing shows the FixedDepositController’sopenFixedDeposit method that uses
FixedDepositDetailsValidator (refer example listing 11-24) to validate FixedDepositDetails model
attribute:
Example listing 11-25 – FixedDepositController– validation by explicitly invoking
FixedDepositDetailsValidator’svalidatemethod
Project–ch11-data-binding
Sourcelocation-src/main/java/sample/spring/chapter11/web
packagesample.spring.chapter11.web;
.....
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=create",method=RequestMethod.POST)
publicStringopenFixedDeposit(
@ModelAttribute(value = "newFixedDepositDetails") FixedDepositDetails
fixedDepositDetails,
BindingResultbindingResult,SessionStatussessionStatus){
newFixedDepositDetailsValidator().validate(fixedDepositDetails,bindingResult);
if(bindingResult.hasErrors()){
logger.info("openFixedDeposit()method:Validationerrors
-re-displayingformforopeninganewfixeddeposit");
return"createFixedDepositForm";
}
.....
}
}
The above example listing shows that the openFixedDeposit method creates an instance of
FixedDepositDetailsValidator and invokes its validate method. As BindingResult is a sub-interface of
Errors, you can pass a BindingResult object where Errors object is expected. The openFixedDeposit
method passes the fixedDepositDetails model attribute and the BindingResult object to the validate
method.AsBindingResultalreadycontainsdatabindingerrors,passingBindingResultobjecttovalidate
methodaddsvalidationerrorsalsototheBindingResultobject.
InvokingmodelattributesvalidationusingJSR303’s@Validannotation
You can instruct Spring to automatically validate a model attribute argument passed to a
@RequestMappingmethodbyaddingJSR303’s@Validannotationtothemodelattributeargument,and
settingthevalidatorforthemodelattributeontheWebDataBinderinstance.
ThefollowingexamplelistingshowshowFixedDepositController’sopenFixedDepositmethod canuse
@ValidannotationtovalidateFixedDepositDetailsmodelattribute:
Examplelisting11-26–FixedDepositController–invokingvalidationusing@Validannotation
importjavax.validation.Valid;
.....
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=create",method=RequestMethod.POST)
publicStringopenFixedDeposit(
@Valid@ModelAttribute(value="newFixedDepositDetails")FixedDepositDetails
fixedDepositDetails,BindingResultbindingResult,SessionStatussessionStatus){
if(bindingResult.hasErrors()){
logger.info("openFixedDeposit()method:
Validationerrors-re-displayingformforopeninganewfixeddeposit");
return"createFixedDepositForm";
}
.....
}
.....
@InitBinder(value="newFixedDepositDetails")
publicvoidinitBinder_New(WebDataBinderwebDataBinder){
webDataBinder.registerCustomEditor(Date.class,newCustomDateEditor(
newSimpleDateFormat("MM-dd-yyyy"),false));
webDataBinder.setValidator(newFixedDepositDetailsValidator());
}
.....
}
Intheaboveexamplelisting,theinitBinder_NewmethodcallsWebDataBinder’ssetValidatormethodto
setFixedDepositDetailsValidatorasthevalidatorfornewFixedDepositDetailsmodelattribute,andinthe
openFixedDeposit method the newFixedDepositDetails model attribute is annotated with JSR 303’s
@Validannotation.WhentheopenFixedDepositmethodisinvoked,bothdatabindingandvalidationare
performedonthenewFixedDepositDetailsmodelattribute,andtheresultsofdatabindingandvalidation
aremadeavailableviatheBindingResultargument.
Itisimportanttonotethatif@InitBinderannotationspecifiesnameofthemodelattribute,thevalidator
setontheWebDataBinderappliesonlytothatparticularmodelattribute.Forinstance,inexamplelisting
11-26,theFixedDepositDetailsValidatorappliesonlytothenewFixedDepositDetailsmodelattribute.Ifa
validator applies to multiple controllers in the application, consider defining an @InitBinder method
inside a @ControllerAdvice annotated class (or use WebBindingInitializer) to set a validator on the
WebDataBinder.
Let’s now lookat how constraintsare specified onproperties ofJavaBeans componentusing JSR303
annotations.
SpecifyingconstraintsusingJSR303annotations
JSR303(BeanValidationAPI)definesannotationsthatyoucanusetospecifyconstraintsonpropertiesof
JavaBeanscomponents.
IMPORTchapter 11/ch11-jsr303-validation (This project shows a modified version of ch11-data-
bindingprojectthatusesJSR303annotationstospecifyconstraintsonFixedDepositDetailsobject.Ifyou
deploy the project on Tomcat server and access the URL http://localhost:8080/ch11-jsr303-validation,
you’llseethelistoffixeddepositsinthesystem.)
The following example listing shows the FixedDepositDetails class that uses JSR 303 annotations to
specifyconstraintsonitsfields:
Examplelisting11-27–FixedDepositDetails–specifyingJSR303constraints
Project–ch11-jsr303-validation
Sourcelocation-src/main/java/sample/spring/chapter11/domain
packagesample.spring.chapter11.domain;
importjavax.validation.constraints.*;
publicclassFixedDepositDetails{
privatelongid;
@Min(1000)
@Max(500000)
privatelongdepositAmount;
@Email
@Size(min=10,max=25)
privateStringemail;
@NotNull
privateDatematurityDate;
.....
}
@Min,@Max,@Email,@Size, and @NotNull are some of the annotations defined by JSR 303. The
above example listing shows that by using JSR 303 annotations FixedDepositDetails class clearly
specifies the constraintsthat apply on its fields. On the other hand, if you are using Spring’s Validator
implementation to validate an object, constraints are contained in the Validator implementation (refer
examplelisting11-24).
The following table describes the constraints enforced by JSR 303 annotations on the
FixedDepositDetailsobjectshowninexamplelisting11-27:
JSR303annotation Constraintdescription
@NotNull Theannotatedfieldmustnotbenull.Forinstance,maturityDatefieldmustnotbenull.
@Min
Theannotatedfield’svaluemustbegreaterthanorequaltothespecifiedminimumvalue.
For instance, @M in(1000) annotation on depositAmount field of FixedDepositDetails object
meansthatdepositAmount’svaluemustbegreaterthanorequalto1000.
@Max
Theannotatedfield’svaluemustbelessthanorequaltothespecifiedvalue.
Forinstance,@Max(500000) annotationon depositAmount fieldof FixedDepositDetails object
meansthatthedepositAmount’svaluemustbelessthanorequalto500000.
@Size
Theannotatedfield’ssizemustbebetweenthespecifiedminandmaxattributes.
For instance, @Size(min=5, max=100) annotation on email field of FixedDepositDetails object
meansthatthesizeoftheemailfieldmustbegreaterthanorequalto5andlessthanorequalto
100.
@Email
Theannotatedfield’svaluemustawell-formedemailaddress.
Forinstance,@EmailannotationontheemailfieldofFixedDepositDetailsobjectmeansthatthe
emailfield’svaluemustbeawell-formedemailaddress.
TouseJSR303annotations,ch11-jsr303-validationprojectspecifiesdependencyonJSR303APIJAR
file(validation-api-1.0.0.GA)andHibernateValidatorframework(hibernate-validation-4.3.0.Final).The
Hibernate Validator framework provides the reference implementation for JSR 303. The Hibernate
Validator framework provides additional constraint annotations that you can use along with JSR 303
annotations. For instance, you can use Hibernate Validator’s @NotBlank annotation to specify that a
field’svaluemustnotbenullorempty.
It is important tonote thatJSR303 also allows you to createcustom constraints and use them in your
application. For instance, you can create a @MyConstraint custom constraint and a corresponding
validatortoenforcethatconstraintonobjects.
Now, that we have specified JSR 303 constraints on FixedDepositDetails class, let’s look at how to
validateFixedDepositDetailsobject.
ValidatingobjectsthatuseJSR303annotations
IfaJSR303provider(likeHibernateValidator)isfoundintheapplication’sclasspath,andyouhave
specified<annotation-driven>elementofSpring’smvcschemainthewebapplicationcontextXMLfile,
then Spring automatically enables support for JSR 303. Behind the scenes, the <annotation-driven>
element configures an instance of Spring’s LocalValidatorFactoryBean class that is responsible for
detectingthepresenceofaJSR303provider(likeHibernateValidator)intheapplication’sclasspathand
initializingit.
LocalValidatorFactoryBean implements JSR 303’s Validator and ValidatorFactory interfaces, and also
Spring’sValidator interface. For this reason, you can choose to validate an object by calling validate
methodofSpring’sValidatorinterfaceorbycallingvalidatemethodofJSR303’sValidator.Asdiscussed
earlier, you can also instruct Spring to automatically validate a model attribute argument passed to a
@RequestMappingmethodbysimplyadding@Validannotationonthemodelattributeargument.
Validatingmodelattributesbyexplicitlycallingvalidatemethod
The following example listing shows the FixedDepositController class that uses Spring’s Validator to
validatetheFixedDepositDetailsobject(referexamplelisting11-27)thatusesJSR303’sconstraints:
Example listing 11-28 – FixedDepositController– validating FixedDepositDetails using Spring
ValidationAPI
Project–ch11-jsr303-validation
Sourcelocation-src/main/java/sample/spring/chapter11/web
packagesample.spring.chapter11.web;
importjavax.validation.Valid;
.....
publicclassFixedDepositController{
.....
@Autowired
privateValidatorvalidator;
.....
@RequestMapping(params="fdAction=create",method=RequestMethod.POST)
publicStringopenFixedDeposit(
@ModelAttribute(value="newFixedDepositDetails")FixedDepositDetailsfixedDepositDetails,
BindingResultbindingResult,SessionStatussessionStatus){
validator.validate(fixedDepositDetails,bindingResult);
if(bindingResult.hasErrors()){.....}.....
}
.....
}
In the above example listing, the LocalValidatorFactoryBean (that implements Spring’s Validator
interface) is autowired into FixedDepositController’s validator instance variable. In the
openFixedDeposit method, call to Validator’s validate method results in invocation of
LocalValidatorFactoryBean’s validate(Object, Errors) method to validate the FixedDepositDetails
instance. The BindingResult object is passed to the validate method to hold the validation errors. An
importantpointtonoticeintheaboveexamplelistingisthattheFixedDepositControllerdoesn’tdirectly
dealwithJSR303-specificAPItovalidateFixedDepositDetailsobject.Instead,SpringValidationAPIis
usedtovalidateFixedDepositDetailsobject.
ThefollowingexamplelistingshowsanalternateversionofFixedDepositControllerthatusesJSR303-
specificAPItovalidateFixedDepositDetailsobject:
Example listing 11-29 – FixedDepositController– validating FixedDepositDetails using JSR 303-
specificAPI
importjavax.validation.ConstraintViolation;
importjavax.validation.Validator;
importjava.util.Set;
.....
publicclassFixedDepositController{
.....
@Autowired
privateValidatorvalidator;
.....
@RequestMapping(params="fdAction=create",method=RequestMethod.POST)
publicStringopenFixedDeposit(
@ModelAttribute(value="newFixedDepositDetails")FixedDepositDetailsfixedDepositDetails,
BindingResultbindingResult,SessionStatussessionStatus){
Set<ConstraintViolation<FixedDepositDetails>>violations=
validator.validate(fixedDepositDetails);
Iterator<ConstraintViolation<FixedDepositDetails>>itr=violations.iterator();
if(itr.hasNext()){.....}.....
}
.....
}
In the above example listing, the LocalValidatorFactoryBean (that implements JSR 303’s Validator
interface) is autowired into FixedDepositController’s validator instance variable. In the
openFixedDeposit method, call to Validator’s validate method results in invocation of
LocalValidatorFactoryBean’s validate(T) method to validate the FixedDepositDetails instance. The
validatemethodreturnsajava.util.SetobjectthatcontainstheconstraintviolationsreportedbytheJSR
303 provider. You can check the java.util.Set object returned by the validate method to find if any
constraintviolationswerereported.
InvokingmodelattributesvalidationusingJSR303’s@Validannotation
You can instruct Spring to automatically validate a model attribute argument passed to a
@RequestMappingmethodbyaddingJSR303’s@Validannotationtothemodelattributeargument.The
following example listing shows FixedDepositController’s editFixedDeposit method that uses @Valid
annotationtovalidateeditableFixedDepositDetailsmodelattribute:
Examplelisting11-30–FixedDepositController–invokingvalidationusing@Validannotation
Project–ch11-jsr303-validation
Sourcelocation-src/main/java/sample/spring/chapter11/web
packagesample.spring.chapter11.web;
importjavax.validation.Valid;
.....
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=edit",method=RequestMethod.POST)
publicStringeditFixedDeposit(
@Valid@ModelAttribute("editableFixedDepositDetails")FixedDepositDetailsfixedDepositDetails,
BindingResultbindingResult,SessionStatussessionStatus){
if(bindingResult.hasErrors()){.....}.....
}
.....
}
Intheaboveexamplelisting,@ValidannotationoneditableFixedDepositDetailsmodelattributeresultsin
itsautomaticvalidationbySpring.Theconstraintviolationsreportedduringvalidationareaddedtothe
BindingResultobjectalongwithanydatabindingerrors.
Let’snowlookathowSpring’sformtaglibrarysimplifieswritingformsinJSPpages.
11-6Spring’sformtaglibrary
Spring’s form tag library provides tags that simplify creating JSP pages for Spring Web MVC
applications.TheSpring’sformtaglibraryprovidestagstorendervariousinputformelementsandfor
bindingformdatatoformbackingobjects.
ThefollowingexamplelistingshowsthecreateFixedDepositForm.jspJSPpageofch11-jsr303-validation
projectthatusesSpring’sformtaglibrarytags:
Examplelisting11-31–createFixedDepositForm.jsp–Spring’sformtaglibraryusage
Project–ch11-jsr303-validation
Sourcelocation-src/main/webapp/WEB-INF/jsp
<%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%>
<%@taglibprefix="form"uri="http://www.springframework.org/tags/form"%>
<html>
.....
<form:formcommandName="newFixedDepositDetails"
name="createFixedDepositForm"method="POST"
action="${pageContext.request.contextPath}/fixedDeposit?fdAction=create">
.....
<tr>
<tdclass="td"><b>Amount(inUSD):</b></td>
<tdclass="td"><form:inputpath="depositAmount"/>
<fontstyle="color:#C11B17;"><form:errorspath="depositAmount"/></font>
</td>
</tr>
<tr>
<tdclass="td"><b>Maturitydate:</b></td>
<tdclass="td"><form:inputpath="maturityDate"/>
<fontstyle="color:#C11B17;"><form:errorspath="maturityDate"/></font></td>
</tr>
.....
<tdclass="td"><inputtype="submit"value="Save"/>
.....
</form:form>
</html>
In the above example listing, the following taglib directive makes the Spring’s form tag library tags
accessibletotheJSPpage:
<%@taglibprefix="form"uri="http://www.springframework.org/tags/form"%>
Spring’sformtaglibrary’s<form>tagrendersanHTMLformthatbindsformfieldstothepropertiesof
model attribute identified by the commandName attribute. The <form> tag contains <input> tags that
correspond to the properties ofthe model attribute specified by the commandNameattribute. When the
formisrendered,propertiesarereadfromthemodelattributeanddisplayedby<input>tags.And,when
theformissubmitted,thefieldvaluesintheformareboundtothecorrespondingpropertiesofthemodel
attribute.
In example listing 11-31, the <form> tag renders an HTML form for opening a fixed deposit. The
commandNameattribute’svalueisnewFixedDepositDetails,whichmeansthattheformfieldsaremapped
tothepropertiesofthenewFixedDepositDetailsmodelattribute.Thenameattributespecifiesthenameof
theHTMLformrenderedbythe<form>tag.ThemethodattributespecifiestheHTTPmethodtousefor
sendingformdatawhentheformissubmitted.TheactionattributespecifiestheURLtowhichtheform
dataissentwhentheformissubmitted.TheURLspecifiedbytheactionattributemustmaptoaunique
@RequestMappingannotatedmethodinyourSpringWebMVCapplication.Inexamplelisting11-31,the
URL ${pageContext.request.contextPath}/fixedDeposit?fdAction=create maps to
FixedDepositController’s openFixedDeposit method (refer FixedDepositController.java file of ch11-
jsr303-validation project). You should note that the expression ${pageContext.request.contextPath}
returnsthecontextpathofthewebapplication.
The<input>tagofSpring’sformtaglibraryrendersanHTML<input>elementwithtypeattributesetto
text.Thepathattributespecifiesthepropertyofthemodelattributetowhichthefieldismapped.When
the form is rendered, the value of the property is displayed by the input field. And, when the form is
submitted,thevalueofthepropertyissettothevalueenteredbytheuserintheinputfield.
The<errors>tagofSpring’sformtaglibraryshowsdatabindingandvalidationerrormessagesthatwere
added to the BindingResult during data binding and validation. If you want to display error messages
correspondingtoaparticularproperty,specifythenameofthepropertyasthevalueofthepathattribute.
If you want to display all the error messages stored in the BindingResult object, specify value of path
attributeas*.
ThecreateFixedDepositForm.jsppageusesonlyasubsetofSpring’sformtaglibrarytags.Thefollowing
tableshowstheothertagsthatSpring’sformtaglibraryoffers:
Tag Description
<checkbox>
RendersanHTM Lcheckbox(thatis,<inputtype="checkbox"/>)
AsthevalueofanHTMLcheckboxisnotsenttotheserverifthecheckboxisunchecked,the
<checkbox> tag additionally renders a hidden field corresponding to each checkbox to allow
sendingthestateofthecheckboxtotheserver.
Example:<form:checkboxpath="myProperty"/>
Thepathattributespecifiesthenameofthepropertytowhichthecheckboxvalueisbound.
<checkboxes>
RendersmultipleHTMLcheckboxes.
Example:<form:checkboxespath="myPropertyList"items="${someList}"/>
Thepathattributespecifiesthenameofthepropertytowhichtheselectedcheckboxesvalues
arebound.Theitemsattributespecifiesthenameofthemodelattributethatcontainsthelistof
optionstoshowascheckboxes.
<radiobutton>
RendersanHTM Lradiobutton(thatis,<inputtype="radio"/>)
Example:<form:radiobuttonpath="myProperty"value="myValue"/>
Thepathattributespecifiesthenameofthepropertytowhichtheradiobuttonisbound,and
thevalueattributespecifiesthevalueassignedtotheradiobutton.
<radiobuttons>
RendersmultipleHTMLradiobuttons.
Example:<form:radiobuttonspath="myProperty"items="${myValues}"/>
Theitemsattributespecifiesthelistofoptionstoshowasradiobuttons,andthepathattribute
specifiesthepropertytowhichtheselectedradiobuttonsvaluesarebound.
<password> RendersanHTM Lpasswordfield(thatis,<inputtype="password"/>)
<select>
RendersanHTM L<select>element.
Example:<form:selectpath="book"items="${books}"/>
Theitems attribute specifies the model attributep roperty that contains the list of options to
displayintheHTML<select>element.Thepathattributespecifiesthepropertytowhichthe
selectedoptionisbound.
<option>
RendersanHTM L<option>element.
Example:
<form:selectpath="book">
<form:optionvalue="GettingstartedwithS pringFramework"/>
<form:optionvalue="GettingstartedwithS pringWebMVC"/>
</form:select>
<options> RendersmultipleHTM L<option>elements.
<textarea> RendersanHTML<textarea>element.
<hidden> RendersanHTM Lhiddeninputfield(thatis,<inputtype="hidden"/>)
Let’snowlookatHTML5supportinSpring’sformtaglibrary.
HTML5supportinSpring’sformtaglibrary
StartingwithSpring3.0,theformtaglibraryallowsyoutouseHTML5-specificattributesinthetags.For
instance,thefollowing<textarea>tagusesHTML5’srequiredattribute:
<form:textareapath="myProperty"required="required"/>
Therequired="required" attribute specifies that it is mandatory for the user to enter information in the
textarea.TheuseofrequiredattributesavestheefforttowritetheJavaScriptcodetoperformclient-side
validationformandatoryfields.Iftheuserdoesn’tenteranyinformationinthetextareaandattemptsto
submittheform,thewebbrowsershowsamessagesayingthatthetextareaisrequiredandmustnotbe
leftblank.
InHTML5youcanspecifytypeattribute’svalueasemail,datetime,date,month,week,time,range,color,
reset,andsoon.StartingwithSpring3.1,<input>tagsupportsspecifyingtypeattributevalueotherthan
text.Forinstance,thefollowing<input>tagspecifiestypeattribute’svalueasemail:
<form:inputpath="myProperty"type="email"/>
Whenauserattemptstosubmittheformcontainingafieldoftypeemail,thewebbrowserchecksthatthe
email type field contains a valid email address. If the email type field doesn’t contain a valid email
address,thewebbrowsershowsamessageindicatingthatthefielddoesn’tcontainavalidemailaddress.
Asthewebbrowserperformsthevalidation,youdon’tneedtowritetheJavaScriptcodetovalidatethe
emailaddress.
11-7Summary
WelookedatmanycorefeaturesofSpringWebMVCinthischapter.Welookedat@ModelAttributeand
@SessionAttributesannotationswhicharemostcommonlyusedindevelopingannotatedcontrollers.We
alsotookanin-depthlookathowSpringperformsdatabindingandvalidation.Inthenextchapter,we’ll
lookathowtodevelopRESTfulwebservicesusingSpringWebMVC.
Chapter12–DevelopingRESTfulwebservicesusingSpring
WebMVC
12-1Introduction
Representational State Transfer (also referred to as REST) is an architectural-style in which an
applicationdefinesresourcesthatareuniquelyidentified byURIs (Uniform Resource Identifier). The
clients of a REST-style application interact with a resource by sending HTTP GET, POST, PUT and
DELETE method requests to the URI to which the resource is mapped. The following figure shows a
REST-styleapplicationthatisaccessedbyitsclients:
Figure12-1REST-styleapplicationdefinesxandyresourcesthatareuniquelyidentifiedby/resource2
and/resource1URIs,respectively.
TheabovefigureshowsaREST-styleapplicationthatconsistsoftworesources–xandy.Theresourcex
ismappedto/resource2URIandtheyresourceismappedto/resource1URI.Aclientcaninteractwith
resourcex by sending HTTP requests to /resource2 URI, and can interact with resource y by sending
HTTPrequeststo/resource1URI.
IfawebservicefollowstheRESTarchitectural-style,itisreferredtoasaRESTfulwebservice.Inthe
contextofRESTfulwebservices,youcanthinkofaresourceasthedataexposedbythewebservice.
TheclientcanperformCRUD(CREATE,READ,UPDATEandDELETE)operationsontheexposeddata
bysendingHTTPrequeststotheRESTfulwebservice.TheclientandtheRESTfulwebserviceexchange
representation of the data, which could be in XML, JSON (JavaScript Object Notation) format, or a
simplestring,oranyotherMIMEtypesupportedbytheHTTPprotocol.
RESTfulwebservicesaresimplertoimplementandaremorescalablecomparedtoSOAP-basedweb
services.InSOAP-basedwebservices,requestsandresponsesarealwaysinXMLformat.InRESTful
webservices,youcanuseJSON(JavaScriptObjectNotation),XML,plaintext,andsoon,forrequests
andresponses.Inthischapter,we’lllookathowSpringWebMVCsimplifiesdevelopingandaccessing
RESTfulwebservices.
Let’sbeginbylookingattherequirementsofaRESTfulwebservicethatwe’llimplementusingSpring
WebMVC.
12-2Fixeddepositwebservice
We saw earlier that the MyBank web application provides the functionality to display a list of fixed
deposits,andtocreate,editandclosefixeddeposits.Asthefixeddepositrelatedfunctionalitymayalso
beaccessedbyotherapplications,thefixeddepositrelatedfunctionalityneedstobetakenoutfromthe
MyBank web application and deployed as a RESTful web service. Let’s call this new RESTful web
serviceasFixedDepositWS.
ThefollowingfigureshowsthattheFixedDepositWSwebserviceisaccessedbyMyBankandSettlement
applications:
Figure12-2MyBankandSettlementapplicationsaccessFixedDepositWSwebservice
The above figure shows that MyBank and Settlement web applications interact with FixedDepositWS
web service by exchanging data in JSON format. We’ll soon see that JSON represents a simpler
alternativetoXMLforexchangingdatabetweenapplications.
Let’s now look at how to implement FixedDepositWS web service as a RESTful web service using
SpringWebMVC.
12-3ImplementingaRESTfulwebserviceusingSpringWebMVC
TodevelopaRESTfulwebservice,youneedtodothefollowing:
·identifyresourcesthatareexposedbythewebservice
·specifyURIscorrespondingtotheidentifiedresources
·identifyoperationsthatcanbeperformedontheresources
·mapHTTPmethodstotheidentifiedoperations
IncaseofFixedDepositWSwebservice,fixeddepositdatarepresentstheresourceexposedbytheweb
service.IftheFixedDepositWSwebservicemapsfixeddepositsinthesystemto/fixedDepositsURI,a
FixedDepositWSwebserviceclientcanperformactionsonfixeddepositsbysendingHTTPrequeststo
/fixedDepositsURI.
InRESTfulwebservice,theHTTPmethodusedbyclientsforinteractingwitharesourceindicatesthe
operation to be performed on the resource. GET retrieves the resource state, POST creates a new
resource, PUT modifies the resource state and DELETE deletes the resource. The following figures
showstheactionsperformedbytheFixedDepositWSwebservicewhenaclientsendsGET,POST,PUT
andDELETEHTTPrequeststothe/fixedDepositsURI:
Figure12-3 HTTPrequestsare sent by the FixedDepositWS’s clientto /fixedDeposits URI to interact
withfixeddepositdata
The above figure shows that the client of FixedDepositWS web service sends GET, POST, PUT and
DELETEHTTPrequeststo/fixedDepositsURItointeractwiththefixeddepositdata.Theidquerystring
parameter uniquelyidentifiesa fixed depositinthesystem.The followingtabledefinesthepurpose of
eachrequestshownintheabovefigure:
HTTPmethod URI Purpose
GET /fixedDeposits Retrieve details of all the fixed deposits in the system. The FixedDepositWS
webservicesendstheresponseinJSONformat.
GET /fixedDeposits?id=123 Retrievedetailsofthefixeddepositwhoseidis123.TheFixedDepositWSweb
servicesendstheresponseinJSONformat.
POST /fixedDeposits Create a new fixed deposit in the system. The web service client sends the
detailsofthefixeddeposittobecreatedinJSONformat.
PUT /fixedDeposits?id=123 M odifies the fixeddeposit whoseid is 123. The web service client sends the
modifieddetailsofthefixeddepositinJSONformat.
DELETE /fixedDeposits?id=123 Removesthefixeddepositwhoseidis123.
The above tableshows that the FixedDepositWS and its clientsexchange informationinJSONformat.
Beforedelving intothedetailsofhowtoimplementFixedDepositWS,let’slookathowthedatalooks
likeinJSONformat.
JSON(JavaScriptObjectNotation)
JSONisatext-baseddataformatthatisusedbyapplicationsforexchangingstructureddata.AsJSON
representationofdataismorecompactcomparedtoXML,JSONservesasasimpleralternativetoXML.
To simplify conversion of Java objects to JSON and vice versa, you can use JSON libraries like
FlexJson(http://flexjson.sourceforge.net/)andJackson(https://github.com/FasterXML/jackson).
Let’ssayaPersonclassdefinesfirstNameandlastName attributes.Ifyoucreateaninstanceof Person
objectand setfirstName to Myfirstname and lastName toMylastname, the representation of the Person
objectinJSONformatwouldlooklikethis:
Examplelisting12-1–PersonobjectrepresentationinJSONformat
{
"firstName":Myfirstname,
"lastName":"Mylastname"
}
TheaboveexamplelistingshowsthateachattributeofPersonobjectisrepresentedas<attribute-name>:
<attribute-value>inJSONformat.
YoucanalsorepresentacollectionofJavaobjectsinJSONformat.Thefollowingexamplelistingshows
howyoucanrepresentacollectionofPersonobjectsinJSONformat:
Examplelisting12-2–CollectionofPersonobjectsrepresentedinJSONformat
[
{
"firstName":Myfirstname,
"lastName":"Mylastname"
},
{
"firstName":Yourfirstname,
"lastName":"Yourlastname"
}
]
Youdon’tneedtowritecodetoconvertanobjectintoJSONrepresentationandviceversa.Instead,the
RESTfulwebserviceanditsclientscanmakeuseofFlexJsonorJacksonlibrarytoperformconversion.
Aswe’llsoonsee,SpringWebMVCusesJacksonforconvertingJSONtoJavaobjectsandviceversa.
Let’snowlookattheimplementationofFixedDepositWSwebserviceusingSpringWebMVC.
IMPORTchapter 12/ch12-webservice (This project shows the implementation of FixedDepositWS
RESTfulwebserviceusingSpringWebMVC.Laterinthischapter,we’llseehowFixedDepositWSweb
serviceisaccessedbyitsclients.)
FixedDepositWSwebserviceimplementation
Spring Web MVC annotations, like @Controller, @RequestMapping, @RequestParam, @PathVariable
@ResponseBody,@RequestBody, and so on, support building RESTful web services. In this section,
we’lllookatusageofsomeoftheseannotationsindevelopingtheFixedDepositWSwebservice.
In FixedDepositWS web service, the FixedDepositController (a Spring Web MVC controller) is
responsible for handling web service requests. FixedDepositController is like any other Spring Web
MVCcontrollerwiththeexceptionthatits@RequestMappingmethodsdon’trenderviews.Thefollowing
examplelistingshowsthat@Controllerand@RequestMappingannotationsareusedtomapwebrequests
toappropriatemethodsofFixedDepositControllerclass:
Examplelisting12-3–FixedDepositController–webservicerequesthandler
Project–ch12-webservice
Sourcelocation-src/main/java/sample/spring/chapter12/web
packagesample.spring.chapter12.web;
importorg.springframework.http.ResponseEntity;
.....
@Controller
@RequestMapping(value="/fixedDeposits")
publicclassFixedDepositController{
.....
@RequestMapping(method=RequestMethod.GET)
publicResponseEntity<List<FixedDepositDetails>>getFixedDepositList(){.....}
@RequestMapping(method=RequestMethod.GET,params="id")
public ResponseEntity<FixedDepositDetails> getFixedDeposit(@RequestParam("id") int id) {
.....}
.....
}
ThegetFixedDepositListmethodreturnsthelistoffixeddepositsinthesystem,andthegetFixedDeposit
methodreturnsdetailsofthefixeddepositidentifiedbytheidargument.Theaboveexamplelistingshows
that the @RequestMapping annotation is used at the class- and method-level to map requests to
getFixedDepositList and getFixedDeposit methods. The getFixedDepositList method is invoked when a
clientapplicationsendsanHTTPGETrequestto/fixedDepositsURI,andthegetFixedDepositmethodis
invoked when a client application sends an HTTP GET request containing id request parameter to
/fixedDeposits URI. So, if the request URI is /fixedDeposits?id=123, the getFixedDeposit method is
invoked.
ThefollowingtablesummarizesthemappingofrequestURIsandHTTPmethodstothemethodsdefined
intheFixedDepositControllerclass:
HTTPmethod URI FixedDepositControllermethod
GET /fixedDeposits getFixedDepositList
GET /fixedDeposits?id=123 getFixedDeposit
POST /fixedDeposits openFixedDeposit
PUT /fixedDeposits?id=123 editFixedDeposit
DELETE /fixedDeposits?id=123 closeFixedDeposit
Wesawinchapter10and11that@RequestMappingannotatedmethodsreturnviewinformationthatis
used by the DispatcherServlet to render a view (like JSP or servlet). In RESTful web services,
@RequestMappingmethodsreturndata(andnottheviewinformation)totheclientapplications.Forthis
reason,thegetFixedDepositListandgetFixedDepositmethodshavebeendefinedtoreturnobjectsoftype
ResponseEntity. Let’s now look at the usage of ResponseEntity object in the FixedDepositController
class.
SpecifyingHTTPresponseusingResponseEntity
ResponseEntityrepresentsanHTTPresponseconsistingofheaders,bodyandstatuscode.Theobjectthat
yousetasbodyontheResponseEntityobjectiswrittentotheHTTPresponsebodybySpringWebMVC.
The following example listing shows how the ResponseEntity object is created by
FixedDepositController’sgetFixedDepositListmethod:
Examplelisting12-4–FixedDepositController–creatingResponseEntityinstance
Project–ch12-webservice
Sourcelocation-src/main/java/sample/spring/chapter12/web
packagesample.spring.chapter12.web;
importorg.springframework.http.HttpStatus;
importorg.springframework.http.ResponseEntity;
.....
publicclassFixedDepositController{
.....
@RequestMapping(method=RequestMethod.GET)
publicResponseEntity<List<FixedDepositDetails>>getFixedDepositList(){
.....
returnnewResponseEntity<List<FixedDepositDetails>>(
fixedDepositService.getFixedDeposits(),HttpStatus.OK);
}
.....
}
Intheaboveexamplelisting,thefixeddepositlistpassedtotheResponseEntityconstructoriswrittento
theHTTPresponsebody.TheHttpStatusisanenumtypethatdefinesHTTPstatuscodes.TheconstantOK
refers to the HTTP status code 200. Notice that the return type of the getFixedDepositList method is
ResponseEntity<List<FixedDepositDetails>>, which means that an object of type
List<FixedDepositDetails>iswrittentotheHTTPresponsebody.SpringWebMVCusesanappropriate
HttpMessageConverter(explainedinsection12-5)toconverttheList<FixedDepositDetails>objectinto
theformatexpectedbytheclientapplication.
NOTELaterinthischapter,we’llseethatclientapplicationscanuseSpring’sRestTemplatetoinvoke
methodsdefinedintheFixedDepositControllerandtoretrievetheobjectswrittentotheHTTPresponse
body.
Allthe@RequestMappingannotatedmethodsofFixedDepositControllerclassdefineResponseEntityas
their return type. If you don’t need to send HTTP status code in the response, you can use Spring’s
HttpEntity class instead of ResponseEntity. HttpEntity represents an HTTP request or response, and
ResponseEntityisasubclassofHttpEntitythataddsanHTTPstatuscodetotheresponse.
ThefollowingexamplelistingshowsamodifiedversionofgetFixedDepositListmethodthatcreatesand
returnsaninstanceofHttpEntity:
Examplelisting12-5–FixedDepositController–usingHttpEntityinsteadofResponseEntity
importorg.springframework.http.HttpStatus;
importorg.springframework.http.HttpEntity;
.....
publicclassFixedDepositController{
.....
@RequestMapping(method=RequestMethod.GET)
publicHttpEntity<List<FixedDepositDetails>>getFixedDepositList(){
.....
returnnewHttpEntity<List<FixedDepositDetails>>(fixedDepositService.getFixedDeposits());
}
.....
}
TheaboveexamplelistingshowsthatthefixeddepositsfoundinthesystemarepassedtotheHttpEntity
constructor. As in case of ResponseEntity (refer example listing 12-4), fixed deposits passed to the
HttpEntityarewrittentotheHTTPresponsebody.
Both HttpEntity and ResponseEntity objects allow you to set HTTP response headers. The following
examplelistingshowsascenarioinwhichsome-headerheaderissetontheHTTPresponse:
Examplelisting12-6–HttpHeadersusage
importorg.springframework.http.HttpHeaders;
.....
@RequestMapping(method=RequestMethod.GET)
publicHttpEntity<String>doSomething(){
HttpHeadersresponseHeaders=newHttpHeaders();
responseHeaders.set("some-header","some-value");
returnnewHttpEntity<String>("Helloworld!",responseHeaders);
}
.....
Spring’sHttpHeadersobjectcontainstheheadersthataresetontheHTTPresponse.Intheaboveexample
listing, HttpHeader’s setmethod setssome-header response header (with value some-value). When the
doSomething method is invoked, the ‘Helloworld!’ string is written to the response body, and some-
headerheaderiswrittentotheHTTPresponse.
As@RequestMappingmethodscanbedefinedtoacceptHttpServletResponseobjectasargument,let’s
lookathowyoucandirectlysetresponsebodyandheadersontheHttpServletResponseobject.
SpecifyingHTTPresponseusingHttpServletResponse
The following example listing shows a @RequestMapping method which writes directly to the
HttpServletResponseobject:
Examplelisting12-7–SettingresponseonHttpServletResponse
importjavax.servlet.http.HttpServletResponse;
.....
@RequestMapping(method=RequestMethod.GET)
publicvoiddoSomething(HttpServletResponseresponse)throwsIOException{
response.setHeader("some-header","some-value");
response.setStatus(200);
response.getWriter().write("Helloworld!");
}
.....
Instead of directly writing response to HttpServletResponse, you should use ResponseEntity (or
HttpEntity)objecttoimprovethetestabilityofthecontrollers.
Let’snowlookatSpring’s@ResponseBodymethod-levelannotationthatwritesthereturnvalueofthe
methodtoHTTPresponsebody.
NOTE As of Spring 4.0, @ResponseBody annotation can also be specified at the class level. If
@ResponseBody annotation is specified at the class level, it is inherited by the @RequestMapping
methodsofthecontroller.
BindingreturnedvalueofamethodtoHTTPresponsebodyusing@ResponseBody
Thefollowingexamplelistingshowsusageof@ResponseBodyannotation:
Examplelisting12-8–@ResponseBodyannotationusage
importorg.springframework.web.bind.annotation.ResponseBody;
.....
@RequestMapping(method=RequestMethod.GET)
@ResponseBody
publicStringdoSomething(){
return"Helloworld!";
}
.....
In the above example listing, the ‘Hello world !’ string value returned by the doSomething method is
writtentotheHTTPresponsebody.Insection10-7ofchapter10,wediscussedthatifthereturntypeofa
@RequestMapping annotatedmethodisString, thereturnedvalueis treatedas thename of theview to
render.Intheaboveexamplelisting,the@ResponseBodyannotationonthedoSomethingmethodinstructs
SpringWebMVCtowritethestringvaluetotheHTTPresponsebodyinsteadoftreatingthestringvalue
astheviewname.YoushouldnotethatSpringusesanappropriateHttpMessageConverter(explainedin
section12-5)implementationtowritethevaluereturnedbythe@ResponseBodyannotatedmethodtothe
HTTPresponsebody.
Now, that we have seen different ways in which a @RequestMapping method can write to the HTTP
response, let’s look at how a @RequestMapping method can read information from the HTTP request
bodyusing@RequestBodyannotation.
BindingHTTPrequestbodytoamethodparameterusing@RequestBody
A @RequestMapping annotated method can use @RequestBody method-parameter level annotation to
bind HTTP request body to the method parameter. Spring Web MVC uses an appropriate
HttpMessageConverter(explainedinsection12-5)implementationtoconverttheHTTPrequestbodyto
themethodparametertype.Thefollowingexamplelistingshowsusageof@RequestBodyannotationin
MyBankapplication’sFixedDepositController:
Examplelisting12-9–@RequestBodyannotationusage
Project–ch12-webservice
Sourcelocation-src/main/java/sample/spring/chapter12/web
packagesample.spring.chapter12.web;
.....
importorg.springframework.web.bind.annotation.RequestBody;
.....
@Controller
@RequestMapping(value="/fixedDeposits")
publicclassFixedDepositController{
.....
@RequestMapping(method=RequestMethod.POST)
publicResponseEntity<FixedDepositDetails>openFixedDeposit(
@RequestBodyFixedDepositDetailsfixedDepositDetails,
BindingResultbindingResult){
newFixedDepositDetailsValidator().validate(fixedDepositDetails,bindingResult);
.....
}
.....
}
In the above example listing, the FixedDepositDetails type method argument is annotated with
@RequestBody annotation. Spring Web MVC is responsible for converting the HTTP request body to
FixedDepositDetailstypeobject.Intheaboveexamplelisting,FixedDepositDetailsValidatorclassisan
implementation of Spring’s Validator interface that validates the FixedDepositDetails object before
attemptingtocreatethefixeddeposit.
An alternative to using @RequestBody annotation is to directly read HTTP request body from the
HttpServletRequestobjectandconverttherequestbodycontenttotheJavatyperequiredbythemethod.
Spring’s @RequestBody annotation simplifies the conversion because it uses an appropriate
HttpMessageConverterimplementationtoconvertHTTPrequestbodytotheobjecttypeexpectedbythe
@RequestMappingmethod.
Let’snowlookatthe@ResponseStatusannotationthatallowsyoutosetHTTPresponsestatus.
SettingHTTPresponsestatususing@ResponseStatus
You can use the @ResponseStatus annotation to specify the HTTP response status returned by a
@RequestMappingmethod.Thefollowingexamplelistingshowsusageof@ResponseStatusannotation:
Examplelisting12-10–@ResponseStatusannotationusage
importorg.springframework.web.bind.annotation.ResponseStatus;
publicclassSomeController{
@RequestMapping(method=RequestMethod.GET)
@ResponseStatus(value=HttpStatus.OK)
@ResponseBody
publicSomeObjectdoSomething(){
.....
}
}
AsthedoSomethingmethodisannotatedwith@ResponseBodyannotation,theSomeObjectreturnedby
thedoSomethingmethodiswrittentotheHTTPresponsebody.And,the@ResponseStatusannotationsets
theHTTPresponsestatuscodeto200(representedbyHttpStatus.OKconstant).
Let’s now look at how the @ExceptionHandler annotation is used in FixedDepositWS web service to
handleexceptions.
Handlingexceptionsusing@ExceptionHandler
In section 10-9 of chapter 10, we saw that the @ExceptionHandler annotation identifies a controller
method that is responsible for handling exceptions. Like @RequestMapping methods,
@ExceptionHandlermethodsinRESTfulwebservicesareannotatedwith@ResponseBodyannotationor
thereturntypeisdefinedasResponseEntity(orHttpEntity).
Thefollowingexamplelistingshowsusageof@ExceptionHandlerannotationinFixedDepositController
classofch12-webserviceproject:
Examplelisting12-11–@ExceptionHandlerannotationusage
Project–ch12-webservice
Sourcelocation-src/main/java/sample/spring/chapter12/web
packagesample.spring.chapter12.web;
importsample.spring.chapter12.exception.ValidationException;
.....
publicclassFixedDepositController{
.....
@ExceptionHandler(ValidationException.class)
@ResponseBody
@ResponseStatus(value=HttpStatus.BAD_REQUEST)
publicStringhandleException(Exceptionex){
logger.info("handlingValidationException"+ex.getMessage());
returnex.getMessage();
}
}
@ExceptionHandlerannotationonhandleExceptionmethodindicatesthatthehandleExceptionmethodis
invoked when ValidationException is thrown by the FixedDepositController during request processing.
As the handleException method is also annotated with @ResponseBody annotation, the exception
messagereturnedbythehandleExceptionmethodiswrittentotheHTTPresponsebody.@ResponseStatus
onthehandleExceptionmethodresultsinsettingtheHTTPresponsestatuscodeto400(representedby
HttpStatus.BAD_REQUESTconstant).
Inthissection,wesawhowtoimplementFixedDepositWSwebserviceusingSpringWebMVC.Let’s
nowlookathowtoaccessFixedDepositWSwebserviceusingSpring’sRestTemplate.
12-4AccessingRESTfulwebservicesusingRestTemplate
Spring’s RestTemplate class simplifies accessing RESTful web services by taking care of managing
HTTPconnectionsandhandlingHTTPerrors.
IMPORTchapter 12/ch12-webservice-client (This project represents a standalone Java application
that accesses FixedDepositWS RESTful web service using Spring’s RestTemplate (for synchronously
accessing the web service) and AsyncRestTemplate (for asynchronously accessing the web service)
class. The ch12-webservice-client project assumes that the ch12-webservice project representing the
FixedDepositWSRESTfulwebserviceisdeployedathttp://localhost:8080/ch12-webserviceURL.)
RestTemplateconfiguration
ThefollowingexamplelistingshowshowRestTemplateisconfiguredintheapplicationcontextXMLfile
ofch12-webservice-clientproject:
Examplelisting12-12–applicationContext.xml-RestTemplateconfiguration
Project–ch12-webservice-client
Sourcelocation-src/main/resources/META-INF/spring
<beans.....>
<beanid="restTemplate"class="org.springframework.web.client.RestTemplate">
<propertyname="errorHandler"ref="errorHandler"/>
</bean>
<beanid="errorHandler"class="sample.spring.chapter12.MyErrorHandler"/>
.....
</beans>
RestTemplate’s errorHandler property refers to an implementation of Spring’s ResponseErrorHandler
interface that inspects the HTTP response for errors and handles the response in case of errors.
DefaultResponseErrorHandler is the default implementation of ResponseErrorHandler interface that is
provided out-of-the-box by Spring. If you don’t specify the errorHandler property, Spring uses the
DefaultResponseErrorHandler implementation. The above example listing shows that the RestTemplate
usesacustomresponseerrorhandler,MyErrorHandler.
ThefollowingexamplelistingshowstheimplementationofMyErrorHandlerclass:
Examplelisting12-13–MyErrorHandlerclass–HTTPresponseerrorhandler
Project–ch12-webservice-client
Sourcelocation-src/main/java/sample/spring/chapter12
packagesample.spring.chapter12;
importorg.apache.commons.io.IOUtils;
importorg.springframework.http.client.ClientHttpResponse;
importorg.springframework.web.client.DefaultResponseErrorHandler;
publicclassMyErrorHandlerextendsDefaultResponseErrorHandler{
privatestaticLoggerlogger=Logger.getLogger(MyErrorHandler.class);
@Override
publicvoidhandleError(ClientHttpResponseresponse)throwsIOException{
logger.info("Statuscodereceivedfromthewebservice:"+response.getStatusCode());
Stringbody=IOUtils.toString(response.getBody());
logger.info("Responsebody:"+body);
super.handleError(response);
}
}
TheaboveexamplelistingshowsthattheMyErrorHandlerclassextendsDefaultResponseErrorHandler
classandoverridesthehandleError method.IftheHTTPresponse’sstatuscodeindicatesan error,the
handleError method is responsible for handling the response. The ClientHttpResponse argument to the
handleErrormethodrepresentstheHTTPresponsereceivedfromcallingtheRESTfulwebservice.The
call to ClientHttpResponse’s getBody method returns the body of HTTP response as an InputStream
object.MyErrorHandler’shandleErrormethodlogsinformationaboutthestatuscodeandthebodyofthe
HTTP response, and delegates handling of the error to DefaultResponseErrorHandler’s handleError
method. The above example listing shows that the MyErrorHandler class uses Apache Commons IO’s
IOUtilsclasstogetthecontentoftheHTTPresponsebodyasaString.
Now,thatwehaveseenhowaRestTemplateclassisconfigured,let’slookathowRestTemplateisused
byclientapplicationstoaccessRESTfulwebservices.
AccessingFixedDepositWSwebserviceusingRestTemplate
ThefollowingexamplelistingshowstheFixedDepositWSClientclassthatusesRestTemplatetoaccess
FixedDepositWSwebservice:
Examplelisting12-14–FixedDepositWSClientclass–RestTemplateusage
Project–ch12-webservice-client
Sourcelocation-src/main/java/sample/spring/chapter12
packagesample.spring.chapter12;
.....
importorg.springframework.web.client.RestTemplate;
publicclassFixedDepositWSClient{
privatestaticApplicationContextcontext;
publicstaticvoidmain(Stringargs[]){
context=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
getFixedDepositList(context.getBean(RestTemplate.class));
getFixedDeposit(context.getBean(RestTemplate.class));
.....
}
privatestaticvoidgetFixedDepositList(RestTemplaterestTemplate){.....}
.....
}
TheaboveexamplelistingshowsthattheFixedDepositWSClient’smainmethodperformsthefollowing
actions:
§bootstrapstheSpringcontainer(representedbytheApplicationContextobject)
§callsgetFixedDepositList,getFixedDeposit,andsoon,methods.Thesemethodsacceptaninstance
ofRestTemplate,andareresponsibleforcallingtheFixedDepositWSwebservice.
ThefollowingexamplelistingshowstheimplementationofFixedDepositWSClient’sgetFixedDepositList
methodthatcallstheFixedDepositWSwebservicedeployedathttp://localhost:8080/ch12-webserviceto
obtainthelistoffixeddepositsinthesystem:
Examplelisting12-15–FixedDepositWSClient’sgetFixedDepositListmethod
Project–ch12-webservice-client
Sourcelocation-src/main/java/sample/spring/chapter12
packagesample.spring.chapter12;
.....
importorg.springframework.core.ParameterizedTypeReference;
importorg.springframework.http.*;
importorg.springframework.web.client.RestTemplate;
publicclassFixedDepositWSClient{
.....
privatestaticvoidgetFixedDepositList(RestTemplaterestTemplate){
HttpHeadersheaders=newHttpHeaders();
headers.add("Accept","application/json");
HttpEntity<String>requestEntity=newHttpEntity<String>(headers);
ParameterizedTypeReference<List<FixedDepositDetails>>typeRef=
newParameterizedTypeReference<List<FixedDepositDetails>>(){
};
ResponseEntity<List<FixedDepositDetails>>responseEntity=restTemplate
.exchange("http://localhost:8080/ch12-webservice/fixedDeposits",
HttpMethod.GET,requestEntity,typeRef);
List<FixedDepositDetails>fixedDepositDetails=responseEntity.getBody();
logger.info("Listoffixeddepositdetails:\n"+fixedDepositDetails);
}
.....
}
Intheaboveexamplelisting,RestTemplate’sexchangemethodhasbeenusedtosendHTTPGETrequest
to http://localhost:8080/ch12-webservice/fixedDeposits URL. As the FixedDepositWS web service is
deployed at http://localhost:8080/ch12-webservice URL, sending HTTP GET request to
http://localhost:8080/ch12-webservice/fixedDeposits URL results in invocation of
FixedDepositController’s getFixedDepositList method. This is because the FixedDepositController’s
getFixedDepositList method is mapped to /fixedDeposits URI (refer example listing 12-3 or
FixedDepositControllerclassofch12-webserviceproject).
In example listing 12-15, the HttpEntity object represents the request sent to the web service, the
HttpHeaders object represents the request headers in the request, and the ParameterizedTypeReference
objectrepresents the generic type of the response received from the web service. The Accept request
header’s value has been set to application/json to specify that the response from the FixedDepositWS
webserviceisexpectedinJSONformat.Onthewebservice-side,thevalueofAcceptheaderisusedby
SpringWebMVCtochooseanappropriateHttpMessageConvertertoconvertthevaluereturnedbythe
@ResponseBody annotated method intothe format specified by the Accept header. For instance, if the
Accept header value is application/json, Spring Web MVC uses
MappingJackson2HttpMessageConverter (an implementation of HttpMessageConverter) to convert the
valuereturnedbythe@ResponseBodyannotatedmethodintoJSONformat.TheFixedDepositWSClient
specifies the value of Accept header as application/json; therefore, the value returned by
FixedDepositController’sgetFixedDepositListmethodisconvertedtoJSONformat.
The RestTemplate’s exchange method returns an instance of ResponseEntity which represents the
responsereturnedbythewebservice.Asthegenerictypeoftheresponsereceivedfrominvocationof
FixedDepositController’s getFixedDepositList is List<FixedDepositDetails>, an instance of
ParameterizedTypeReference<List<FixedDepositDetails>>iscreatedandpassedtotheexchangemethod.
YoucancallResponseEntity’sgetBodymethodtoretrievetheresponsereturnedbythewebservice.In
example listing 12-15, ResponseEntity’s getBody method returns an object of type
List<FixedDepositDetails>thatrepresentsthelistoffixeddepositsreturnedbytheFixedDepositWSweb
service.
The following figure shows the role played by MappingJackson2HttpMessageConverter when
FixedDepositWSClientinvokesFixedDepositController’sgetFixedDepositListmethod:
Figure 12-4 FixedDepositWSClient’s getFixedDepositList method uses RestTemplate to send a web
requesttoFixedDepositWSwebservice
TheabovefigureshowsthatMappingJackson2HttpMessageConverterisusedtoconvertthereturnvalue
of FixedDepositController’s getFixedDepositList method into JSON format. Also,
MappingJackson2HttpMessageConverter is used by the RestTemplate to convert the JSON response
receivedfromtheFixedDepositControllertoaJavaobjectoftypeList<FixedDepositDetails>.
In examplelisting 12-15,RestTemplate’s exchange method was used to send anHTTP GET request to
FixedDepositWSwebservice.TheexchangemethodistypicallyusediftheHTTPresponsefromtheweb
serviceneedstobeconvertedtoaJavagenerictype,andtosendHTTPrequestheaders.RestTemplate
alsodefinesHTTPmethod-specificmethodsthatsimplifywritingRESTfulclients.Forinstance,youcan
usegetForEntitymethodtosendHTTPGETrequest,postForEntitytosendHTTPPOSTrequest,deleteto
sendHTTPDELETErequest,andsoon.
The following example listing shows FixedDepositWSClient’sopenFixedDeposit method that sends an
HTTPPOSTrequesttoFixedDepositWSwebservicetocreateanewfixeddeposit:
Examplelisting12-16–FixedDepositWSClient’sopenFixedDepositmethod
Project–ch12-webservice-client
Sourcelocation-src/main/java/sample/spring/chapter12
packagesample.spring.chapter12;
importorg.springframework.http.ResponseEntity;
importorg.springframework.web.client.RestTemplate;
.....
publicclassFixedDepositWSClient{
.....
privatestaticvoidopenFixedDeposit(RestTemplaterestTemplate){
FixedDepositDetailsfdd=newFixedDepositDetails();
fdd.setDepositAmount("9999");
.....
ResponseEntity<FixedDepositDetails>responseEntity=restTemplate
.postForEntity("http://localhost:8080/ch12-webservice/fixedDeposits",
fdd,FixedDepositDetails.class);
FixedDepositDetailsfixedDepositDetails=responseEntity.getBody();
.....
}
}
FixedDepositWSClient’sopenFixedDepositmethodsendsdetailsofthefixeddeposittobecreatedtothe
FixedDepositWSweb service.Ifthefixeddepositiscreatedsuccessfully,FixedDepositWSreturnsthe
newly created FixedDepositDetails object containing the unique identifier assigned to it. The above
examplelistingshowsthatRestTemplate’spostForEntitymethodacceptswebserviceURL,objecttobe
POSTed (which is FixedDepositDetails object), and the HTTP response type (which is
FixedDepositDetails.class). Sending HTTP POST request to http://localhost:8080/ch12-
webservice/fixedDeposits URL results in invocation of FixedDepositController’s openFixedDeposit
method(referexamplelisting12-9orFixedDepositControllerclassofch12-webserviceproject).
FixedDepositController’s openFixedDeposit method validates details of the fixed deposit before
attempting to create the fixed deposit. FixedDepositDetailsValidator is responsible for validating the
fixeddepositdetails.Ifthefixeddepositamountislessthan1000ortenureislessthan12monthsorifthe
email id specified is not well-formed, an exception is thrown by the openFixedDeposit method. The
following example listing shows openFixedDeposit and handleException methods of
FixedDepositController:
Examplelisting12-17–openFixedDepositandhandleExceptionmethodsofFixedDepositController
Project–ch12-webservice
Sourcelocation-src/main/java/sample/spring/chapter12/web
packagesample.spring.chapter12.web;
importorg.springframework.validation.BindingResult;
importorg.springframework.web.bind.annotation.ExceptionHandler;
importsample.spring.chapter12.exception.ValidationException;
.....
@Controller
@RequestMapping(value="/fixedDeposits")
publicclassFixedDepositController{
.....
@RequestMapping(method=RequestMethod.POST)
publicResponseEntity<FixedDepositDetails>openFixedDeposit(
@RequestBodyFixedDepositDetailsfixedDepositDetails,BindingResultbindingResult){
newFixedDepositDetailsValidator().validate(fixedDepositDetails,bindingResult);
if(bindingResult.hasErrors()){
thrownewValidationException("Validationerrorsoccurred");
}else{
fixedDepositService.saveFixedDeposit(fixedDepositDetails);
.....
}
@ExceptionHandler(ValidationException.class)
@ResponseBody
@ResponseStatus(value=HttpStatus.BAD_REQUEST)
publicStringhandleException(Exceptionex){
returnex.getMessage();
}
}
.....
}
TheaboveexamplelistingshowsthattheopenFixedDepositmethodthrowsValidationExceptioniffixed
deposit fails validation. As the handleException method is annotated with
@ExceptionHandler(ValidationException.class), the ValidationException thrown by the
openFixedDeposit method is handled by the handleException method. @ResponseBody and
@ResponseStatus(value=HttpStatus.BAD_REQUEST) annotations specify that the exception message
returned by the handleException method is written to the response body and the status code is set to
HttpStatus.BAD_REQUESTconstant(whichcorrespondstoHTTPstatuscode400).
FixedDepositWSClient’sopenInvalidFixedDepositmethodattemptstocreateafixeddepositwithdeposit
amount100,asshownhere:
Examplelisting12-18–FixedDepositWSClient-openInvalidFixedDepositmethod
Project–ch12-webservice-client
Sourcelocation-src/main/java/sample/spring/chapter12
privatestaticvoidopenInvalidFixedDeposit(RestTemplaterestTemplate){
FixedDepositDetailsfdd=newFixedDepositDetails();
fdd.setDepositAmount("100");
fdd.setEmail("99@somedomain.com");
fdd.setTenure("12");
ResponseEntity<FixedDepositDetails>responseEntity=restTemplate
.postForEntity("http://localhost:8080/ch12-webservice/fixedDeposits",
fdd,FixedDepositDetails.class);
FixedDepositDetailsfixedDepositDetails=responseEntity.getBody();
logger.info("Detailsofthenewlycreatedfixeddeposit:"
+fixedDepositDetails);
}
The openInvalidFixedDeposit method uses RestTemplate to send request to FixedDepositController’s
openFixedDeposit method. As the fixed deposit amount is specified as 100, FixedDepositController’s
openFixedDeposit method throws ValidationException (refer example listing 12-17).
FixedDepositController’s handleException method (refer example listing 12-17) handles the
ValidationExceptionandsetstheHTTPresponsestatusto400.Astheresponsestatuscodereceivedby
RestTemplateis400,thehandlingofresponseisdelegatedtotheMyErrorHandlerimplementation(refer
examplelisting12-12and12-13)thatweconfiguredfortheRestTemplate.
RestTemplateallowsclientstosynchronouslyaccessRESTfulwebservices.Let’snowlookathowto
asynchronouslyaccessRESTfulwebservicesusingSpring’sAsyncRestTemplate.
AsynchronouslyaccessingRESTfulwebservicesusingAsyncRestTemplate
ToallowclientstoasynchronouslyaccessRESTfulwebservices,SpringprovidesAsyncRestTemplate.
The following example listing shows how AsyncRestTemplate is configured in the application context
XMLfileofch12-webservice-clientproject:
Examplelisting12-19–applicationContext.xml-AsyncRestTemplateconfiguration
Project–ch12-webservice-client
Sourcelocation-src/main/resources/META-INF/spring
<beans.....>
.....
<beanid="errorHandler"class="sample.spring.chapter12.MyErrorHandler"/>
<beanid="asyncRestTemplate"class="org.springframework.web.client.AsyncRestTemplate">
<propertyname="errorHandler"ref="errorHandler"/>
</bean>
</beans>
If you compare the above example listing with the example listing 12-12, you’ll notice that both
AsyncRestTemplate and RestTemplate classes are configured in the same way; they use the same
MyErrorHandlerinstanceforhandlingHTTPerrors.
AsyncRestTemplate class defines methods that are similar to the methods defined by the RestTemplate
class. The following example listing shows the FixedDepositWSAsyncClient class that uses
AsyncRestTemplatetoaccessFixedDepositWSwebservice:
Examplelisting12-20–FixedDepositWSAsyncClient-openFixedDepositmethod
Project–ch12-webservice-client
Sourcelocation-src/main/java/sample/spring/chapter12
packagesample.spring.chapter12;
importorg.springframework.http.HttpEntity;
importorg.springframework.util.concurrent.ListenableFuture;
importorg.springframework.util.concurrent.ListenableFutureCallback;
importorg.springframework.web.client.AsyncRestTemplate;
publicclassFixedDepositWSAsyncClient{
privatestaticApplicationContextcontext;
publicstaticvoidmain(Stringargs[]){
context=newClassPathXmlApplicationContext(
"classpath:META-INF/spring/applicationContext.xml");
.....
openFixedDeposit(context.getBean(AsyncRestTemplate.class));
}
privatestaticvoidopenFixedDeposit(AsyncRestTemplaterestTemplate){
FixedDepositDetailsfdd=newFixedDepositDetails();
fdd.setDepositAmount("9999");
.....
HttpEntity<FixedDepositDetails>requestEntity=newHttpEntity<FixedDepositDetails>(fdd);
ListenableFuture<ResponseEntity<FixedDepositDetails>>futureResponseEntity=
restTemplate.postForEntity("http://localhost:8080/ch12-webservice/fixedDeposits",
requestEntity,FixedDepositDetails.class);
futureResponseEntity
.addCallback(newListenableFutureCallback<ResponseEntity<FixedDepositDetails>>(){
@Override
publicvoidonSuccess(ResponseEntity<FixedDepositDetails>entity){
FixedDepositDetailsfixedDepositDetails=entity.getBody();
}
@Override
publicvoidonFailure(Throwablet){}
});
}
}
TheaboveexamplelistingshowsthattheopenFixedDepositmethodusesAsyncRestTemplatetosenda
request to FixedDepositWS web service. AsyncRestTemplate’s postForEntity method sends an HTTP
POSTrequesttoFixedDepositWSwebservicethatinvokesFixedDepositController’sopenFixedDeposit
method. If you compare the AsyncRestTemplate’s postForEntity method shown above with that of
RestTemplate’s postForEntity method (refer example listing 12-16), you’ll notice that the
AsyncRestTemplate’s postForEntity returns an object of type ListenableFuture (that extends
java.util.concurrent.Future interface). ListenableFuture’s addCallback method is used to register a
callback that is triggered when the ListenableFuture task completes. ListenableFuture’s addCallback
method accepts an argument of type ListenableFutureCallback that defines onSuccess and onFailure
methods.TheonSuccessmethodiscalledwhentheListenableFuturetaskcompletessuccessfully,andthe
onFailuremethodiscalledwhentheListenableFuturetaskfailstocomplete.
YoushouldnotethatbydefaultAsyncRestTemplateusesaSimpleAsyncTaskExecutortoasynchronously
executeeachrequestinanewthread.YoucanpassaThreadPoolTaskExecutortoAsyncRestTemplate’s
constructor toasynchronously execute tasks using a thread from a threadpool. Refer to section 8-6 of
chapter8tolearnmoreaboutSimpleAsyncTaskExecutorandThreadPoolTaskExecutor.
Let’snowlookatthepurposeservedbyHttpMessageConvertersinSpringWebMVC.
12-5 Converting Java objects to HTTP requests and responses and
viceversausingHttpMessageConverter
HttpMessageConvertersareusedbySpringinthefollowingscenariostoperformconversion:
§ifamethodargumentisannotatedwith@RequestBodyannotation,SpringconvertsHTTPrequest
bodytotheJavatypeofthemethodargument
§ifamethodisannotatedwith@ResponseBodyannotation,SpringconvertsthereturnedJavaobject
fromthemethodtoHTTPresponsebody
§ifthereturntypeofamethodisHttpEntityorResponseEntity,Springconvertstheobjectreturnedby
themethodtotheHTTPresponsebody
§objectspassedtoandreturnedfromthemethodsofRestTemplateandAsyncRestTemplateclasses
likegetForEntity,postForEntity,exchange, and so on, are converted to HTTP requests and from
HTTPresponsesbySpring
ThefollowingtabledescribessomeoftheHttpMessageConverterimplementationsthatareprovidedout-
of-the-boxbySpringWebMVC:
HttpMessageConverterimplementation Description
StringHttpMessageConverter
convertsto/fromstrings
FormHttpM essageConverter
convertsformdatato/fromMultiValueMap<String,String> type.
ThisHttpM essageConverterisusedbySpringwhendealingwith
formdataandfileuploads.
MappingJackson2HttpM essageConverter convertsto/fromJSON
MarshallingHttpMessageConverter convertsto/fromXM L
HttpMessageConverters mentioned in the above table are automatically registered with the Spring
container by the <annotation-driven> element of Spring’s mvc schema. To view the complete list of
HttpMessageConvertersthatareregisteredbydefaultby<annotation-driven>element,refertotheSpring
Frameworkreferencedocumentation.
Let’s now look at @PathVariable and @MatrixVariable annotations that further simplify developing
RESTfulwebservicesusingSpringWebMVC.
12-6@PathVariableand@MatrixVariableannotations
Instead of specifying the actual URI, a @RequestMapping annotation may specify a URI template to
access specific parts of the request URI. A URI template contains variable names (specified within
braces) whose values are derived from the actual request URI. For example, the URI template
http://www.somebank.com/fd/{fixeddeposit} contains the variable name fixeddeposit. If the request
actual request URI is http://www.somebank.com/fd/123, the value of {fixeddeposit} URI template
variablebecomes123.
@PathVariable is a method argument level annotation that is used by @RequestMapping methods to
assignvalueofaURItemplatevariabletothemethodargument.
IMPORTchapter 12/ch12-webservice-uritemplates and chapter 12/ch12-webservice-client-
uritemplates(ch12-webservice-uritemplatesprojectisavariantofch12-webserviceprojectthatshows
the implementation of FixedDepositWS RESTful web service using @PathVariable annotation. ch12-
webservice-client-uritemplatesisavariantofch12-webservice-clientthataccessestheFixedDepositWS
webservicerepresentedbych12-webservice-uritemplatesproject.)
The following example listing shows usage of @PathVariable annotation in FixedDepositController of
ch12-webservice-uritemplatesproject:
Examplelisting12-21–FixedDepositController-@PathVariableusage
Project–ch12-webservice-uritemplates
Sourcelocation-src/main/java/sample/spring/chapter12/web
packagesample.spring.chapter12.web;
importorg.springframework.web.bind.annotation.PathVariable;
.....
@Controller
publicclassFixedDepositController{
.....
@RequestMapping(value="/fixedDeposits/{fixedDepositId}",method=RequestMethod.GET)
publicResponseEntity<FixedDepositDetails>getFixedDeposit(
@PathVariable("fixedDepositId")intid){
returnnewResponseEntity<FixedDepositDetails>(
fixedDepositService.getFixedDeposit(id),HttpStatus.OK);
}
.....
}
InsteadofspecifyingtheactualURI,@RequestMappingannotationintheaboveexamplelistingspecifies
/fixedDeposits/{fixedDepositId}URItemplate.Now,iftheincomingrequestURIis/fixedDeposits/1,the
value of fixedDepositId URI template variable is set to 1. As the @PathVariable annotation specifies
fixedDepositIdasthename of the URI templatevariable,value1 is assigned totheidargument ofthe
getFixedDepositmethod.
If a URI template defines multiple variables, the @RequestMapping method can define multiple
@PathVariableannotatedarguments,asshowninthefollowingexamplelisting:
Examplelisting12-22–MultipleURItemplatevariables
@Controller
publicclassSomeController{
.....
@RequestMapping(value="/users/{userId}/bankstatements/{statementId}",.....)
publicvoidgetBankStatementForUser(
@PathVariable("userId")Stringuser,
@PathVariable("statementId")Stringstatement){
.....
}
}
Intheaboveexamplelisting,theURItemplatedefinesuserIdandstatementIdvariables.Iftheincoming
requestURIis/users/me/bankstatements/123,valuemeisassignedtotheuserargumentandvalue123is
assignedtothestatementargument.
IfyouwanttoassignalltheURItemplatevariablesandtheirvaluestoamethodargument,youcanuse
@PathVariableannotationonaMap<String,String>argument type,as shown inthefollowing example
listing:
Examplelisting12-23–AccessingallURItemplatevariablesandtheirvalues
@Controller
publicclassSomeController{
.....
@RequestMapping(value="/users/{userId}/bankstatements/{statementId}",.....)
publicvoidgetBankStatementForUser(
@PathVariableMap<String,String>allVariables){
.....
}
}
Intheaboveexamplelisting,URItemplatevariables(userIdandstatementId)andtheirvalues(meand
123)areassignedtotheallVariablesmethodargument.
YoushouldnotethatURItemplatecanalsobespecifiedbyclasslevel@RequestMappingannotation,as
shownhere:
Example listing 12-24 – URI template specified at both class and method level @RequestMapping
annotations
@Controller
@RequestMapping(value="/service/{serviceId}",.....)
publicclassSomeController{
.....
@RequestMapping(value="/users/{userId}/bankstatements/{statementId}",.....)
publicvoidgetBankStatementForUser(@PathVariableMap<String,String>allVariables){
.....
}
}
In the above example listing, URI template /service/{serviceId} is specified by the class level
@RequestMapping annotation, and /users/{userId}/bankstatements/{statementId} is specified by the
method level @RequestMapping annotation. If the request URI is
/service/bankingService/users/me/bankstatements/123, the allVariables argument contains details of
serviceId,userIdandstatementIdURItemplatevariables.
Thescenariosinwhichyoumaywanttohavefine-grainedcontroloverwhattoextractfromtherequest
URI,you canuse regular expressions in URItemplates. The following example listingshows usageof
regularexpressionstoextract123.jsonvaluefrom/statements/123.jsonrequestURI:
Examplelisting12-25–URItemplates–regularexpressionsusage
@Controller
publicclassSomeController{
.....
@RequestMapping(value="/bankestatement/{statementId:[\\d\\d\\d]}.{responseType:[a-z]}",..)
publicvoidgetBankStatementForUser(@PathVariable("statementId")Stringstatement,
@PathVariable("responseType")StringresponseTypeExtension){
.....
}
}
Regular expressions in URI templates are specified in the following format: {variable-name:regular-
expression}.IftherequestURIis/statements/123.json,statementIdvariableisassignedthevalue123and
responseTypeisassignedthevaluejson.
NOTEYoucanalsouseAnt-stylepatternsinURItemplates.Forinstance,youcanspecifypatterns,like
/myUrl/*/{myId}and/myUrl/**/{myId}asURItemplates.
So far in this section we have seen examples of how to use @PathVariable to selectively extract
information from the request URI path. Let’s now look at @MatrixVariable annotation that is used to
extractname-valuepairsfrompathsegments.
Matrix variables appear as name-value pairs in the request URI, and you can assign value of these
variablestomethodarguments.Forinstance,intherequestURI/bankstatement/123;responseType=json,
theresponseTypevariablerepresentsamatrixvariablewhosevalueisjson.
NOTE You should note that by default Spring removes matrix variables from the URL. To ensure that
matrix variables are not removed, set the enable-matrix-variables attribute of <annotation-driven>
elementofSpringmvcschematotrue.Whenusingmatrixvariables,thepathsegmentsthatcontainmatrix
variablesmustberepresentedbyURItemplatevariables.
Thefollowingexamplelistingshowsusageof@MatrixVariableannotation:
Examplelisting12-26–@MatrixVariableannotation
@Controller
publicclassSomeController{
.....
@RequestMapping(value="/bankestatement/{statementId}",..)
publicvoidgetBankStatementForUser(@PathVariable("statementId")Stringstatement,
@MatrixVariable("responseType")StringresponseTypeExtension){
.....
}
}
Intheaboveexamplelisting,iftherequestURIis/bankstatement/123;responseType=json,thevaluejson
is assigned to responseTypeExtension argument. The above example listing also shows a scenario in
which both @PathVariable and @MatrixVariable annotations are used to retrieve information from the
requestURI.
As matrix variables can appear in any path segment of the request URI, you should specify the path
segment from which the matrix variable should be retrieved. The following example listing shows a
scenarioinwhichtwomatrixvariableswiththesamenamearepresentindifferentpathsegments:
Examplelisting12-27–@MatrixVariableannotation–multiplematrixvariableswiththesamename
@Controller
publicclassSomeController{
.....
@RequestMapping(value="/bankestatement/{statementId}/user/{userId}",..)
publicvoidgetBankStatementForUser(
@MatrixVariable(value="id",pathVar="statementId")intsomeId,
@MatrixVariable(value="id",pathVar="userId")intsomeOtherId){
.....
}
}
ThepathVarattributeof@MatrixVariableannotationspecifiesthenameoftheURItemplatevariablethat
contains the matrix variable. So, if the request URI is /bankstatement/123;id=555/user/me;id=777, the
value555isassignedtosomeId,andthevalue777isassignedtosomeOtherIdargument.
Asincaseof@PathVariableannotation,youcanannotateamethodargumenttypeofMap<String,String>
with@MatrixVariabletoassignallthematrixvariablestothemethodargument.Unlike@PathVariable
annotation, @MatrixVariable annotation allows you to specify a default value for the matrix variable
usingdefaultValueattribute.Also,youcansetrequiredattributeof@MatrixVariableannotationtofalseto
indicatethatthematrixvariableisoptional.Bydefault,thevalueofrequiredattributeissettotrue.Ifthe
requiredattributeissettotrue,andthematrixvariableisnotfoundintherequest,thenanexceptionis
thrown.
12-7Summary
Inthischapter,welookedathowtodevelopRESTfulwebservicesandaccessthem.Welookedathow
touseURItemplatesalongwith@PathVariableand@MatrixVariableannotationstoaccessinformation
from the request URI. We also looked at how to access RESTful web services synchronously using
RestTemplateandasynchronouslyusingAsyncRestTemplate.
Chapter13–MoreSpringWebMVC–internationalization,
fileuploadandasynchronousrequestprocessing
13-1Introduction
Inearlierchapters,wesawthatSpringWebMVCsimplifiescreatingwebapplicationsandRESTfulweb
services.Inthischapter,we’lllookatsomemorefeaturesofferedbySpringWebMVCframeworkthat
youmayrequireinyourwebapplications.We’llparticularlylookat:
§pre-andpost-processingrequestsusinghandlerinterceptors
§internationalizingSpringWebMVCapplications
§asynchronouslyprocessingrequests
§performingtypeconversionandformatting,and
§uploadingfiles
IMPORTchapter13/ch13-bankapp(Thisprojectisavariantofch10-bankappprojectthatdemonstrates
howtoincorporateinternationalizationinMyBankwebapplication,andhowtousehandlerinterceptors.)
Let’sbeginbylookingathowtopre-andpost-processrequestsusinghandlerinterceptors.
13-2Pre-andpost-processingrequestsusinghandlerinterceptors
Handlerinterceptorsallowyoutopre-andpost-processrequests.Theconceptofhandlerinterceptorsis
similartothatofservletfilters.HandlerinterceptorsimplementSpring’sHandlerInterceptorinterface.A
handlerinterceptor containsthepre- and post-processing logicthatisrequired bymultiplecontrollers.
Forinstance,youcanusehandlerinterceptorsforlogging,securitychecks,changinglocale,andsoon.
Let’snowlookathowtoimplementandconfigurehandlerinterceptors.
Implementingandconfiguringahandlerinterceptor
You can create handler interceptors by implementing HandlerInterceptor interface. HandlerInterceptor
interfacedefinesthefollowingmethods:
§preHandle–thismethodisexecutedbeforethecontrollerprocessestherequest.IfthepreHandle
method returns true, the controller is invoked by Spring to process the request. If the preHandle
methodreturnsfalse,thecontrollerisnotinvoked.
§postHandle–thismethodisexecutedafterthecontrollerprocessestherequest,butbeforetheview
isrenderedbytheDispatcherServlet.
§afterCompletion–thismethodisinvokedafterthecompletionofrequestprocessing(thatis,after
theviewisrenderedbytheDispatcherServlet)todoanycleanup,ifrequired.
The following example listing shows MyRequestHandlerInterceptor class of ch13-bankapp that
implementsHandlerInterceptorinterface:
Examplelisting13-1–MyRequestHandlerInterceptor
Project–ch13-bankapp
Sourcelocation-src/main/java/sample/spring/chapter13/web
packagesample.spring.chapter13.web;
importorg.springframework.web.servlet.HandlerInterceptor;
.....
publicclassMyRequestHandlerInterceptorimplementsHandlerInterceptor{
.....
publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,
Objecthandler)throwsException{
logger.info("HTTPmethod-->"+request.getMethod());
Enumeration<String>requestNames=request.getParameterNames();
.....
returntrue;
}
publicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,
Objecthandler,ModelAndViewmodelAndView)throwsException{
logger.info("Statuscode-->"+response.getStatus());
}
publicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,
Objecthandler,Exceptionex)throwsException{
logger.info("Requestprocessingcomplete");
}
}
Intheaboveexamplelisting,thepreHandlemethodinspectseachincomingrequestandlogstheHTTP
methodassociatedwiththerequestandtherequestparameterscontainedintherequest.ThepreHandle
methodreturnstrue,which means thatthe requestwill be processed by thecontroller.The postHandle
method logs the HTTP response status code. The afterCompletion method logs the message that the
requestwassuccessfullyprocessed.
NOTE Instead of directly implementing the HandlerInterceptor interface, you can extend the abstract
HandlerInterceptorAdapter class that provides empty implementations for postHandle and
afterCompletionmethods,andthepreHandlemethodisdefinedtosimplyreturntrue.
The following example listing shows how handler interceptors are configured in the web application
contextXMLfile:
Examplelisting13-2–MyRequestHandlerInterceptor
Project–ch13-bankapp
Sourcelocation-src/main/webapp/WEB-INF/spring/bankapp-config.xml
<beans.....xmlns:mvc="http://www.springframework.org/schema/mvc".....>
<mvc:annotation-driven/>
<mvc:interceptors>
.....
<beanclass="sample.spring.chapter13.web.MyRequestHandlerInterceptor"/>
</mvc:interceptors>
</beans>
The above example listing shows that the <interceptors> element of Spring’s mvc schema is used for
configuringhandlerinterceptors.The<interceptors>elementcanhavethefollowingsub-elements:
§ <bean> element of Spring’s beans schema - specifies a Spring bean that implements the
HandlerInterceptor interface. A handler interceptor defined using <bean> element applies to all
requests.
§ <ref> element of Spring’s beans schema - refers to a Spring bean that implements the
HandlerInterceptor interface. A handler interceptor defined using <ref> element applies to all
requests.
§ <interceptor> element of Spring’s mvc schema – specifies a Spring bean that implements the
HandlerInterceptorinterface,andtherequestURIstowhichtheHandlerInterceptorapplies.
The following example listing shows a scenario in which MyRequestHandlerInterceptor is mapped to
/audit/**requestURI:
Examplelisting13-3–<mvc:interceptor>usage
<beans.....xmlns:mvc="http://www.springframework.org/schema/mvc".....>
<mvc:annotation-driven/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mappingpath="/audit/**"/>
<beanclass="sample.spring.chapter13.web.MyRequestHandlerInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
In the above example listing, <interceptor> element of Spring’s mvc schema is used for mapping
MyRequestHandlerInterceptorto/audit/**URIpattern.The<mapping>elementofSpring’smvcschema
specifies the request URI pattern to which the handler interceptor specified by the <bean> element
applies.
Let’snowlookathowtointernationalizeaSpringWebMVCapplication.
13-3Internationalizingusingresourcebundles
BeforedelvingintothedetailsofhowtointernationalizeSpringWebMVCapplications,let’slookatthe
internationalizationandlocalizationrequirementsoftheMyBankwebapplication.
MyBankwebapplication’srequirements
It is required that the MyBank web application supports English (en_US locale) and German (de_DE
locale) languages. The following figure shows one of the web pages of MyBank web application in
de_DElocale:
Figure13-1Webpagethatshowsthelistoffixeddepositsinde_DElocale.Ausercanselectalocale
fromthegivenoptions.
Theabovefigureshowsthatausercanchooseoneofthefollowinglanguages:English(US),German,or
English(Canada). If a user chooses German language option, the web pages are displayed in de_DE
locale.IfauserchoosesEnglish(US)languageoption,thewebpagesaredisplayedinen_USlocale.Ifa
userchoosesEnglish(Canada)languageoption,thewebpagesaredisplayedinen_CAlocale.
Let’s now look at how to address internationalization and localization requirements of MyBank web
application.
InternationalizingandlocalizingMyBankwebapplication
InSpringWebMVC,theDispatcherServletusesaLocaleResolverforautomaticallyresolvingmessages
basedontheuser’slocale.Tosupportinternationalization,youneedtoconfigurethefollowingbeansin
yourwebapplicationcontextXMLfile:
·LocaleResolver–resolvesthecurrentlocaleoftheuser
·MessageSource–resolvesmessagesfromresourcebundlesbasedonthecurrentlocaleofthe
user
· LocaleChangeInterceptor – allows changing current locale on every request based on a
configurablerequestparameter
The following example listing shows configuration of LocaleResolver, LocaleChangeInterceptor and
MessageSourcebeansinthewebapplicationcontextXMLfileofch13-bankappproject:
Examplelisting13-4–bankapp-config.xml
Project–ch13-bankapp
Sourcelocation-src/main/webapp/WEB-INF/spring
<beans.....>
<beanclass="org.springframework.web.servlet.i18n.CookieLocaleResolver"id="localeResolver">
<propertyname="cookieName"value="mylocale"/>
</bean>
<bean
class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
id="messageSource">
<propertyname="basenames"value="WEB-INF/i18n/messages"/>
</bean>
<mvc:interceptors>
.....
<beanclass="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<propertyname="paramName"value="lang"/>
</bean>
</mvc:interceptors>
.....
</beans>
Intheaboveexamplelisting,CookieLocaleResolver(animplementationofLocaleResolverinterface)has
been configured for locale resolution. If the locale information is stored in a cookie by the web
application,CookieLocaleResolverisusedforlocaleresolution.CookieLocaleResolver’s cookieName
propertyspecifiesthenameofthecookiethatcontainsthelocaleinformation.Ifthecookieisnotfoundin
the request, CookieLocaleResolver determines the locale either by looking at the default locale
(configured using defaultLocale property of CookieLocaleResolver) or by inspecting the Accept-
Language request header. Spring additionally provides the following built-in LocaleResolver
implementations that you can use: AcceptHeaderLocaleResolver (returns the locale specified by the
Accept-Language requestheader), SessionLocaleResolver (returns the locale information stored in the
HttpSessionoftheuser)andFixedLocaleResolver(alwaysreturnsafixeddefaultlocale).
Inadditiontoknowinguser’slocale,youmayalsowanttoknowuser’stimezonetoconvertdateandtime
in user’s time zone. LocaleContextResolver (introduced in Spring 4.0) not only provides the locale
information but also the time zone information of the user. CookieLocaleResolver,
SessionLocaleResolver and FixedLocaleResolver implement the LocaleContextResolver interface;
therefore,ifyouareusinganyoftheseresolversyoucanobtainuser’stimezoneinyourcontrollersusing
getTimeZonemethodofLocaleContextHolder(orRequestContextUtils)class.Ifyouonlywanttoobtain
the locale information in your controllers, you can use getLocale method of LocaleContextHolder (or
RequestContextUtils)class.
Spring provides a LocaleChangeInterceptor (a HandlerInterceptor) that uses a configurable request
parameter(specifiedbyparamNameproperty)tochangethecurrentlocaleoneveryrequest.Inexample
listing13-4,theparamNamepropertyissettolang.LocaleResolverdefinesasetLocalemethodthatis
used by the LocaleChangeInterceptor to change the current locale. If you don’t want to use
LocaleChangeInterceptor, thenyou can changetheuser’s localein your controller bycalling setLocale
methodofLocaleContextHolder(orRequestContextUtils)class.
Oncetheuser’slocaleisresolved,SpringusestheconfiguredMessageSourceimplementationtoresolve
messages.Springprovidesthefollowingbuilt-inimplementationsofMessageSourceinterface:
§ResourceBundleMessageSource–aMessageSourceimplementationthataccessesresourcebundles
usingthespecifiedbasenames
§ ReloadableResourceBundleMessageSource – similar to ResourceBundleMessageSource
implementation.Thisimplementationsupportsreloadingofresourcebundles.
Example listing 13-4 shows that the MyBank web application uses
ReloadableResourceBundleMessageSource.ThebasenamespropertyissettoWEB-INF/i18n/messages,
which means that the ReloadableResourceBundleMessageSource looks for resource bundles named
messages inside WEB-INF/i18n folder. So, if the user’s locale is resolved to en_US, the
ReloadableResourceBundleMessageSource willresolve messages from the messages_en_US.properties
file.
Ifyoulookat/src/main/webapp/WEB-INF/i18nfolderofch13-bankappproject,you’llfindthefollowing
propertiesfiles:messages.properties,messages_en_US.propertiesandmessages_de_DE.properties.The
messages_de_DE.properties file contains messages and labels for de_DE locale,
messages_en_US.properties contains messages and labels for en_US locale, and messages.properties
contains messages and labels that are shown when no locale-specific resource bundles are found. As
there is no messages_en_CA.properties file corresponding to en_CA locale, selecting the
English(Canada)option(referfigure13-1)showsmessagesfromthemessages.propertiesfile.
In figure 13-1, we saw that we can change the language of the MyBank web application by selecting
English(US), English(Canada) and German language options. We saw earlier that the
LocaleChangeInterceptorcanchangethelocaleoftheMyBankwebapplicationifthelocaleinformation
iscontainedinarequestparameternamedlang.Tosimplifychangingthelocale,langrequestparameteris
appended to the hyperlinks shown by English(US), English(Canada) and German language options, as
shownhere:
Examplelisting13-5–fixedDepositList.jsp
Project–ch13-bankapp
Sourcelocation-src/main/webapp/WEB-INF/jsp
<b>Language:</b>
<ahref="${pageContext.request.contextPath}/fixedDeposit/list?lang=en_US">English(US)</a>|
<ahref="${pageContext.request.contextPath}/fixedDeposit/list?lang=de_DE">German</a>|
<ahref="${pageContext.request.contextPath}/fixedDeposit/list?lang=en_CA">English(Canada)</a>
Let’snowlookathowyoucanasynchronouslyprocessrequestsinSpringWebMVCapplications.
13-4Asynchronouslyprocessingrequests
A @RequestMapping annotated method that returns a java.util.concurrent.Callable or Spring’s
DeferredResult object processes web requests asynchronously. If a @RequestMapping method returns
Callable,SpringWebMVCtakescareofprocessingtheCallableinanapplicationthread(andnot the
Servletcontainerthread)toproducetheresult.Ifa@RequestMappingmethodreturnsDeferredResult,it
isapplication’sresponsibilitytoprocesstheDeferredResultinanapplicationthread(andnottheServlet
containerthread)toproducetheresult.BeforedelvingintothedetailofhowCallableandDeferredResult
return values are processed, let’s look at how to configure a Spring Web MVC application to support
asynchronousrequestprocessing.
IMPORTchapter 13/ch13-async-bankapp (This project is a variant of ch10-bankapp project that
asynchronouslyprocessesrequests.@RequestMappingmethodsdefinedintheFixedDepositControllerof
this project return Callable. You should deploy and run the ch13-async-bankapp project to see
asynchronousrequestprocessinginaction.)
Asynchronousrequestprocessingconfiguration
AsasynchronousrequestprocessinginSpringWebMVCisbasedonServlet3,web.xml mustrefer to
Servlet 3 XML schema. Also, <async-supported> element must be added to the DispatcherServlet
definition in web.xml file to indicate that it supports asynchronous request processing. The following
examplelistingshowstheweb.xmlfileofch13-async-bankappproject:
Examplelisting13-6–web.xml–asynchronousrequestprocessingconfiguration
Project–ch13-async-bankapp
Sourcelocation-src/main/webapp/WEB-INF
<web-app.....
xsi:schemaLocation="java.sun.com/xml/ns/javaeejava.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
.....
<servlet>
<servlet-name>bankapp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
.....
<async-supported>true</async-supported>
</servlet>
.....
</web-app>
Theaboveexamplelistingshowsthatthebankappservletisconfiguredtosupportasynchronousrequest
processing.Now,thebankappservletcanasynchronouslyprocesswebrequests.
ReturningCallablefrom@RequestMappingmethods
The following example listing shows the FixedDepositController whose @RequestMapping methods
returnCallable:
Examplelisting13-7–FixedDepositController–returningCallablefrom@RequestMappingmethods
Project–ch13-async-bankapp
Sourcelocation-src/main/java/sample/spring/chapter13/web
packagesample.spring.chapter13.web;
importjava.util.concurrent.Callable;
.....
publicclassFixedDepositController{
.....
@RequestMapping(value="/list",method=RequestMethod.GET)
publicCallable<ModelAndView>listFixedDeposits(){
returnnewCallable<ModelAndView>(){
@Override
publicModelAndViewcall()throwsException{
Thread.sleep(5000);
Map<String,List<FixedDepositDetails>>modelData=
newHashMap<String,List<FixedDepositDetails>>();
modelData.put("fdList",fixedDepositService.getFixedDeposits());
returnnewModelAndView("fixedDepositList",modelData);
}
};
}
.....
}
TheaboveexamplelistingshowsthatthelistFixedDepositsmethodreturnsaCallable<T>object,where
Tisthetypeoftheresultthatisasynchronouslycomputed.TheCallable’scallmethodcontainsthelogic
that needs to be executed asynchronously to produce the result. The call method shown in the above
examplelistinginvokesFixedDepositService’sgetFixedDepositsmethod,andreturnsaModelAndView
objectcontainingthemodelandviewinformation.TheThread.sleepmethodisinvokedinthebeginning
ofcallmethodtosimulateascenarioinwhichtherequestprocessingtakestime.
If an exception is thrown during the execution of the Callable returned from the controller, the
@ExceptionHandler method (or the configured HandlerExceptionResolver bean) of the controller is
responsibleforhandlingtheexception.Formoreinformationon@ExceptionHandlerannotation,referto
section10-9ofchapter10.
Examplelisting13-7showsthatifyouwanttoswitchfromsynchronousrequestprocessingapproachto
asynchronousrequestprocessing,youneedtomovethelogicfromthe@RequestMappingmethodtothe
callmethodofCallable,andchangethereturntypeofthe@RequestMappingmethodtoCallable<T>.
Let’snowlookathowrequestsareasynchronouslyprocessedwhena@RequestMappingmethodreturns
aDeferredResultobject.
IMPORTchapter 13/ch13-async-webservice and ch13-async-webservice-client (The ch13-async-
webservice project is a variant of FixedDepositWS web service (refer ch12-webservice project of
chapter12)thatasynchronouslyprocesseswebservicerequests.@RequestMappingmethodsdefinedin
theFixedDepositControllerofthisprojectreturnaninstanceofDeferredResultobject.Thech13-async-
webservice-client project is same as the FixedDepositWS web service client (refer ch12-webservice-
clientprojectofchapter12)thatassumesthatthewebserviceisdeployedathttp://localhost:8080/ch13-
async-webservice.)
ReturningDeferredResultfrom@RequestMappingmethods
ADeferredResultinstancerepresentsaresultthatisasynchronouslycomputed.Yousettheresultonthe
DeferredResultinstancebycallingitssetResultmethod.Typically,a@RequestMappingmethodstoresa
DeferredResult instance in a Queue or a Map or any other data structure, and a separate thread is
responsibleforcomputingtheresultandsettingtheresultontheDeferredResultinstance.
Let’sfirstlookat@RequestMappingmethodsthatreturnDeferredResulttype.
@RequestMappingmethodimplementation
The following example listing shows the FixedDepositController whose @RequestMapping methods
returnDeferredResultobjects:
Example listing 13-8 – FixedDepositController – returning DeferredResult from @RequestMapping
methods
Project–ch13-async-webservice
Sourcelocation-src/main/java/sample/spring/chapter13/web
packagesample.spring.chapter13.web;
importjava.util.Queue;
importjava.util.concurrent.ConcurrentLinkedQueue;
importorg.springframework.web.context.request.async.DeferredResult;
.....
@Controller
@RequestMapping(value="/fixedDeposits")
publicclassFixedDepositController{
privatestaticfinalStringLIST_METHOD="getFixedDepositList";
privatestaticfinalStringGET_FD_METHOD="getFixedDeposit";
.....
privatefinalQueue<ResultContext>deferredResultQueue=
newConcurrentLinkedQueue<ResultContext>();
.....
@RequestMapping(method=RequestMethod.GET)
publicDeferredResult<ResponseEntity<List<FixedDepositDetails>>>getFixedDepositList(){
DeferredResult<ResponseEntity<List<FixedDepositDetails>>>dr=
newDeferredResult<ResponseEntity<List<FixedDepositDetails>>>();
ResultContext<ResponseEntity<List<FixedDepositDetails>>>resultContext=
newResultContext<ResponseEntity<List<FixedDepositDetails>>>();
resultContext.setDeferredResult(dr);
resultContext.setMethodToInvoke(LIST_METHOD);
resultContext.setArgs(newHashMap<String,Object>());
deferredResultQueue.add(resultContext);
returndr;
}
.....
}
Each@RequestMappingmethodofFixedDepositControllerperformsthesesteps:
Step1-createsaninstanceofDeferredResult<T>object,whereTrepresentsthetypeoftheresultthatis
asynchronously computed. As the type of the result computed for the getFixedDepositList method is
ResponseEntity<List<FixedDepositDetails>>, an instance of
DeferredResult<ResponseEntity<List<FixedDepositDetails>>>iscreated.
Step2-createsaninstanceofResultContextobject.ResultContextobjectholdsDeferredResultinstance
thatwecreatedinStep1,andotherdetailsthatarerequiredtoasynchronouslycomputetheresultforthe
DeferredResult object. In case of FixedDepositController’s getFixedDepositList method, result is
representedbythelist offixeddeposits obtainedbyinvokingFixedDepositService’s getFixedDeposits
method.
ThefollowingexamplelistingshowstheResultContextclass:
Examplelisting13-9–ResultContextclassforstoringDeferredResultandotherinformation
Project–ch13-async-webservice
Sourcelocation-src/main/java/sample/spring/chapter13/web
packagesample.spring.chapter13.web;
importjava.util.Map;
importorg.springframework.web.context.request.async.DeferredResult;
publicclassResultContext<T>{
privateStringmethodToInvoke;
privateDeferredResult<T>deferredResult;
privateMap<String,Object>args;
publicvoidsetDeferredResult(DeferredResult<T>deferredResult){
this.deferredResult=deferredResult;
}
.....
}
The deferredResult property refers to an instance of DeferredResult, the methodToInvoke property
specifies the name of the FixedDepositService method that is invoked to compute the result for the
DeferredResultobject,andargsproperty(oftypejava.util.Map)specifiestheargumentstobepassedto
the FixedDepositService method. A separate thread (as explained later in this section) uses the
methodToInvokeand args properties to invoke the specified FixedDepositService method, and sets the
returnedresultontheDeferredResultinstance.
AstheLIST_METHOD,GET_FD_METHOD,andsoon,constantsintheFixedDepositControllerclass
refertothenamesoftheFixedDepositServicemethods(referexamplelisting13-8),themethodToInvoke
property is set to the one of these constants. In example listing 13-8, FixedDepositController’s
getFixedDepositListmethodsetsthemethodToInvokepropertytoLIST_METHODconstant(whosevalue
is getFixedDeposits) because FixedDepositService’s getFixedDeposits method needs to be invoked to
obtaintheresultfortheDeferredResultobjectreturnedbyFixedDepositController’sgetFixedDepositList
method.
Step3-storestheResultContextinstancecreatedinStep2intoaQueue(refertodeferredResultQueue
instancevariableinexamplelisting13-8)
Step4-returnstheDeferredResultobjectcreatedinStep1
TheabovesequenceofstepssuggeststhatforeachwebrequestaninstanceofResultContextisstoredin
the deferredResultQueue. The following figure summarizes the actions that are performed by
FixedDepositController’sgetFixedDepositListmethod.
Figure 13-2 FixedDepositController’s getFixedDepositList method adds a ResultContext object to the
queueandreturnsaDeferredResultobject
Let’s now look at how the result is computed for the DeferredResult instance contained inside the
ResultContextobject.
ComputingresultforaDeferredResultinstance
FixedDepositController’s processResults method is responsible for iterating over the ResultContext
objects stored in the deferredResultQueue (refer example listing 13-8), computing the result for each
DeferredResultobject,andsettingtheresultontheDeferredResultobject.Thefollowingexamplelisting
showstheprocessResultsmethod:
Example listing 13-10 – processResults method – computing and setting results on DeferredResult
objects
Project–ch13-async-webservice
Sourcelocation-src/main/java/sample/spring/chapter13/web
packagesample.spring.chapter13.web;
importorg.springframework.scheduling.annotation.Scheduled;
importorg.springframework.web.context.request.async.DeferredResult;
@Controller
@RequestMapping(value="/fixedDeposits")
publicclassFixedDepositController{
privatestaticfinalStringLIST_METHOD="getFixedDepositList";
.....
privatefinalQueue<ResultContext>deferredResultQueue=
newConcurrentLinkedQueue<ResultContext>();
@Autowired
privateFixedDepositServicefixedDepositService;
.....
@Scheduled(fixedRate=10000)
publicvoidprocessResults(){
for(ResultContextresultContext:deferredResultQueue){
if(resultContext.getMethodToInvoke()==LIST_METHOD){
resultContext.getDeferredResult().setResult(
newResponseEntity<List<FixedDepositDetails>>(
fixedDepositService.getFixedDeposits(),HttpStatus.OK));
}
.....
deferredResultQueue.remove(resultContext);
}
}
}
@Scheduled annotation (refer section 8-6 of chapter 8 for more details) on processResults method
specifies that every 10 seconds an application thread is responsible for executing the processResults
method. The processResults method uses the method name and argument information stored in the
ResultContext instance to invoke the appropriate FixedDepositService’s method. The processResults
methodthensetstheresultontheDeferredResultinstancebycallingitssetResultmethod.Intheend,the
processResults method removes the ResultContext instance from the Queue. After processing a
ResultContextinstance,theprocessResultsmethodremovestheResultContextinstancefromtheQueueso
thatitisnotre-processedbytheprocessResultsmethodwhenitexecutesagainafter10seconds.
Figure 13-3 summarizes the actions performed by FixedDepositController’s processResults method to
computetheresultandsetitontheDeferredResultinstance.
Figure 13-3 The processResults method reads method name and argument information from the
ResultContextobjecttocomputetheresultfortheDeferredResultinstance
Let’s now look at how exceptions are handled when a @RequestMapping method returns a
DeferredResultinstance.
ExceptionHandling
Ifyousetanobjectoftypejava.lang.ExceptionusingDeferredResult’ssetErrorResultmethod,theresult
is handled by @ExceptionHandler annotated method of the controller (or by the configured
HandlerExceptionResolver bean). For more information on @ExceptionHandler annotation, refer to
section10-9ofchapter10.
The following example listing shows FixedDepositController’sopenFixedDeposit method that opens a
newfixeddeposit:
Examplelisting13-11–FixedDepositController’sopenFixedDepositmethod
Project–ch13-async-webservice
Sourcelocation-src/main/java/sample/spring/chapter13/web
packagesample.spring.chapter13.web;
@Controller
@RequestMapping(value="/fixedDeposits")
publicclassFixedDepositController{
privatestaticfinalStringOPEN_FD_METHOD="openFixedDeposit";
.....
privatefinalQueue<ResultContext>deferredResultQueue=
newConcurrentLinkedQueue<ResultContext>();
@RequestMapping(method=RequestMethod.POST)
publicDeferredResult<ResponseEntity<FixedDepositDetails>>openFixedDeposit(
@RequestBodyFixedDepositDetailsfixedDepositDetails,BindingResultbindingResult){
DeferredResult<ResponseEntity<FixedDepositDetails>>dr=
newDeferredResult<ResponseEntity<FixedDepositDetails>>();
ResultContext<ResponseEntity<FixedDepositDetails>>resultContext=
newResultContext<ResponseEntity<FixedDepositDetails>>();
resultContext.setDeferredResult(dr);
resultContext.setMethodToInvoke(OPEN_FD_METHOD);
Map<String,Object>args=newHashMap<String,Object>();
args.put("fixedDepositDetails",fixedDepositDetails);
args.put("bindingResult",bindingResult);
resultContext.setArgs(args);
deferredResultQueue.add(resultContext);
returndr;
}
.....
}
Theaboveexamplelistingshowsthatthearguments(fixedDepositDetailsandbindingResult)passedto
theopenFixedDepositmethodaresetontheResultContextinstancesothattheseargumentsareavailable
when the processResults method executes the logic for opening a new fixed deposit. The
fixedDepositDetailsargumentcontainsthedetailsofthefixeddeposittobeopenedandthebindingResult
argumentcontainstheresultsofdatabinding.
The following example listing shows how the processResults method executes the logic for opening a
newfixeddeposit:
Examplelisting13-12–FixedDepositController’sprocessResultsmethod
Project–ch13-async-webservice
Sourcelocation-src/main/java/sample/spring/chapter13/web
packagesample.spring.chapter13.web;
@Controller
@RequestMapping(value="/fixedDeposits")
publicclassFixedDepositController{
privatestaticfinalStringOPEN_FD_METHOD="openFixedDeposit";
.....
privatefinalQueue<ResultContext>deferredResultQueue=
newConcurrentLinkedQueue<ResultContext>();
@Autowired
privateFixedDepositServicefixedDepositService;
.....
@ExceptionHandler(ValidationException.class)
@ResponseBody
@ResponseStatus(value=HttpStatus.BAD_REQUEST)
publicStringhandleException(Exceptionex){
logger.info("handlingValidationException"+ex.getMessage());
returnex.getMessage();
}
@Scheduled(fixedRate=10000)
publicvoidprocessResults(){
for(ResultContextresultContext:deferredResultQueue){
.....
if(resultContext.getMethodToInvoke()==OPEN_FD_METHOD){
FixedDepositDetailsfixedDepositDetails=(FixedDepositDetails)resultContext
.getArgs().get("fixedDepositDetails");
BindingResultbindingResult=(BindingResult)resultContext.getArgs().get("bindingResult");
newFixedDepositDetailsValidator().validate(fixedDepositDetails,bindingResult);
if(bindingResult.hasErrors()){
logger.info("openFixedDeposit()method:Validationerrorsoccurred");
resultContext.getDeferredResult().setErrorResult(newValidationException(
"Validationerrorsoccurred"));
}else{
fixedDepositService.saveFixedDeposit(fixedDepositDetails);
resultContext.getDeferredResult().setResult(newResponseEntity<FixedDepositDetails>(
fixedDepositDetails,HttpStatus.CREATED));
}
}
.....
}
}
}
Theaboveexamplelistingshowsthe@ExceptionHandlerannotatedhandleExceptionmethodthathandles
exceptionsoftypeValidationException.ThehandleExceptionmethodlogsthatavalidationexceptionhas
occurredandreturnstheexceptionmessage.
To open a new fixed deposit, the processResults method retrieves the fixedDepositDetails (of type
FixedDepositDetails) and bindingResult (of type BindingResult) arguments from the ResultContext and
validates the fixedDepositDetails object by calling FixedDepositValidator’s validate method. If
validation errors are reported, the processResults method invokes DeferredResult’s setErrorResult
method to set ValidationException (of type java.lang.Exception) as the result. Setting the
ValidationExceptionusingDeferredResult’ssetErrorResult method will cause handling of the result by
FixedDepositController’shandleExceptionmethod.
It is recommended that you deploy the ch13-async-webservice project (which represents the
FixedDepositWS RESTful web service) and access it by running the main method of
FixedDepositWSClient of ch13-async-webservice-client project (which represents a client of
FixedDepositWSRESTfulwebservice).TheFixedDepositWSClient’sopenInvalidFixedDepositmethod
invokes FixedDepositController’s openFixedDeposit web service method such that it results in
ValidationException.YoucancheckthelogstoverifythattheFixedDepositController’shandleException
methodhandles the resultwhen processResultsmethodsets ValidationException on the DeferredResult
objectbycallingDeferredResult’ssetErrorResultmethod.
Let’snowlookathowtosetdefaulttimeoutvalueforasynchronousrequests.
Settingdefaulttimeoutvalue
You can set the default timeout value of asynchronous requests by using default-timeout attribute of
<async-support>element,asshownhere:
Examplelisting13-13–Settingdefaulttimeoutforasynchronousrequests
Project–ch13-async-webservice
Sourcelocation–src/main/webapp/WEB-INF/spring/webservice-config.xml
<mvc:annotation-driven>
<mvc:async-supportdefault-timeout="10000">
.....
</mvc:async-support>
</mvc:annotation-driven>
Intheaboveexamplelisting,defaulttimeoutforasynchronousrequestsissetto10seconds.Ifyoudon’t
specify the default timeout, the timeout for asynchronous requests depends on the Servlet container on
whichyoudeployedyourwebapplication.
Let’snowlookathowyoucaninterceptasynchronousrequestsusingCallableProcessingInterceptorand
DeferredResultProcessingInterceptor.
Interceptingasynchronousrequests
IfyouareusingCallabletoasynchronouslyprocessrequests,youcanuseCallableProcessingInterceptor
callbackinterfacetointerceptrequestsbeforeandaftertheCallable taskisexecuted.For instance,the
postProcessmethodisexecutedaftertheCallablehasproducedtheresult,andthepreProcessmethodis
called before the Callable task is executed. Similarly, if you are using DeferredResult, you can use
DeferredResultProcessingInterceptorcallbackinterfacetointerceptprocessingofasynchronousrequests.
YoucanconfigureaCallableProcessingInterceptorusing<callable-interceptors>elementofSpring’smvc
schema. And, you can configure a DeferredResultProcessingInterceptor using <deferred-result-
interceptors> element of Spring’s mvc schema. The following example listing shows configuration of
MyDeferredResultInterceptor(aDeferredResultProcessingInterceptorimplementation):
Examplelisting13-14–ConfiguringaDeferredResultProcessingInterceptorimplementation
Project–ch13-async-webservice
Sourcelocation–src/main/webapp/WEB-INF/spring/webservice-config.xml
<mvc:annotation-driven>
<mvc:async-supportdefault-timeout="30000">
<mvc:deferred-result-interceptors>
<beanclass="sample.spring.chapter13.web.MyDeferredResultInterceptor"/>
</mvc:deferred-result-interceptors>
</mvc:async-support>
</mvc:annotation-driven>
Let’snowlookatSpring’ssupportfortypeconversionandformatting.
13-5TypeconversionandformattingsupportinSpring
Spring’sConverter interface simplifies converting an object type to another object type. And, Spring’s
Formatter interface is useful when converting an object type to its localizedString representation, and
vice versa. You can find a number of built-in Converter implementations in the
org.springframework.core.convert.supportpackageofspring-coreJARfile.Springalsoprovidesbuilt-in
Formatters for java.lang.Number and java.util.Date types that you can find in
org.springframework.format.numberandorg.springframework.format.datetimepackages,respectively.
IMPORTchapter 13/ch13-converter-formatter-bankapp (This project is a variant of ch13-bankapp
projectthatshowshowtocreatecustomConvertersandFormatters)
Let’sfirstlookathowtocreateacustomConverter.
CreatingacustomConverter
AconverterimplementsSpring’sConverter<S,T>interface,whereS(referredtoasthesourcetype)is
thetypeoftheobjectgiventotheconverter,andT(referredtoasthetargettype)isthetypeoftheobject
towhichSisconvertedbytheconverter.Converterinterfacedefinesaconvertmethodthatprovidesthe
conversionlogic.
The following example listing shows the IdToFixedDepositDetailsConverter that converts an object of
typeString(representingthefixeddepositID)toanobjectoftypeFixedDepositDetails(representingthe
fixeddepositcorrespondingtothefixeddepositID):
Examplelisting13-15–Converterimplementation
Project–ch13-converter-formatter-bankapp
Sourcelocation–src/main/java/sample/spring/chapter13/converter
packagesample.spring.chapter13.converter;
importorg.springframework.core.convert.converter.Converter;
.....
publicclassIdToFixedDepositDetailsConverterimplementsConverter<String,FixedDepositDetails>{
@Autowired
privateFixedDepositServicefixedDepositService;
@Override
publicFixedDepositDetailsconvert(Stringsource){
returnfixedDepositService.getFixedDeposit(Integer.parseInt(source));
}
}
IdToFixedDepositDetailsConverterimplementsConverter<String,FixedDepositDetails>interface,where
StringisthesourcetypeandFixedDepositDetailsisthetargettype.IdToFixedDepositDetailsConverter’s
convertmethodusesFixedDepositService’sgetFixedDepositmethodtoretrievetheFixedDepositDetails
objectcorrespondingtothefixeddepositID.
Let’snowlookathowtoconfigureanduseacustomconverter.
ConfiguringandusingacustomConverter
Touseacustomconverter,youneedtoregisterthecustomconverterwithSpring’sConversionService.A
ConversionServiceactsasaregistryofConvertersandFormatters,andSpringdelegatestypeconversion
responsibility to the registered ConversionService. By default, the <annotation-driven> element of
Spring’smvcschemaautomaticallyregistersSpring’sFormattingConversionService(animplementation
ofConversionService)withtheSpringcontainer.Springcomeswithacoupleofbuilt-inconvertersand
formatters that are automatically registered with the FormattingConversionService. If you want to
substitute adifferentimplementation ofConversionService, you can doso byusing conversion-service
attributeof<annotation-driven>element.
To register custom converters with the FormattingConversionService instance, configure Spring’s
FormattingConversionServiceFactoryBean(a FactoryBean implementation that creates and configures a
FormattingConversionService instance) and specify custom converters as part of the configuration, as
showninthefollowingexamplelisting:
Examplelisting13-16–RegisteringacustomConverterwithFormattingConversionService
Project–ch13-converter-formatter-bankapp
Sourcelocation–src/main/webapp/WEB-INF/spring
<mvc:annotation-drivenconversion-service="myConversionService"/>
<beanid="myConversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<propertyname="converters">
<set>
<beanclass="sample.spring.chapter13.converter.IdToFixedDepositDetailsConverter"/>
</set>
</property>
.....
</bean>
By default, FormattingConversionServiceFactoryBean registers only the built-in converters and
formatterswiththeFormattingConversionServiceinstance.Youregistercustomconvertersandformatters
usingFormattingConversionServiceFactoryBean’sconvertersandformattersproperties.Aswewantour
Spring application to use FormattingConversionService instance created by the
FormattingConversionServiceFactoryBean, the conversion-service attribute of <annotation-driven>
elementreferstotheFormattingConversionServiceFactoryBean.
Theconvertersand formatters registered withtheFormattingConversionServiceareused bytheSpring
container to perform type conversion during data binding. In the following example listing,
FixedDepositController’s viewFixedDepositDetails method shows a scenario in which the Spring
containerusesIdToFixedDepositDetailsConverter<String,FixedDepositDetails>toconvertfixeddeposit
ID(oftypeString)toFixedDepositDetailsinstance:
Examplelisting13-17–FixedDepositController’sviewFixedDepositDetailsmethod
Project–ch13-converter-formatter-bankapp
Sourcelocation–src/main/java/sample/spring/chapter13/web
packagesample.spring.chapter13.web;
.....
publicclassFixedDepositController{
.....
@RequestMapping(params="fdAction=view",method=RequestMethod.GET)
publicModelAndViewviewFixedDepositDetails(
@RequestParam(value="fixedDepositId")FixedDepositDetailsfixedDepositDetails){
.....
}
}
@RequestParamannotationspecifiesthatthevalueoffixedDepositIdrequestparameterisassignedtothe
fixedDepositDetailsmethodargument.ThefixedDepositIdrequestparameteruniquelyidentifiesafixed
deposit. As the fixedDepositId request parameter is of type String and method argument type is
FixedDepositDetails, Spring uses IdToFixedDepositDetailsConverter<String, FixedDepositDetails> to
performthetypeconversion.
The use of ConversionService is not limited to the web layer. You can use ConversionService to
programmaticallyperformtypeconversioninanylayerofyourapplication.Thefollowingexamplelisting
shows a variant of FixedDepositController’s viewFixedDepositDetails method that uses
ConversionServicedirectlyforperformingtypeconversion:
Examplelisting13-18–Performingtypeconversionprogrammatically
importorg.springframework.core.convert.ConversionService;
.....
publicclassFixedDepositController{
@Autowired
privateConversionServiceconversionService;
.....
@RequestMapping(params="fdAction=view",method=RequestMethod.GET)
publicModelAndViewviewFixedDepositDetails(HttpServletRequestrequest){
StringfixedDepositId=request.getParameter("fixedDepositId");
FixedDepositDetailsfixedDepositDetails=
conversionService.convert(fixedDepositId,FixedDepositDetails.class);
.....
}
}
Intheaboveexamplelisting,ConversionServiceinstancethatisregisteredwiththeSpringcontaineris
autowired into the FixedDepositController. The viewFixedDepositDetails method uses
ConversionService’sconvertmethodtoconvertfixedDepositId(oftypeString)toFixedDepositDetails.
Behind the scenes, ConversionService makes use of the IdToFixedDepositDetailsConverter<String,
FixedDepositDetails>converterregisteredwithittoperformthetypeconversion.
NowthatwehaveseenhowtocreateanduseacustomConverter,let’snowlookathowtocreateanduse
acustomFormatter.
CreatingacustomFormatter
AformatterconvertsanobjectoftypeTtoaStringvaluefordisplaypurposes,andparsesaStringvalue
totheobjecttypeT.AformatterimplementsSpring’sFormatter<T>interface,whereTisthetypeofthe
objectthattheformatterformats.ThismaysoundsimilartowhatPropertyEditorsdoinwebapplications.
Aswe’llseeinthischapter,FormattersofferamorerobustalternativetoPropertyEditors.
NOTESpring’staglibrarytagsusetheformattersregisteredwiththeFormattingConversionServiceto
performtypeconversionduringdatabindingandrendering.
The following example listing shows the AmountFormatter that is used by the MyBank application to
display fixed deposit amount in the currency that applies to the user’s locale, and to parse the fixed
depositamountenteredbytheuser.Forsimplicity,currencyconversionisnotappliedonthefixeddeposit
amount; the currency symbol that applies to the user’s locale is simply appended to the fixed deposit
amount.
Examplelisting13-19–AmountFormatter-aFormatterimplementation
Project–ch13-converter-formatter-bankapp
Sourcelocation–src/main/java/sample/spring/chapter13/formatter
packagesample.spring.chapter13.formatter;
importjava.text.ParseException;
importjava.util.Locale;
importorg.springframework.format.Formatter;
publicclassAmountFormatterimplementsFormatter<Long>{
@Override
publicStringprint(Longobject,Localelocale){
StringreturnStr=object.toString()+"USD";
if(locale.getLanguage().equals(newLocale("de").getLanguage())){
returnStr=object.toString()+"EURO";
}
returnreturnStr;
}
@Override
publicLongparse(Stringtext,Localelocale)throwsParseException{
Stringstr[]=text.split("");
returnLong.parseLong(str[0]);
}
}
AmountFormatterimplementsFormatter<Long>interface,whichmeansthattheAmountFormatterapplies
to Long type objects. The print method converts the Long type object (representing the fixed deposit
amount) to a String value that is displayed to the user. Based on the language code obtained from the
locale,theprintmethodsimplyappendsUSD(forenlanguagecode)orEURO(fordelanguagecode)to
thefixeddepositamount.Forinstance,ifthefixeddepositamountis1000andthelanguagecodeisde,the
printmethodreturns‘1000EURO’.Theparsemethodtakesthefixeddepositamountenteredbytheuser
(like,‘1000EURO’)andconvertsitintoaLongtypeobjectbysimplyextractingthefixeddepositamount
fromtheuserenteredvalue.
Let’snowlookathowtoconfigureacustomformatter.
ConfiguringacustomFormatter
YoucanregistercustomformatterswiththeFormattingConversionServiceusingtheformatterspropertyof
FormattingConversionServiceFactoryBean,asshownhere:
Examplelisting13-20–RegisteringacustomFormatterwithFormattingConversionService
<beans.....>
.....
<mvc:annotation-drivenconversion-service="myConversionService"/>
.....
<beanid="myConversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<propertyname="formatters">
<set>
<beanclass="sample.spring.chapter13.formatter.AmountFormatter"/>
</set>
</property>
</bean>
</beans>
AmountFormatterregisteredwiththeFormattingConversionServiceisappliedtoalltheLongtypefields
duringdatabindingandrendering.
YoucancontrolthefieldsonwhichaFormatterappliesbyusingSpring’sAnnotationFormatterFactory.
An AnnotationFormatterFactory implementation creates formatters for fields that are annotated with a
particularannotation.Let’sseehowwecanuseAnnotationFormatterFactorytoformatonlytheLongtype
fieldsannotatedwith@AmountFormatannotation.
CreatingAnnotationFormatterFactorytoformatonly@AmountFormatannotated
fields
Thefollowingexamplelistingshowsthedefinitionof@AmountFormatannotation:
Examplelisting13-21–AmountFormatannotation
Project–ch13-converter-formatter-bankapp
Sourcelocation–src/main/java/sample/spring/chapter13/formatter
packagesample.spring.chapter13.formatter;
.....
@Target(value={ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public@interfaceAmountFormat{}
In theabove examplelisting, the@Target annotation specifies that the @AmountFormat annotation can
onlyappearonfields.
The following example listing shows the implementation of AnnotationFormatterFactory that creates
formattersforfieldsannotatedwith@AmountFormatannotation:
Examplelisting13-22–AmountFormatAnnotationFormatterFactoryclass
Project–ch13-converter-formatter-bankapp
Sourcelocation–src/main/java/sample/spring/chapter13/formatter
packagesample.spring.chapter13.formatter;
importorg.springframework.format.AnnotationFormatterFactory;
importorg.springframework.format.Parser;
importorg.springframework.format.Printer;
publicclassAmountFormatAnnotationFormatterFactoryimplements
AnnotationFormatterFactory<AmountFormat>{
publicSet<Class<?>>getFieldTypes(){
Set<Class<?>>fieldTypes=newHashSet<Class<?>>(1,1);
fieldTypes.add(Long.class);
returnfieldTypes;
}
publicParser<?>getParser(AmountFormatannotation,Class<?>fieldType){
returnnewAmountFormatter();
}
publicPrinter<?>getPrinter(AmountFormatannotation,Class<?>fieldType){
returnnewAmountFormatter();
}
}
In the above example listing, AmountFormatAnnotationFormatterFactory implements
AnnotationFormatterFactory<AmountFormat> interface, which means that the
AmountFormatAnnotationFormatterFactorycreatesformattersforfieldsannotatedwith@AmountFormat
annotation.
ThegetFieldTypesmethodreturnsthefieldtypesthatmaybeannotatedwith@AmountFormatannotation.
ThegetFieldTypesmethodintheaboveexamplelistingreturnsasingletype,Longtype,whichmeansthat
onlyaLongtypefieldthatisannotatedwith@AmountFormatannotationisconsideredforformattingby
the formatters created by the AmountFormatAnnotationFormatterFactory. The getParser and getPrinter
methodsreturnformattersforfieldsthatareannotatedwith@AmountFormatannotation.Youshouldnote
thattheFormatterinterfaceisasub-interfaceofParserandPrinterinterfaces.
ConfiguringAnnotationFormatterFactoryimplementation
AsincaseofFormattersconfiguration,anAnnotationFormatterFactoryimplementationisregisteredwith
FormattingConversionServiceviaformatterspropertyofFormattingConversionServiceFactoryBean:
Examplelisting13-23–AmountFormatAnnotationFormatterFactoryconfiguration
Project–ch13-converter-formatter-bankapp
Sourcelocation–src/main/webapp/WEB-INF/spring
<beans.....>
.....
<mvc:annotation-drivenconversion-service="myConversionService"/>
.....
<beanid="myConversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<propertyname="formatters">
<set>
<bean
class="sample.spring.chapter13.formatter.AmountFormatAnnotationFormatterFactory"/>
</set>
</property>
</bean>
</beans>
Now that we have seen how to use AnnotationFormatterFactory to enable formatting of fields that are
annotated with a specific annotation, let’s look at how it is used in ch13-converter-formatter-bankapp
project.
The following figure shows the web page of ch13-converter-formatter-bankapp project that shows the
listsoffixeddeposits:
Figure13-4 - The ‘Deposit amount’ column shows USD or EURO depending upon the language code
obtainedfromtheuser’scurrentlocale
TheabovefigureshowsthatUSDisappendedtothefixeddepositamountifthelanguagechosenbythe
userisEnglish.IfyouswitchthelanguagetoGerman,theUSDwillbereplacedbyEURO.Inexample
listing13-19,wesawthattheAmountFormattercontainedthelogicto showUSD orEUROdepending
uponthelanguagecodeobtainedfromtheuser’scurrentlocale.
ToensurethattheformattersconfiguredwiththeFormattingConversionServiceareinvokedduringpage
renderingandformsubmission,Spring’staglibrarytags(like,<eval>and<input>)havebeenusedinthe
JSPpagesofch13-converter-formatter-bankappproject.
Let’snowlookathowSpringWebMVCsimplifiesuploadingfiles.
13-6FileuploadsupportinSpringWebMVC
You can handle multipart requests in your Spring Web MVC applications by configuring a
MultipartResolver. Spring provides the following out-of-the-box implementations of MultipartResolver
interfacethatyoucanuseinyourwebapplications:
§CommonsMultipartResolver–basedonApacheCommonsFileUploadlibrary
§StandardServletMultipartResolver–basedonServlet3.0PartAPI
Whenamultipartrequestisreceived,DispatcherServletusestheconfiguredMultipartResolvertowrap
theHttpServletRequest intoa MultipartHttpServletRequest instance. In Spring Web MVC, an uploaded
file is represented by the MultipartFile object. The controller responsible for handling file uploads
accesses the uploaded file using methods defined by the MultipartHttpServletRequest or by directly
accessingtheMultipartFileobject.
Let’sfirstlookatasamplewebapplicationthatusesCommonsMultipartResolverforuploadingfiles.
IMPORTchapter 13/ch13-commons-file-upload (This project shows how to use
CommonsMultipartResolver to upload files. As CommonsMultipartResolver uses Apache Commons
FileUploadlibrary,theprojectisdependentoncommons-fileuploadJARfile.)
UploadingfilesusingCommonsMultipartResolver
Thefollowingexamplelistingshowsthefileuploadformthatisdisplayedbych13-commons-file-upload
project:
Examplelisting13-24–uploadForm.jsp–showstheuploadform
Project–ch13-commons-file-upload
Sourcelocation–src/main/webapp/WEB-INF/jsp
.....
<formmethod="post"action="/ch13-commons-file-upload/uploadFile"
enctype="multipart/form-data">
<tablestyle="padding-left:200px;">
<tr>
<tdcolspan="2"><c:outvalue="${uploadMessage}"/></td>
</tr>
<tr>
<td><b>Selectthefiletobeuploaded: </b></td>
<td><inputtype="file"name="myFileField"/></td>
</tr>
<tr>
<tdcolspan="2"align="center"><inputtype="button"
value="Uploadfile"onclick="document.forms[0].submit();"/></td>
</tr>
</table>
</form>
.....
The above example listing shows that the enctype attribute of <form> element is set to multipart/form-
data, which means that the form submission results in sending multipart request to the server. The
uploadMessage request attribute shows the success or failure message after the user selects a file and
clicksthe‘Uploadfile’button.
The following example listing shows the configuration of CommonsMultipartResolver that resolves
multipartrequests:
Examplelisting13-25–fileupload-config.xml–CommonsMultipartResolverconfiguration
Project–ch13-commons-file-upload
Sourcelocation–src/main/webapp/WEB-INF/spring
<beanid="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<propertyname="maxUploadSize"value="100000"/>
<propertyname="resolveLazily"value="true"/>
</bean>
It is important to note that the MultipartResolver implementation must be configured with id as
multipartResolverin the webapplication context XML file.The maxUploadSize propertyspecifies the
maximum size(inbytes)of the file thatcan beuploaded. Ifyouattempttouploadafilewhose size is
greaterthan100KB,theCommonsMultipartResolvershownintheaboveexamplelistingwillthrowan
exception. If an exception is thrown by the CommonsMultipartResolver instance, the controller
responsible for handling the file upload doesn’t get the opportunity to handle the exception. For this
reason,theresolveLazilypropertyissettotrue.IftheresolveLazilypropertyissettotrue,themultipart
requestisresolvedonlywhentheuploadedfileisaccessedbythecontroller.Thisgivestheopportunity
tothecontrollertohandleexceptionsthatoccurduringmultipartrequestresolution.
ThefollowingexamplelistingshowstheFileUploadControllerthathandlesfileuploads:
Examplelisting13-26–FileUploadController
Project–ch13-commons-file-upload
Sourcelocation–src/main/java/sample/spring/chapter13/web
packagesample.spring.chapter13.web;
importorg.springframework.web.multipart.MultipartFile;
.....
publicclassFileUploadController{
.....
@RequestMapping(value="/uploadFile",method=RequestMethod.POST)
publicModelAndViewhandleFileUpload(
@RequestParam("myFileField")MultipartFilefile)throwsIOException{
ModelMapmodelData=newModelMap();
if(!file.isEmpty()){
//--savetheuploadedfileonthefilesystem
StringsuccessMessage="Filesuccessfullyuploaded";
modelData.put("uploadMessage",successMessage);
returnnewModelAndView("uploadForm",modelData);
}
.....
}
@ExceptionHandler(value=Exception.class)
publicModelAndViewhandleException(){
.....
}
}
FileUploadController’s handleFileUpload method accepts an argument of type MultipartFile which
identifies the uploaded file. Notice that the @RequestParam annotation specifies name of the <input
type=”file”.....>fieldintheuploadForm.jsppage(referexamplelisting13-24).Ifthefileissuccessfully
uploaded, the handleFileUpload method sets a success message which is shown to the user.
@ExceptionHandler method shows an error message in case an exception occurs during file upload
process.Forinstance,ifthefilesizeisgreaterthan100KB,anerrormessageisshowntotheuser.
Now that we have seen how to use CommonsMultipartResolver to upload files, let’s look at how to
uploadfilesusingStandardServletMultipartResolver.
IMPORTchapter 13/ch13-servlet3-file-upload (This project shows how to use
StandardServletMultipartResolvertouploadfiles.)
UploadingfilesusingStandardServletMultipartResolver
Thesupportforhandlingmultipartrequestisprovidedout-of-the-boxinServlet3.Ifyouwanttousethe
multipart support provided by Servlet 3, enable multipart request handling by specifying <multipart-
config>elementintheDispatcherServletconfiguration,andconfigureStandardServletMultipartResolver
in the web application context XML file. Unlike, CommonsMultipartResolver,
StandardMultipartResolverdoesn’tdefineanyproperties.
ThefollowingexamplelistingshowstheDispatcherServletconfigurationinweb.xmlfile:
Examplelisting13-27–web.xml
Project–ch13-servlet3-file-upload
Sourcelocation–src/main/webapp
<servlet>
<servlet-name>fileupload</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
.....
<multipart-config>
<max-file-size>10000</max-file-size>
</multipart-config>
</servlet>
Asthe<multipart-config>elementisspecified,thefileuploadservletcanhandlemultipartrequests.The
<max-file-size>elementspecifiesthemaximumfilesizethatcanbeuploaded.Noticethatthemaximum
filesizeisnowspecifiedaspartof<multipart-config>element.
13-7Summary
Inthischapter,welookedatsomeoftheimportantfeaturesofSpringWebMVCframeworkthatsimplify
developingwebapplications.Inthenextchapter,we’lllookathowtosecureSpringapplicationsusing
SpringSecurityframework.
Chapter14–SecuringapplicationsusingSpringSecurity
14-1Introduction
Securityisanimportantaspectofanyapplication.SpringSecurityisbuiltontopofSpringFramework,
andprovidesacomprehensiveframeworkforsecuringSpring-basedapplications.Inthischapter,we’ll
lookathowtouseSpringSecurityframeworkto:
§authenticateusers
§implementwebrequestsecurity,
§implementmethod-levelsecurity
§securedomainobjectsusingACL(AccessControlList)basedsecurity
Let’sbeginbylookingattheMyBankwebapplication’ssecurityrequirementsthatwe’ll address using
SpringSecurity.
14-2SecurityrequirementsoftheMyBankwebapplication
TheusersoftheMyBankwebapplicationarecustomersandadministratorsthatmanagefixeddeposits
inthesystem.Acustomercanopenandeditfixeddepositsbutcan’tclosethem.Anadministratorcan’t
createoreditfixeddepositsbutcanclosefixeddepositsofcustomers.
As only authenticated users can access the MyBank web application, a login form is displayed to
unauthenticatedusers:
Figure14-1-Loginformthatisdisplayedtounauthenticatedusers
Theabovefigureshowstheloginformthatisdisplayedtounauthenticatedusers.Iftheuserselectsthe
‘Remember me on this computer’ checkbox, the MyBank web application remembers the credentials
enteredbytheuserandusesitforautomaticauthenticationoftheuserinfuturevisits.
When a customer logs in, details ofthe fixed deposits associated with the customer are displayed, as
shownhere:
Figure14-2-Fixeddepositsofthecustomeraredisplayedafterauthentication
TheabovefigureshowsaLogouthyperlinkthatthecustomercanclicktologoutfromtheMyBankweb
application.AcustomercaneditdetailsofafixeddepositbyclickingtheEdithyperlinkcorrespondingto
thatfixeddeposit.AcustomercanviewtheformforopeninganewfixeddepositbyclickingtheCreate
new Fixed Deposit button. Notice that the username of the authenticated user is displayed below the
Logouthyperlink.
Whenanadministratorlogsin,detailsofallthefixeddepositsinthesystemaredisplayedbytheMyBank
webapplication,asshownhere:
Figure14-3-Fixeddepositsofallthecustomeraredisplayedtoanadministrator
Intheabovefigure,anadministratorcanchoosetocloseafixeddepositbyclickingtheClosehyperlink
corresponding to that fixed deposit. As in case of customers, the Create new Fixed Deposit button is
visibletoanadministratoralso,butanattempttosavedetailsofthenewfixeddepositwillresultina
securityexceptionthrownbytheapplication.
Let’s now look at how to address the security requirements of MyBank web application using Spring
Security.
IMPORTchapter 14/ch14-bankapp-simple-security (This project represents the MyBank web
applicationthatusesSpringSecurityframeworkforaddressingsecurityrequirementsdescribedinsection
14-2.)
14-3SecuringMyBankwebapplicationusingSpringSecurity
Spring Security framework consists of multiple modules that address various security aspects of
applications.ThefollowingtabledescribessomeoftheimportantmodulesofSpringSecurity:
Module Description
spring-security-core DefinesthecoreclassesandinterfacesofSpringSecurityframework.Thismoduleis
requiredbyanyapplicationthatusesSpringSecurity.
spring-security-web Providessupportforsecuringwebapplications
spring-security-config
Like Spring’s tx and mvc schemas, Spring Security defines a security schema that
simplifiesconfiguring Spring Security features. The sp ring-security-config module is
responsibleforparsingtheelementsofthesecuritynamespace.
spring-security-taglibs Definestagsthatyoucanusetoaccesssecurityinformationandtosecurethecontent
displayedbyJSPpages
spring-security-acl Enables useof ACLs (Access ControlList) to secureinstances ofdomain objects in
applications
In this section, we’ll look at usage of spring-security-core, spring-security-web, spring-security-config
andspring-security-taglibsmodules tosecuretheMyBank webapplication. Laterinthischapter, we’ll
lookathowtousespring-security-aclmoduletosecuredomainobjectinstances.
Let’sbeginbylookingathowwebrequestsecurityisconfigured.
Webrequestsecurityconfiguration
Youcanaddwebrequestsecuritytoanapplicationby:
§configuringSpring’sDelegatingFilterProxyfilterintheweb.xmlfile,and
§enablingwebrequestsecurityprovidedbytheSpringSecurityframework
Let’sfirstlookathowtoconfigureDelegatingFilterProxyfilter.
DelegatingFilterProxyfilterconfiguration
Spring Framework’s web module (represented by spring-web-4.0.0.RELEASE.jar file) defines the
DelegatingFilterProxyclassthatimplementsServletAPI’sFilterinterface.Thefollowingexamplelisting
showstheconfigurationofDelegatingFilterProxyfilterintheweb.xmlfile:
Examplelisting14-1–web.xml-DelegatingFilterProxyfilterconfiguration
Project–ch14-bankapp-simple-security
Sourcelocation-src/main/webapp/WEB-INF
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The<filter-mapping>element specifies that the DelegatingFilterProxy filter is mapped to all incoming
webrequests.Thefilternamespecifiedbythe<filter-name>elementcarriesaspecialsignificanceinthe
context of DelegatingFilterProxy filter. DelegatingFilterProxy filter delegates request processing to the
Springbeanwhosenamematchesthevalueof<filter-name>element.Intheaboveexamplelisting,web
requests received by the DelegatingFilterProxy filter are delegated to the Spring bean named
springSecurityFilterChain in the root application context. We’ll soon see that the
springSecurityFilterChainbeaniscreatedbytheSpringSecurityframework.
Now,thatwehaveconfiguredtheDelegatingFilterProxyfilter,let’slookathowtoconfigurewebrequest
security.
Configuringwebrequestsecurity
The following example listing shows the application context file that uses <http> element of security
schematoconfigurewebrequestsecurity:
Examplelisting14-2–applicationContext-security.xml–websecurityconfiguration
Project–ch14-bankapp-simple-security
Sourcelocation-src/main/resources/META-INF/spring
<beans:beansxmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation=".....
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<httpuse-expressions="true">
<intercept-urlpattern="/**"access="hasAnyRole('ROLE_CUSTOMER','ROLE_ADMIN')"/>
<form-login/>
<logout/>
<remember-me/>
<headers>
<cache-control/>
<xss-protection/>
</headers>
</http>
.....
</beans:beans>
Theaboveexamplelistingshowsthatthespring-security-3.2.xsdschemaisreferencedbytheapplication
context XML file. The spring-security-3.2.xsd schema is contained in the
org.springframework.security.configpackageofspring-security-config-3.2.0.RELEASE.jarfile.
The<http>elementcontainsthewebrequest securityconfigurationfor theapplication.SpringSecurity
framework parses the <http> element and registers a bean named springSecurityFilterChain with the
Spring container. The springSecurityFilterChain bean is responsible for handling web request security.
TheDelegatingFilterProxy filter that we configured earlier (refer example listing 14-1) delegates web
requesthandlingtothespringSecurityFilterChainbean.ThespringSecurityFilterChainbeanrepresentsan
instanceofFilterChainProxybean(referSpringSecuritydocsformoreinformation)thatcontainsachain
ofServletfiltersthatareaddedtothechainbythesub-elementsof<http>element.
The <intercept-url> element’s access attribute specifies a Spring EL expression that evaluates to a
boolean value. If the Spring EL expression returns true, the URLs matched by the pattern attribute are
accessibletotheuser.IftheSpringELexpressionreturnsfalse,accessisdeniedtotheURLsmatchedby
thepatternattribute.SpringSecurityframeworkprovidesacoupleofbuilt-inexpressions,likehasRole,
hasAnyRole,isAnonymous,andsoon.
Inexamplelisting14-2,thehasAnyRole('ROLE_CUSTOMER','ROLE_ADMIN')expressionreturnstrue
if the authenticated user has ROLE_CUSTOMERor ROLE_ADMIN role. In MyBank web application,
theROLE_CUSTOMER role is assigned to a customer and the ROLE_ADMIN role is assigned to an
administrator. As the pattern /* matches all URLs, the <intercept-url> element in example listing 14-2
specifiesthatonlyauserwithroleROLE_CUSTOMERorROLE_ADMINcanaccesstheMyBankweb
application.YoushouldnotethattheuseofSpringELexpressionintheaccessattributeisallowedonlyif
yousetthevalueofuse-expressionsattributeof<http>elementtotrue.
The<form-login>elementconfiguresaloginpagethatisusedtoauthenticateusers.Youcanusevarious
attributesof<form-login>element,likelogin-page,default-target-url,andsoon,tocustomizethelogin
page.Thelogin-pageattributespecifiestheURLthatisusedtorendertheloginpage.Ifthelogin-page
attributeisnotspecified,aloginpageisautomaticallyrenderedatthe/spring_security_loginURL.
The<logout>elementconfiguresthelogoutprocessingfeatureofSpringSecurityframework.Youcanuse
variousattributesof<logout>element,likelogout-url,delete-cookies,invalidate-session,andsoon,to
configurethelogoutfunctionality.Forinstance,youcanusethedelete-cookiesattributetospecifycomma-
separatednamesofcookiesthatshouldbedeletedwhentheuserlogsoutoftheapplication.Thelogout-
urlattributeallowsyoutoconfiguretheURLthatperformsthelogoutprocessing.Ifyoudon’tspecifythe
logout-urlattribute,thelogout-urlattributevalueissetto/j_spring_security_logoutbydefault.
The<remember-me>elementconfiguresthe‘remember-me’authenticationinwhichthewebapplication
remembers the identity of the authenticated user between sessions. When a user is successfully
authenticated,SpringSecurityframeworkgeneratesauniquetokenthatcaneitherbestoredinapersistent
store or sent to the user in a cookie. In example listing 14-2, <remember-me> element configures a
cookie-basedremember-meauthenticationservice.Whentheuserrevisitsthewebapplication,thetoken
isretrievedfromthecookieandisautomaticallyauthenticated.
The<headers>elementspecifiesthesecurityheadersthatareaddedtotheHTTPresponsebytheSpring
Security framework. For instance, in example listing 14-2, the <cache-control> element adds Cache-
Control,PragmaandExpiresresponseheaders,andthe<xss-protection>elementaddsX-XSS-Protection
header.
WhenanunauthenticateduseraccessestheMyBankwebapplication,SpringSecuritydisplaysthelogin
page (refer figure 14-1) configured by the <form-login> element to the user. Let’s now look at how
authenticationisperformedwhentheuserentershiscredentialsandclickstheLoginbutton.
Authenticationconfiguration
Whenauserentershiscredentialsandsubmitstheloginpage,SpringSecurity’sAuthenticationManageris
responsibleforprocessingtheauthenticationrequest.AnAuthenticationManagerisconfiguredwithone
ormoreAuthenticationProvidersagainstwhichtheAuthenticationManagerattemptstoauthenticateusers.
For instance, if you want to authenticate users against an LDAP server, you can configure an
LdapAuthenticationProvider (an implementation of AuthenticationProvider) that authenticates users
againstanLDAPserver.
The security schema simplifies configuration of AuthenticationManager and AuthenticationProvider
objects,asshowninthefollowingexamplelisting:
Examplelisting14-3–applicationContext-security.xml
Project–ch14-bankapp-simple-security
Sourcelocation-src/main/resources/META-INF/spring
<authentication-manager>
<authentication-provider>
<user-service>
<username="admin"password="admin"authorities="ROLE_ADMIN"/>
<username="cust1"password="cust1"authorities="ROLE_CUSTOMER"/>
<username="cust2"password="cust2"authorities="ROLE_CUSTOMER"/>
</user-service>
</authentication-provider>
</authentication-manager>
The <authentication-manager> element configures an AuthenticationManager instance. The
<authentication-provider> element configures an AuthenticationProvider instance. By default, the
<authentication-provider> element configures a DaoAuthenticationProvider (an implementation of
AuthenticationProvider)thatusesSpring’sUserDetailsServiceasaDAOtoloaduserdetails.
DaoAuthenticationProvider uses the configured UserDetailsService to load user details from the user
repository based on the supplied username. DaoAuthenticationProvider performs authentication by
comparing the login credentials supplied by the user with the user details loaded by the configured
UserDetailsService.YoushouldnotethataUserDetailsServicemayloaduserdetailsfromadatasource,
aflatfileoranyotheruserrepository.
The <user-service> sub-element of <authentication-provider> configures an in-memory
UserDetailsServicethatloadsusersdefinedbythe<user>elements.Inexamplelisting14-3,the<user-
service> element defines that the application has three users: admin (ROLE_ADMIN role), cust1
(ROLE_CUSTOMER role) and cust2 (ROLE_CUSTOMER role). The name attribute specifies the
username assigned to the user,the password attribute specifies the password assigned to the user, and
authoritiesattributespecifiestherole(s)assignedtotheuser.
Now, if you deploy the ch14-bankapp-simple-security project and access it by going to the
http://localhost:8080/ch14-bankapp-simple-security URL, the login page (refer figure 14-1) of the web
application is displayed. If you authenticate by entering username as cust1 and password as cust1, the
webapplicationwilldisplayfixeddepositsassociatedwithcust1(referfigure14-2)user.Similarly,if
youloginwithusernameascust2andpasswordascust2,thewebapplicationwilldisplayfixeddeposits
associated with cust2 user. If you login with username as admin and password as admin, the web
applicationwilldisplayfixeddepositsofbothcust1andcust2users.
Let’snowlookathowtouseSpringSecurity’sJSPtaglibrarytoaccesssecurityinformationandtoapply
securityconstraintsonthecontentdisplayedbyJSPpages.
SecuringJSPcontentusingSpringSecurity’sJSPtablibrary
OneoftherequirementsofMyBankwebapplicationisthattheoptiontoeditafixeddeposit(referfigure
14-2)isavailableonlytouserswithroleROLE_CUSTOMER.And,theoptiontocloseafixeddeposit
(refer figure 14-3) isavailable only touser withrole ROLE_ADMIN.As we need tosecure Edit and
Close hyperlinks based on the authenticated user’s role, the MyBank web application uses Spring
Security’sJSPtaglibrarytosecureJSPcontent.
ThefollowingexamplelistingshowsusageofSpringSecurity’sJSPtaglibrarytoaccessauthenticated
user’susername,andtosecureJSPcontentbasedontheroleoftheloggedinuser:
Examplelisting14-4–fixedDepositList.jsp
Project–ch14-bankapp-simple-security
Sourcelocation-src/main/webapp/WEB-INF/jsp
<%@tagliburi="http://www.springframework.org/security/tags"prefix="security"%>
.....
<body>
.....
<tdstyle="font-family:'arial';font-size:12px;font-weight:bold"align="right">
<ahref="${pageContext.request.contextPath}/j_spring_security_logout">Logout</a>
<p>
Username:<security:authenticationproperty="principal.username"/>
</p>
</td>
.....
<tdclass="td">
<security:authorizeaccess="hasRole('ROLE_CUSTOMER')">
<ahref="${pageContext.request.contextPath}/fixedDeposit?.....">Edit</a>
</security:authorize>
<security:authorizeaccess="hasRole('ROLE_ADMIN')">
<ahref="${pageContext.request.contextPath}/fixedDeposit.....">Close</a>
</security:authorize>
</td>
</body>
</html>
The above example listing shows that the Logout hyperlink refers to
${pageContext.request.contextPath}/j_spring_security_logout URL. As mentioned earlier, if you don’t
specify the logout-url attribute of <logout> element, the logout-url value is set to
/j_spring_security_logout. So, when a user clicks the Logout hyperlink, the user is logged out of the
MyBankwebapplication.
TheaboveexamplelistingalsoshowsthattheJSPpageincludesSpringSecurity’sJSPtaglibraryusing
thetaglibdirective.SpringSecurity’sAuthenticationobjectcontainsinformationabouttheauthenticated
user. Forinstance, itcontains informationaboutauthenticated user’s role(s) and username thattheuser
usedforauthentication.The<authentication>elementprintsthespecifiedpropertyoftheAuthentication
object. In the above example, the principal.username property refers to the username property of the
authenticateduser.
The<authorize>elementsecurestheenclosedJSPcontentbasedontheresultofevaluationofthesecurity
expression specified by the access attribute. If the security expression evaluates to true, the enclosed
content is rendered, otherwise the enclosed content is not rendered. In the above example listing, the
hasRole(‘ROLE_CUSTOMER’)expressionreturnstrueiftheauthenticateduserhasROLE_CUSTOMER
role, and the hasRole(‘ROLE_ADMIN’) expression returns true if the authenticated user has
ROLE_ADMIN role. In the above example listing, the hasRole expression has been used such that the
EditoptionisdisplayedonlytoauserwithROLE_CUSTOMERroleandtheCloseoptionisdisplayed
onlytoauserwithROLE_ADMINrole.
Let’snowlookathowtoincorporatemethod-levelsecurityusingSpringSecurity.
Securingmethods
One of the requirements of MyBank application is that a user with ROLE_ADMIN role can view the
‘Create new Fixed Deposit’ button (refer figure 14-3) but an attempt to save details of the new fixed
deposit will result in a security exception. This is an example in which we want to secure the
FixedDepositService’ssaveFixedDepositmethodsuchthatonlyauserwithROLE_CUSTOMERrolecan
invokeit.
WealsowanttosecureothermethodsoftheFixedDepositServicesothatitisnotinvokedbyunauthorized
users.Forinstance,cust1userloggedinwithROLE_CUSTOMERcaninvoketheFixedDepositService’s
closeFixedDeposit method to close an existing fixed deposit by entering the following URL in the
browser:
http://localhost:8080/ch14-bankapp-simple-security/fixedDeposit?fdAction=close&fixedDepositId=
<fixed-fixed-id>
The<fixed-deposit-id>intheaboveURListhefixeddepositidthatyouwanttoremove,ashighlightedin
thefollowingfigure:
Figure14-4–FixeddepositIDofafixeddepositisdisplayedintheIDcolumn
Toaddmethod-levelsecuritytoyourapplication,youneedtodothefollowing:
§configuremethod-levelsecurityforyourapplicationbyusing<global-method-security>elementof
securityschema
§add@Securedannotationstothemethodsthatyouwanttosecureagainstunauthorizedaccess
Let’sfirstlookatthe<global-method-security>element.
Configuringmethod-levelsecurityusing<global-method-security>element
Thefollowingexamplelistingshowsusageof<global-method-security>element:
Examplelisting14-5–applicationContext-security.xml
Project–ch14-bankapp-simple-security
Sourcelocation-src/main/resources/META-INF/spring
<beans:beansxmlns="http://www.springframework.org/schema/security"
.....>
<global-method-securitysecured-annotations="enabled"/>
</beans:beans>
The<global-method-security> element configures method-level security. The <global-method-security>
elementisapplicableonlytotheapplicationcontextinwhichitisdefined.Forinstance,ifthe<global-
method-security>elementisdefinedintherootwebapplicationcontextXMLfile,thenitisapplicable
only to the beans registered with the root WebApplicationContext instance. In ch14-bankapp-simple-
security project, the applicationContext-security.xml (shown in the above example listing) and the
applicationContext.xml(thatdefinesservicesandDAOs)filesconstitutetherootwebapplicationcontext
XMLfiles(referweb.xmlfileofch14-bankapp-simple-securityproject);therefore,the<global-method-
security>elementappliesonlytothebeansdefinedintheseapplicationcontextXMLfiles.
The <global-method-security> element’s secured-annotations attribute specifies whether the use of
Spring’s@Secured annotation should be enabled or disabled for the beans registered with the Spring
container.Asthevalueissettoenabled,youcanuseSpring’s@Securedannotationtospecifythebean
methodsthataresecured.
NOTEIfyouwanttosecurecontrollermethods,thendefinethe<global-method-security>elementinthe
webapplicationcontextXMLfileinsteadoftherootwebapplicationcontextXMLfile.
Let’snowlookathowtosecuremethodsusingSpring’s@Securedannotation.
Specifyingsecurityconstraintsonbeanmethodsusing@Securedannotation
The following example listing shows usage of Spring’s @Secured annotation to define security
constraintsonmethods:
Examplelisting14-6–FixedDepositServiceinterface
Project–ch14-bankapp-simple-security
Sourcelocation-src/main/java/sample/spring/chapter14/service
packagesample.spring.chapter14.service;
importorg.springframework.security.access.annotation.Secured;
.....
publicinterfaceFixedDepositService{
.....
@Secured("ROLE_CUSTOMER")
voidsaveFixedDeposit(FixedDepositDetailsfixedDepositDetails);
.....
@Secured("ROLE_ADMIN")
voidcloseFixedDeposit(intfixedDepositId);
@Secured("ROLE_CUSTOMER")
voideditFixedDeposit(FixedDepositDetailsfixedDepositDetails);
}
TheaboveexamplelistingshowstheFixedDepositServiceinterfacethatdefinesmethodsthatoperateon
fixed deposits. @Secured("ROLE_CUSTOMER") annotation on the saveFixedDeposit and
editFixedDeposit methods specifies that these methods can only be invoked by a user whose role is
ROLE_CUSTOMER. @Secured("ROLE_ADMIN") annotation on the closeFixedDeposit method
specifiesthatthemethodcanonlybeinvokedbyauserwhoseroleisROLE_ADMIN.
NOTEBydefault,method-levelsecurityisbasedonSpringAOP.IfyouwanttouseAspectJinsteadof
Spring AOP, set mode attribute of <global-method-security> element to aspectj. Also, add spring-
security-aspects module to your project, and specify @Secured annotations on the class instead of the
interface.
Insteadofusing@Securedannotation,youcanuseSpring’s@PreAuthorizeannotationtoapplysecurity
constraints on methods. Unlike @Secured annotation, @PreAuthorize annotation accepts security
expressions,likehasRole,hasAnyRole,andsoon.Toenableuseof@PreAuthorizeannotation,setpre-
post-annotationsattributeof<global-method-security>elementtoenabled.Thefollowingexamplelisting
showsusageof@PreAuthorizeannotation:
Examplelisting14-6–@PreAuthorizeannotation
importorg.springframework.security.access.prepost.PreAuthorize;
.....
publicinterfaceSomeService{
.....
@PreAuthorize("hasRole('ROLE_XYZ')")
voiddoSomething(.....);
.....
}
In the above example listing, @PreAuthorize annotation specifies that the doSomething method is
accessibleonlytouserswithroleROLE_XYZ.
SpringSecurityalsosupportssecurityannotations,like@RolesAllowed,@DenyAll,@PermitAll,andso
on, defined by JSR-250 – Common Annotations. To enable use of JSR-250 security annotations, set
jsr250-annotations attribute of <global-method-security> to enabled. The following example listing
showsusageof@RolesAllowedannotation:
Examplelisting14-7–@RolesAllowedannotation
importjavax.annotation.security.RolesAllowed;
.....
publicinterfaceSomeService{
.....
@RolesAllowed("ROLE_XYZ")
voiddoSomething(.....);
.....
}
In the above example listing, @RolesAllowed annotation specifies that the doSomething method is
accessibleonlytouserswithroleROLE_XYZ.
NOTEWesawearlierinthisbookthatJSR250annotations,like@PreDestroy,@PostConstruct,andso
on,arepartofJavaSE6orlater.AssecurityrelatedannotationsofJSR250arenotpartofJavaSE,you
need to add jsr250-api JAR file to your project to use @RolesAllowed, @PermitAll, and so on,
annotations.
Inthissection,welookedathowtouseSpringSecuritytoauthenticateusers,securewebrequestsand
implementmethod-levelsecurity.Let’snowlookatSpringSecurity’sACLmoduleforsecuringdomain
objectinstances.
IMPORTchapter14/ch14-bankapp-db-security(ThisprojectrepresentstheMyBankwebapplication
thatusesSpringSecurity’sACLmoduleforsecuringFixedDepositDetailsinstances.)
14-4 MyBank web application - securing FixedDepositDetailsinstances
usingSpringSecurity’sACLmodule
Thech14-bankapp-db-securityprojectrepresentsavariantofMyBankwebapplicationthatusesSpring
Security’sACLmoduletosecureFixedDepositDetailsinstances.
Let’slookathowtodeployandusech14-bankapp-db-securityproject.
Deployingandusingch14-bankapp-db-securityproject
The ch14-bankapp-db-security project uses MySQL database to store application users, fixed deposit
detailsandACLinformation.Beforedeployingthech14-bankapp-db-securityproject,createadatabase
named securitydb in MySQL and execute the bankapp.sql script located in scripts folder of ch14-
bankapp-db-securityproject.
The execution of bankapp.sql script creates the following tables: ACL_CLASS, ACL_ENTRY,
ACL_OBJECT_IDENTITY, ACL_SID, FIXED_DEPOSIT_DETAILS, AUTHORITIES, and USERS.
TableswhosenamesbeginwithACL_storeACLrelatedinformation(moreonthesetableslaterinthis
chapter).FIXED_DEPOSIT_DETAILStablecontainsfixeddepositdetails.USERSandAUTHORITIES
tablescontainuserandroleinformation,respectively.Thebankapp.sqlscriptalsoinsertssetupdatainto
USERS,AUTHORITIES,ACL_CLASSandACL_SIDtables.
Now, that you have setup the database for ch14-bankapp-db-security project, deploy the project on
embeddedTomcat7serverbyexecutingthetomcat7:rungoalfromtheproject’sdirectory(referappendix
AformoreinformationonhowtodeploywebprojectsonembeddedTomcat7server).Oncetheproject
issuccessfullydeployed,gotohttp://localhost:8080/ch14-bankapp-db-securityURL.Youshouldseethe
loginpage,asshownbelow:
Figure14-5–LoginpageofMyBankwebapplication
By default, the following three users are configured for the MyBank web application: cust1
(ROLE_CUSTOMERrole),cust2(ROLE_CUSTOMERrole), and admin(ROLE_ADMIN role). When
youloginwithusernamecust1andpasswordascust1,you’llseethefixeddepositsassociatedwithcust1
customer,asshowninthefollowingfigure:
Figure14-6–Listoffixeddepositsassociatedwithcustomercust1
Asnofixeddepositsarecurrentlyassociatedwithcust1,theabovefigureshowsanemptylistoffixed
deposits.Clickingthe‘CreatenewFixedDeposit’buttonopenstheformforcreatinganewfixeddeposit.
Ifyoucreateanewfixeddeposit,it’llappearinthelistoffixeddeposits,asshownhere:
Figure14-7–Acustomercaneditfixeddepositsormakethemaccessibletotheadminuser.
Intheabovefigure,the‘Edit’optionallowsthecustomertoeditfixeddepositdetails,andthe‘Provide
accesstoadmin’optionmakesthefixeddepositaccessibletotheadminuser.Theadminusercanonly
viewfixeddepositsthataremadeaccessiblebycustomers.Clickthe‘Provideaccesstoadmin’hyperlink
tomakethefixeddepositaccessibletotheadminuser.
Now,logoutfromtheMyBankwebapplication,andloginusingadminusernameandadminaspassword.
Theadminusercanviewallthefixeddepositsthatweremadeaccessiblebycustomers,asshownhere:
Figure14-8–Theadminusercancloseafixeddepositbyselectingthe‘Close’option
The above figure shows that the admin user can choose the ‘Close’ option to close the fixed deposit.
ClosingafixeddepositdeletesthefixeddepositfromtheFIXED_DEPOSIT_DETAILStable.
To summarize, you can login using cust1/cust1, cust2/cust2 and admin/admin credentials to see the
followingfeaturesoftheMyBankwebapplication:
§onlycust1(ROLE_CUSTOMERrole)andcust2(ROLE_CUSTOMERrole)userscancreatefixed
deposits
§ cust1 and cust2 can only edit fixed deposits that they own. For instance, cust1 can’t edit a fixed
depositcreatedbycust2.
§ cust1 andcust2 can onlymakethefixeddepositsthatthey ownaccessibletotheadmin user. For
instance,cust1can’tmakeafixeddepositcreatedbycust2accessibletotheadminuser.
§adminuser(ROLE_ADMINrole)canonlyviewfixeddepositsthataremadeaccessiblebycust1
andcust2users
§onlytheadminusercanclosefixeddeposits
Before delving into the implementation details of MyBank web application, let’s look at the standard
databasetablesrequiredbySpringSecuritytostoreACLanduserinformation.
DatabasetablestostoreACLanduserinformation
SpringSecurity’sACLmoduleprovidesdomainobjectinstancesecurity.MyBankwebapplicationuses
Spring Security’s ACL module to secure instances of FixedDepositDetails. Spring Security tables
(ACL_CLASS,ACL_ENTRY,ACL_OBJECT_IDENTITYandACL_SID)containpermissionsthatapply
tofixeddepositsstoredintheFIXED_DEPOSIT_DETAILStable.WhenaFixedDepositDetailsinstance
is accessed, Spring Security’s ACL module verifies that the authenticated user has the necessary
permissionstooperateontheFixedDepositDetailsinstance.
Let’slookateachoftheSpringSecuritytablesthatareusedtostoreACLinformation.
ACL_CLASStable
ACL_CLASS table contains the fully-qualified name of domain classes whose instances we want to
secureinourapplication.IncaseofMyBankwebapplication,theACL_CLASStablecontainsthefully-
qualifiednameoftheFixedDepositDetailsclass,asshownhere:
Figure14-9ACL_CLASStable
Tablecolumndescription
id–containstheprimarykey
class–fully-qualifiednameofthedomainclasswhoseinstanceswewanttosecure
ACL_SIDtable
ACL_SIDtable(SIDmeans‘securityidentity’)containstheprincipals(thatis,usernames)orauthorities
(thatis,roles)inthesystem.IncaseofMyBankwebapplication,ACL_SIDtablecontainsadmin,cust1
andcust2usernames,asshownhere:
Tablecolumndescription
id–containstheprimarykey
principal–specifieswhetherthesidcolumnstoresroleorusername.Thevaluetruespecifiesthatthesid
columnstoresusername.Thevaluefalsespecifiesthatthesidcolumnstoresrole.
sid–containsusernameorrole
ACL_OBJECT_IDENTITYtable
ACL_OBJECT_IDENTITYtablecontainsidentitiesofdomainobjectsthatwewanttosecure.Incaseof
MyBank web application, the ACL_OBJECT_IDENTITY table contains identities of fixed deposits
storedinFIXED_DEPOSIT_DETAILStable,asshownhere:
Figure14-11ACL_OBJECT_IDENTITYtable
In the above figure, the object_id_identity column contains identities of fixed deposits stored in the
FIXED_DEPOSIT_DETAILStable.
Tablecolumndescription
id–containstheprimarykey
object_id_class–referstothedomainclassdefinedintheACL_CLASStable
object_id_identity–referstothedomainobjectinstanceintheFIXED_DEPOSIT_DETAILStable
parent_object – if a parent object exists for the domain object referenced by the object_id_identity
column,thiscolumnreferstotheidentityoftheparentobject
owner_sid–referstotheuserorrolethatownsthedomainobjectinstance
entries_inheriting–flagthatindicateswhethertheobjectinheritsACLentriesfromanyparentACLentry
ornot
ACL_ENTRYtable
ACL_ENTRY table contains permissions (read, write, create, and so on) assigned to users on domain
objects. In case of MyBank web application, the ACL_ENTRY table contains permissions assigned to
usersonfixeddepositsstoredinFIXED_DEPOSIT_DETAILStable,asshownhere:
Figure14-12ACL_ENTRYtable
Intheabovefigure,theacl_object_identity,maskandsidcolumnsdeterminethepermissionsassignedto
auser(orrole)onadomainobjectinstance.YoushouldnotethatanentryintheACL_ENTRYtableis
commonlyreferredtoasACE(AccessControlEntry).
Tablecolumndescription
id–containstheprimarykey
acl_object_identity – refers to the id column of the ACL_OBJECT_IDENTITY table, which in turn
identifiesthedomainobjectinstance
ace_order–specifiestheorderingoftheaccesscontrolentries
sid–referstotheidcolumnofACL_SIDtable,whichinturnidentifiestheuser(orrole)
mask–specifiesthepermissions(read,write,create,andsoon)assignedtotheuser(orrole).1means
read,2meanswrite,8meansdeleteand16meansadministrationpermission.
granting – flag that indicates whether the entry in the mask column identifies as granting access or
denyingaccess.Forinstance,ifthevalueinthemaskcolumnis1andgrantingcolumnistrue,itmeans
thatthecorrespondingSIDhasreadaccess.But,ifthevalueinthemaskcolumnis1andgrantingcolumn
isfalse,itmeansthatthecorrespondingSIDdoesn’thavereadaccess.
audit_success–flagthatindicateswhethertoauditsuccessfulpermissionsornot.Laterinthischapter,
we’llseethatSpringSecurity’sConsoleAuditLoggercanbeusedtologsuccessfulpermissions.
audit_failure-flagthatindicateswhethertoauditfailedpermissionsornot.Laterinthischapter,we’ll
seethatSpringSecurity’sConsoleAuditLoggercanbeusedtologfailedpermissions.
Asexplainedsofar,thediagram14-13depictsrelationshipbetweenACLtables.Thearrowsinthefigure
representforeignkeyreferencesfromatable.Forinstance,theACL_OBJECT_IDENTITYtablecontains
foreignkeysthatrefertoACL_CLASS,ACL_SIDandFIXED_DEPOSIT_DETAILStables.
Figure14-13 ACL tables and their relationships. The arrows represent foreign key references from a
table.
Now,thatwehaveseentheACLtablesrequiredtostoreACLinformation,let’snowlookattheSpring
Securitytablesthatstoreusersandtheirrolesinformation.
USERStable
USERStablestorescredentialsofusers,asshownhere:
Figure14-14USERStable
Tablecolumndescription
username–usernameoftheuser
password–passwordoftheuser
enabled–flagthatindicateswhethertheuserisenabledordisabled
AUTHORITIEStable
AUTHORITIEStablecontainstheroleassignedtoeachuserdefinedintheUSERStable
Tablecolumndescription
username–usernameoftheuser
authority–roleassignedtotheuser
Figure14-15AUTHORITIEStable
Let’snowlookathowtheusersareauthenticatedinMyBankwebapplication.
Userauthentication
MyBank web application explicitly configures the UserDetailsService to load user details from the
USERSandAUTHORITIESdatabasetables,asshowninthefollowingexamplelisting:
Examplelisting14-8–applicationContext-security.xml
Project–ch14-bankapp-db-security
Sourcelocation-src/main/resources/META-INF/spring
<authentication-manager>
<authentication-provideruser-service-ref="userDetailsService"/>
</authentication-manager>
<beans:beanid="userDetailsService"
class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<beans:propertyname="dataSource"ref="dataSource"/>
</beans:bean>
Intheaboveexamplelisting,theuser-service-refattributeof<authentication-provider>elementrefersto
an implementation of UserDetailsService that is responsible for loading user (and their authorities)
details based on the supplied username. JdbcDaoImpl is an implementation of UserDetailsService that
loadsuser(andtheirauthorities)detailsfromthedatasource(specifiedbythedataSourceproperty)using
JDBCqueries.RefertotheapplicationContext.xmlfileofch14-bankapp-db-securityprojecttoviewthe
dataSourcebeandefinition.Bydefault,JdbcDaoImplloadsuserdetailsfromtheUSERS(referfigure14-
14)tableandauthoritiesinformationfromtheAUTHORITIES(referfigure14-15)table.Ifyoualready
havecustomdatabasetablesthatcontainuserandauthoritiesdetails,thensettheusersByUsernameQuery
andauthoritiesByUsernameQuerypropertiesofJdbcDaoImpltoretrieveuserdetailsandtheirauthorities
fromthesecustomtables.
TheusersByUsernameQuerypropertyspecifiestheSQLquerytoretrieveuserdetailsbasedonthegiven
username. If user details are stored in a table named MY_USERS that contains USERNAME and
PASSWORD columns, you can set the following SQL query as the value of usersByUsernameQuery
propertytoretrieveuserdetails:
selectUSERNAME,PASSWORD,‘true’asENABLEDfromMY_USERSwhereUSERNAME=?
You should note that the columns returned by the SQL query must be USERNAME, PASSWORD and
ENABLED.Ifaparticularcolumn(like,ENABLED)doesn’texistinyourdatabasetable,thenreturna
defaultvalue(like,‘true’)forthatcolumn.
TheauthoritiesByUsernameQuerypropertyspecifiestheSQLquery toretrieve authorities basedonthe
givenusername.IfauthoritydetailsarestoredinatablenamedMY_AUTHORITIESthatcontainsUSER
andROLEcolumns, youcan set the followingSQLquery as the value of authoritiesByUsernameQuery
propertytoretrieveauthorities:
selectUSERASUSERNAME,ROLEASAUTHORITYfromMY_AUTHORITIESwhereUSER=?
YoushouldnotethatthecolumnsreturnedbytheSQLquerymustbeUSERNAMEandAUTHORITY.
Ifyourapplicationstoresencodedpasswordsinthedatabase,youcanusethe<password-encoder>sub-
element of <authentication-provider> element to specify the password encoder (an implementation of
Spring’sPasswordEncoderinterface)tobeusedtoconvertthesubmittedpasswordsintotheirencoded
form. BCryptPasswordEncoder is a concrete implementation of PasswordEncoder that uses BCrypt
hashing algorithm (http://en.wikipedia.org/wiki/Bcrypt). The DaoAuthenticationProvider uses the
configured password encoder to encode the submitted password and compare it with the password
loadedbytheUserDetailsService.
Let’snowlookatthewebrequestsecurityconfigurationintheMyBankwebapplication.
Webrequestsecurity
The following example listing shows how web request security is configured for the MyBank web
application:
Examplelisting14-9–applicationContext-security.xml–websecurityconfiguration
Project–ch14-bankapp-db-security
Sourcelocation-src/main/resources/META-INF/spring
<httpuse-expressions="true">
<access-denied-handlererror-page="/access-denied"/>
<intercept-urlpattern="/fixedDeposit/*"
access="hasAnyRole('ROLE_CUSTOMER','ROLE_ADMIN')"/>
<form-loginlogin-page="/login"authentication-failure-handler-ref="authFailureHandler"/>
<logout/>
....
</http>
<beans:beanid="authFailureHandler"
class="sample.spring.chapter14.security.MyAuthFailureHandler"/>
If you compare the web request security configuration shown above with the one we saw in ch14-
bankapp-simple-security project (refer example listing 14-2), you’ll notice that we have added some
additionalconfigurationinformation.
The <access-denied-handler> element’s error-page attribute specifies the error page (refer to
scr/main/webapp/WEB-INF/jsp/access-denied.jsppage)to which anauthenticateduser isredirectedin
case the user attempts to access an unauthorized web page. The <form-login> element’s login-page
attribute specifies the URL that renders the login page. The value /login URL is mapped to
LoginController (refer to LoginController class of ch14-bankapp-db-security project) that renders the
loginpage(refer to scr/main/webapp/WEB-INF/jsp/login.jsp page). The authentication-failure-handler-
ref attribute refers to an AuthenticationFailureHandler bean that handles authentication failures. As the
above example listing shows, MyAuthFailureHandler (an implementation of
AuthenticationFailureHandler) is responsible for handling authentication failures in MyBank web
application.ThefollowingexamplelistingshowstheimplementationofMyAuthFailureHandlerclass:
Examplelisting14-10–MyAuthFailureHandlerclass
Project–ch14-bankapp-db-security
Sourcelocation-src/main/java/sample/spring/chatper14/security
packagesample.spring.chapter14.security;
.....
importorg.springframework.security.core.AuthenticationException;
importorg.springframework.security.web.authentication.AuthenticationFailureHandler;
publicclassMyAuthFailureHandlerimplementsAuthenticationFailureHandler{
@Override
publicvoidonAuthenticationFailure(HttpServletRequestrequest,
HttpServletResponseresponse,AuthenticationExceptionexception)
throwsIOException,ServletException{
request.setAttribute("exceptionMsg",exception.getMessage());
response.sendRedirect(request.getContextPath()+"/login?exceptionMsg="+
exception.getMessage());
}
}
AuthenticationFailureHandler interface defines an onAuthenticationFailure method which is invoked
when authentication fails. The onAuthenticationFailure method accepts an instance of
AuthenticationException that represents an authentication failure. In the above example listing, the
onAuthenticationFailuremethodredirectstheusertotheloginpageandpassestheexceptionmessageasa
querystringparameter.Ifyouenterwrongcredentials(orentercredentialsofauserwhoisdisabledin
thesystem)ontheloginpageofMyBankwebapplication,you’llnoticethattheMyAuthFailureHandler’s
onAuthenticationFailuremethod isinvoked.Forinstance,ifyouenter wrongcredentials, you’llseethe
message‘Badcredentials’.
Let’snowlookatACL-specificconfigurationinMyBankwebapplication.
JdbcMutableAclServiceconfiguration
As ACL permissions are stored in database tables, the MyBank web application uses Spring’s
JdbcMutableAclService to perform CRUD (Create Read Update Delete) operations on ACLs in the
tables.ThefollowingexamplelistingshowstheconfigurationofJdbcMutableAclService:
Examplelisting14-11–applicationContext-security.xml–JdbcMutableAclServiceconfiguration
Project–ch14-bankapp-db-security
Sourcelocation-src/main/resources/META-INF/spring
<beans:beanid="aclService"class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
<beans:constructor-argref="dataSource"/>
<beans:constructor-argref="lookupStrategy"/>
<beans:constructor-argref="aclCache"/>
</beans:bean>
The above example listing shows references to dataSource, lookupStrategy and aclCache beans are
passed to the JdbcMutableAclService’s constructor. Let’s now look at how dependencies (dataSource,
lookupStrategyandaclCache)ofJdbcMutableAclServiceareconfigured.
The dataSource bean identifies the javax.sql.DataSource that holds the ACL tables (refer to the
dataSourcebeandefinitionintheapplicationContext.xmlfileformoredetails).
The lookupStrategy bean represents an implementation of Spring’s LookupStrategy interface that is
responsible for looking up ACL information. The following example listing shows the lookupStrategy
beandefinition:
Examplelisting14-12–applicationContext-security.xml–LookupStrategyconfiguration
Project–ch14-bankapp-db-security
Sourcelocation-src/main/resources/META-INF/spring
<beans:beanid="lookupStrategy"
class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
<beans:constructor-argref="dataSource"/>
<beans:constructor-argref="aclCache"/>
<beans:constructor-arg>
<beans:beanclass="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<beans:constructor-arg>
<beans:bean
class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<beans:constructor-argvalue="ROLE_ADMIN"/>
</beans:bean>
</beans:constructor-arg>
</beans:bean>
</beans:constructor-arg>
<beans:constructor-arg>
<beans:bean
class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
<beans:constructor-arg>
<beans:beanclass="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
</beans:constructor-arg>
</beans:bean>
</beans:constructor-arg>
</beans:bean>
In the above example listing, Spring’s BasicLookupStrategy (an implementation of
LookupStrategy interface) uses JDBC queries to fetch ACL details from standard ACL tables
(ACL_CLASS, ACL_ENTRY, ACL_SID and ACL_OBJECT_IDENTITY). If the ACL information is
stored in custom database tables, then you can customize the JDBC queries by setting selectClause,
lookupPrimaryKeysWhereClause, lookupObjectIdentitiesWhereClause and orderByClause properties of
BasicLookupStrategy. For more details on these properties, please refer to the API documentation of
SpringSecurity.
BasicLookupStrategy’s constructor accepts arguments of type DataSource (represents the database that
contains the ACL tables), AclCache (represents the ACL caching layer),
AclAuthorizationStrategy (represents the strategy to determine if a SIDhas the permissions to perform
administrative actions on the ACL entries of a domain object instance), and
PermissionGrantingStrategy (strategy to grant or deny access to secured objects depending on the
permissionsassignedtoSIDs).
In the above example listing, the AclAuthorizationStrategyImpl class implements
AclAuthorizationStrategy. The AclAuthorizationStrategyImpl’s constructor accepts an instance of
GrantedAuthoritythatspecifiestherolethatcanperformadministrativeactions(like,changingownership
ofanACLentry)ontheACLentries(representedbyanobjectoftypeMutableAcl)ofadomainobject
instance. In the above example listing, ROLE_ADMIN role is passed to the
AclAuthorizationStrategyImpl, which means that a user with ROLE_ADMIN role can perform
administrativeactionsonACLentries.Laterinthischapter,we’llseethattheAclAuthorizationStrategy
securestheMutableAclinstancefromunauthorizedmodification.
In the above example listing, the DefaultPermissionGrantingStrategy implements
PermissionGrantingStrategy.TheDefaultPermissionGrantingStrategy’sconstructoracceptsaninstanceof
AuditLogger that logs success and/or failure in granting permissions for an ACL entry in the
ACL_ENTRY table. In the above example listing, the ConsoleAuditLogger (an implementation of
AuditLoggerthatwritesontheconsole)logssuccessfulpermissionsifaudit_successcolumn’svalueis
settotrue(thatis,1),andlogsfailedpermissionsifaudit_failurecolumn’svalueissettotrue(thatis,1).
Forinstance,thefollowingmessageshowsoutputfromtheConsoleAuditLoggeronsuccessfulpermission
toanACLentry:
GRANTEDduetoACE:AccessControlEntryImpl[id:1037;granting:true;sid:PrincipalSid[cust1];permission:
BasePermission[...............................R=1];auditSuccess:true;auditFailure:true]
BasicLookupStrategy accepts an instance of AclCache object (represented by the aclCache bean in
example listing 14-12) that represents a cache for ACLs. The following example listing shows the
aclCachebeandefinitionthatisusedbyBasicLookupStrategytocacheACLs:
Examplelisting14-13–applicationContext-security.xml–Cacheconfiguration
Project–ch14-bankapp-db-security
Sourcelocation-src/main/resources/META-INF/spring
<beans:bean id="aclCache"
class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
<beans:constructor-arg>
<beans:beanclass="org.springframework.cache.ehcache.EhCacheFactoryBean">
<beans:propertyname="cacheManager">
<beans:beanclass="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
</beans:property>
<beans:propertyname="cacheName"value="aclCache"/>
</beans:bean>
</beans:constructor-arg>
</beans:bean>
EhCacheBasedAclCache is an implementation of AclCache that uses EhCache (http://ehcache.org/) for
caching ACLs. EhCacheFactoryBean is Spring FactoryBean that creates an instance of
net.sf.ehcache.EhCache. The cacheManager property of EhCacheFactoryBean specifies the
net.sf.ehcache.CacheManagerinstancethatisresponsibleformanagingthecache.Intheaboveexample
listing, EhCacheManagerFactoryBean is a Spring FactoryBean that creates an instance of
net.sf.ehcache.CacheManager.TheEhCacheFactoryBean’scacheNamepropertyreferstothecacheregion
tobecreatedinEhCacheforstoringACLs.
Now,thatwehaveconfiguredJdbcMutableAclServicetoperformCRUDoperationsonACLs,let’slook
at the method-level security configuration that uses ACLs loaded by JdbcMutableAclService for
authorizationpurposes.
Method-levelsecurityconfiguration
Thefollowingexamplelistingshowsmethod-levelsecurityconfigurationintheMyBankwebapplication:
Examplelisting14-14–applicationContext-security.xml–Method-levelsecurityconfiguration
Project–ch14-bankapp-db-security
Sourcelocation-src/main/resources/META-INF/spring
<global-method-securitypre-post-annotations="enabled">
<expression-handlerref="expressionHandler"/>
</global-method-security>
The <global-method-security> element’s pre-post-annotations attribute value is set to enabled, which
enables use of @PreAuthorize (explained earlier in this chapter), @PostAuthorize, @PostFilter and
@PostAuthorizeannotations.Intheaboveexamplelisting,the<expression-handler>elementreferstothe
expressionHandlerbeanthatconfiguresaSecurityExpressionHandlerinstance.
ASecurityExpressionHandlerisusedbySpringSecuritytoevaluatesecurityexpressions,likehasRole,
hasAnyRole,hasPermission,andsoon.ThefollowingexamplelistingshowstheexpressionHandlerbean
definition that configures a DefaultMethodSecurityExpressionHandler (a SecurityExpressionHandler
implementation)instance:
Examplelisting14-15–applicationContext-security.xml–SecurityExpressionHandlerconfiguration
Project–ch14-bankapp-db-security
Sourcelocation-src/main/resources/META-INF/spring
<beans:beanid="expressionHandler"class="org.springframework.security.access.expression.method.
DefaultMethodSecurityExpressionHandler">
<beans:propertyname="permissionEvaluator"ref="permissionEvaluator"/>
<beans:propertyname="permissionCacheOptimizer">
<beans:beanclass="org.springframework.security.acls.AclPermissionCacheOptimizer">
<beans:constructor-argref="aclService"/>
</beans:bean>
</beans:property>
</beans:bean>
<beans:beanid="permissionEvaluator"
class="org.springframework.security.acls.AclPermissionEvaluator">
<beans:constructor-argref="aclService"/>
</beans:bean>
In the above example listing, the permissionEvaluator property refers to an instance of
AclPermissionEvaluator instance that uses ACLs to evaluate security expressions. The
permissionCacheOptimzer property refers to an instance of AclPermissionCacheOptimizer that loads
ACLsinbatchestooptimizeperformance.
Let’snowlookathowdomainobjectinstancesecurityisachievedintheMyBankwebapplication.
Domainobjectinstancesecurity
We saw earlier that the @PreAuthorize annotation specifies role-based security constraints on the
methods. If a @PreAuthorize annotated method accepts a domain object instance as an argument, the
@PreAuthorizeannotationcanspecifytheACLpermissionsthattheauthenticatedusermusthaveonthe
domainobjectinstance to invoke themethod. The following examplelisting showsthe @PreAuthorize
annotationthatspecifiesACLpermissions:
Example listing 14-16 – FixedDepositService interface – @PreAuthorize annotation with ACL
permissions
Project–ch14-bankapp-db-security
Sourcelocation-src/main/java/sample/spring/chatper14/service
packagesample.spring.chapter14.service;
importorg.springframework.security.access.prepost.PreAuthorize;
importsample.spring.chapter14.domain.FixedDepositDetails;
.....
publicinterfaceFixedDepositService{
.....
@PreAuthorize("hasPermission(#fixedDepositDetails,write)")
voideditFixedDeposit(FixedDepositDetailsfixedDepositDetails);
}
Intheaboveexamplelisting,theFixedDepositService’seditFixedDepositmethodacceptsaninstanceof
FixedDepositDetails. In the hasPermission expression, #fixedDepositDetails represents an expression
variable that refers to the FixedDepositDetails instance passed to the editFixedDeposit method. The
hasPermission expression evaluates to true if the authenticated user has write permission on the
FixedDepositDetails instance passed to the editFixedDeposit method. At runtime, the hasPermission
expressionisevaluatedby the configured AclPermissionEvaluator (refer example listing 14-15). If the
hasPermissionevaluatestotrue,theeditFixedDepositmethodisinvoked.
If a method accepts a domain object identifier (instead of the actual domain object instance) as an
argument,youcanstillspecifyACLpermissionsthatapplytothedomainobjectinstancereferredbythe
identifier. The following example listing shows the provideAccessToAdmin method that accepts
fixedDepositId(whichuniquelyidentifiesaFixedDepositDetailsinstance)asargument:
Examplelisting14-17–FixedDepositServiceinterface–@PreAuthorizeannotationusage
Project–ch14-bankapp-db-security
Sourcelocation-src/main/java/sample/spring/chatper14/service
packagesample.spring.chapter14.service;
importorg.springframework.security.access.prepost.PreAuthorize;
.....
publicinterfaceFixedDepositService{
.....
@PreAuthorize("hasPermission(#fixedDepositId,
'sample.spring.chapter14.domain.FixedDepositDetails',write)")
voidprovideAccessToAdmin(intfixedDepositId);
}
Intheaboveexamplelisting,#fixedDepositIdexpressionvariablereferstothefixedDepositIdargument
passedtotheprovideAccessToAdminmethod.AsthefixedDepositIdargumentidentifiesaninstanceof
FixedDepositDetailsobject,thefully-qualifiednameoftheFixedDepositDetailsclassisspecifiedasthe
second argument of hasPermission expression. The hasPermission(#fixedDepositId,
‘sample.spring.chapter14.domain.FixedDepositDetails’,write)evaluatestotrueiftheauthenticateduser
has write permission on the FixedDepositDetails instance identified by the fixedDepositId argument
passedtotheprovideAccessToAdminmethod.
Itisalsopossibletocombinemultiplesecurityexpressionstoformamorecomplexsecurityexpression,
asshowninthefollowingexamplelisting:
Examplelisting14-18–FixedDepositServiceinterface–@PreAuthorizeannotationusage
Project–ch14-bankapp-db-security
Sourcelocation-src/main/java/sample/spring/chatper14/service
packagesample.spring.chapter14.service;
importorg.springframework.security.access.prepost.PreAuthorize;
.....
publicinterfaceFixedDepositService{
.....
@PreAuthorize("hasPermission(#fixedDepositId,
'sample.spring.chapter14.domain.FixedDepositDetails',read)or"
+"hasPermission(#fixedDepositId,
'sample.spring.chapter14.domain.FixedDepositDetails',admin)")
FixedDepositDetailsgetFixedDeposit(intfixedDepositId);
.....
}
Intheaboveexamplelisting,thetwohasPermissionexpressionshavebeencombinedusingoroperatorto
formamoresophisticatedsecurityexpression.ThegetFixedDepositmethodwillbeinvokedonlyifthe
authenticated userhas read or admin permission on the FixedDepositDetails instance identified by the
fixedDepositIdargument.
If a method returns a list of domain object instances, you can filter the results by using @PostFilter
annotation.Thefollowingexamplelistingshowsusageof@PostFilterannotation:
Examplelisting14-19–FixedDepositServiceinterface–@PostFilterannotationusage
Project–ch14-bankapp-db-security
Sourcelocation-src/main/java/sample/spring/chatper14/service
packagesample.spring.chapter14.service;
importorg.springframework.security.access.prepost.PostFilter;
.....
publicinterfaceFixedDepositService{
.....
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostFilter("hasPermission(filterObject,read)orhasPermission(filterObject,admin)")
List<FixedDepositDetails>getAllFixedDeposits();
.....
}
Like @PreAuthorize annotation, @PostFilter specifies a security expression. If a method is annotated
with @PostFilter annotation, Spring Security iterates over the collection returned by the method and
removes the elements for which the specified security expression returns false. In the above example
listing, Spring Security iterates over the collection of FixedDepositDetails instances returned by the
getAllFixedDepositsmethodandremovestheinstancesforwhichtheauthenticateduserdoesn’thaveread
or admin permission. The term filterObject in the hasPermission expression of @PostFilter annotation
referstothecurrentobjectinthecollection.NoticethatthegetAllFixedDepositsmethodisalsoannotated
with@PreAuthorizeannotation,whichindicatesthatthegetAllFixedDepositsmethodisonlyinvokedif
theauthenticateduserhasROLE_ADMINrole.
Wesawearlierthatacustomer(ROLE_CUSTOMERrole)makesafixeddepositavailabletotheadmin
user(ROLE_ADMINrole)byclickingthe‘Provideaccesstoadmin’hyperlink(referfigure14-7).When
thecustomerclicksthe‘Provideaccesstoadmin’,applicationgrantsread,adminanddeletepermissions
onthefixeddeposittotheadminuser.We’llseelaterinthischapterhowthisisdoneprogrammatically.
The FixedDepositService’s getAllFixedDeposits method is invoked when a user with ROLE_ADMIN
rolevisitsthewebpagethatshowslistsoffixeddeposits(referfigure14-8).Astheadminusershould
onlybeabletoseefixeddepositsforwhichcustomershavegrantedpermissions,thegetAllFixedDeposits
method is annotated with @PostFilter annotation to remove fixed deposits on which the admin user
doesn’thavereadoradminpermission.
Let’snowlookathowtoprogrammaticallymanageACLentries.
ManagingACLentriesprogrammatically
YoucanmanageACLentriesprogrammaticallybyusingtheJdbcMutableAclServicethatwasconfigured
intheapplicationcontextXMLfile(referexamplelisting14-11).
When a customer creates a new fixed deposit, read and write permissions on the newly created fixed
deposit are granted to the customer. When a customer clicks the ‘Provide access to admin’ hyperlink
correspondingtoafixeddeposit,theMyBankwebapplicationgrantsread,adminanddeletepermissions
onthefixeddeposittotheadminuser.
ThefollowingexamplelistingshowstheFixedDepositServiceImpl’sprovideAccessToAdminmethodthat
isinvokedwhenthe‘Provideaccesstoadmin’hyperlinkisclicked:
Examplelisting14-20–FixedDepositServiceImplclass–addingACLpermissions
Project–ch14-bankapp-db-security
Sourcelocation-src/main/java/sample/spring/chatper14/service
packagesample.spring.chapter14.service;
importorg.springframework.security.acls.domain.*;
importorg.springframework.security.acls.model.*;
.....
@Service
publicclassFixedDepositServiceImplimplementsFixedDepositService{
.....
@Autowired
privateMutableAclServicemutableAclService;
@Override
publicvoidprovideAccessToAdmin(intfixedDepositId){
addPermission(fixedDepositId,newPrincipalSid("admin"),BasePermission.READ);
addPermission(fixedDepositId,newPrincipalSid("admin"),BasePermission.ADMINISTRATION);
addPermission(fixedDepositId,newPrincipalSid("admin"),BasePermission.DELETE);
}
privatevoidaddPermission(longfixedDepositId,Sidrecipient,Permissionpermission){.....}
}
Intheaboveexamplelisting,theprovideAccessToAdminmethodusestheaddPermissionmethodtogrant
read, admin and delete permissions to the admin user. The following arguments are passed to the
addPermissionmethod:
§fixedDepositId–uniquelyidentifiestheFixedDepositDetails instance on whom wewantto grant
permissions
§ PrincipalSid object - represents the SID (that is, the user or role) whom we want to grant
permissions.ThePrincipalSidclassimplementsSpringSecurity’sSidinterface.
§ permission to grant – The BasePermission class defines constants, like READ,
ADMINISTRATION,DELETE,andsoon,representingstandardpermissionsthatwecangrantto
PrincipalSid.TheBasePermissionclassimplementsSpringSecurity’sPermissioninterface.
ThefollowingexamplelistingshowstheimplementationofaddPermissionmethod:
Examplelisting14-21–FixedDepositServiceImplclass–addingACLpermissions
Project–ch14-bankapp-db-security
Sourcelocation-src/main/java/sample/spring/chatper14/service
packagesample.spring.chapter14.service;
importorg.springframework.security.acls.domain.*;
importorg.springframework.security.acls.model.*;
.....
@Service
publicclassFixedDepositServiceImplimplementsFixedDepositService{
.....
@Autowired
privateMutableAclServicemutableAclService;
.....
privatevoidaddPermission(longfixedDepositId,Sidrecipient,Permissionpermission){
MutableAclacl;
ObjectIdentityoid=newObjectIdentityImpl(FixedDepositDetails.class,fixedDepositId);
try{
acl=(MutableAcl)mutableAclService.readAclById(oid);
}catch(NotFoundExceptionnfe){
acl=mutableAclService.createAcl(oid);
}
acl.insertAce(acl.getEntries().size(),permission,recipient,true);
mutableAclService.updateAcl(acl);
}
.....
}
As JdbcMutableAclService class implements MutableAclService interface, JdbcMutableAclService
instanceisautowiredintotheFixedDepositServiceImplclass.
Tograntpermissions,theaddPermissionmethodfollowsthesesteps:
1)declaresanobjectoftypeMutableAcl.AMutableAclobject representsACLentriesof adomain
objectinstance.MutableAcldefinesmethodsthatyoucanusetomodifyACLentries.
2) creates an instance of ObjectIdentityImpl by passing domain object type (which is
FixedDepositDetails.class)andidentity(whichisfixedDepositId)asargumentstotheconstructor
3) retrieves the ACL entries for the domain object instance by calling MutableAclService’s
readAclById method. If no ACL entries are found, the readAclById method throws
NotFoundException.
oIfNotFoundException isthrown,MutableAclService’s createAcl method is used to create an
empty instance of MutableAcl that doesn’t contain any ACL entries. This is equivalent to
creatinganentryintheACL_OBJECT_IDENTITYtable(referfigure14-11).
4) adds ACL entries to the MutableAcl instance using insertAce method. The ACL entries added to
MutableAclareeventuallypersistedintotheACL_ENTRYtable(referfigure14-12).Thearguments
passed to the insertAce method are - the index location where the ACL entry is to be added
(corresponds to the ACE_ORDER column), the permission to be added (corresponds to the MASK
column),theSIDforwhomthepermissionistobeadded(correspondstotheSIDcolumn),andthe
flag indicating that the ACL entry is for granting or denying permission (corresponds to the
GRANTINGcolumn).
5)persistschangesmadetotheMutableAclinstanceusingMutableAclService’supdateAclmethod.
The following example listing shows FixedDepositServiceImpl’s closeFixedDeposit method that is
invokedwhentheadminuserclicksthe‘Close’hyperlinktocloseafixeddeposit(referfigure14-8):
Examplelisting14-22–FixedDepositServiceImplclass–removingACLs
Project–ch14-bankapp-db-security
Sourcelocation-src/main/java/sample/spring/chatper14/service
packagesample.spring.chapter14.service;
importorg.springframework.security.acls.domain.ObjectIdentityImpl;
importorg.springframework.security.acls.model.MutableAclService;
importorg.springframework.security.acls.model.ObjectIdentity;
.....
@Service
publicclassFixedDepositServiceImplimplementsFixedDepositService{
.....
@Autowired
privateMutableAclServicemutableAclService;
.....
@Override
publicvoidcloseFixedDeposit(intfixedDepositId){
fixedDepositDao.closeFixedDeposit(fixedDepositId);
ObjectIdentityoid=newObjectIdentityImpl(FixedDepositDetails.class,fixedDepositId);
mutableAclService.deleteAcl(oid,false);
}
.....
}
Intheaboveexamplelisting,MutableAclService’sdeleteAclmethodisusedtodeleteACLentriesofthe
fixed deposit identified by the ObjectIdentity instance. For instance, if the fixedDepositId is 101,
deleteAclmethoddeletesallACLentriesoffixeddeposit101fromACL_ENTRY(referfigure14-12)
andACL_OBJECT_IDENTITY(referfigure14-11)tables.
Let’snowlookathowMutableAclinstanceissecuredfromunauthorizedmodifications.
MutableAclandsecurity
Spring Security’s MutableAcl interface defines methods for modifying ACL entries of a domain object
instance.WesawthattheMyBankwebapplicationusesMutableAcl’sinsertAcemethodtoaddanACL
entry for a domain object instance (refer example listing 14-21). The
AclAuthorizationStrategyImplinstancethatwesuppliedtotheBasicLookupStrategy(referexamplelisting
14-12) is used behind the scenes to ensure that the authenticated user has appropriate permissions to
modifyACLentries.
AnauthenticatedusercanmodifyACLentriesofadomainobjectinstanceifatleastoneofthefollowing
conditionsistrue:
§iftheauthenticateduserownsthedomainobjectinstance,theusercanmodifytheACLentriesofthat
domainobjectinstance
§ if the authenticated user holds the authority that was passed to AclAuthorizationStrategyImpl’s
constructor. In example listing 14-12, the ROLE_ADMIN role was passed to
AclAuthorizationStrategyImpl’s constructor; therefore, a user with ROLE_ADMIN role can make
changestoACLentriesofanydomainobjectinstance.
§ if the authenticated user has BasePermission’s ADMINISTRATION permission on the domain
objectinstance.
14-5Summary
In this chapter, we lookedathowto useSpring Securityframeworkto secureSpringapplications. We
looked at how to incorporate web request security, method-level security, and domain object instance
security.
Appendix A – Importing and deploying sample projects in
EclipseIDE(orIntelliJIDEA)
Inthisappendix,we’lllookathowtosetupthedevelopmentenvironment,importasampleprojectinto
EclipseIDE(orIntelliJIDEA),andrunitasastandaloneapplication(ifthesampleprojectrepresentsa
standalone Java application) or deploy it on Tomcat 7 server (if the sample project represents a web
application).
A-1Settingupthedevelopmentenvironment
Beforesettingupthedevelopmentenvironment,youneedtodothefollowing:
·DownloadandinstallEclipseIDE(orIntelliJIDEA)–YoucandownloadtheEclipseIDEfor
JavaEEDevelopersfromhttp://www.eclipse.org/downloads.ToinstallEclipseIDE,allyouneedto
doistounzipthedownloadedZIPfileintoadirectory.
·Download and install Tomcat 7 server – You can download the Tomcat 7 server from
http://tomcat.apache.org/download-70.cgi.ItisrecommendedthatyoudownloadtheTomcat7bundled
asZIPfile,andunzipthebundleintoyourlocalfilesystem.
·Download and install Maven 3 build tool – You can download Maven 3 from
http://maven.apache.org/download.cgi. To install Maven, all you need to do is to unzip the
downloaded ZIP file into a directory. Maven is used for converting the sample web projects that
accompanythisbookintoEclipseIDEorIntelliJIDEAprojects.
Let’slookathowtoimportasampleprojectintoEclipseIDE.
A-2ImportingasampleprojectintoEclipseIDE(orIntelliJIDEA)
Itisrecommendedthatyoudownloadthesampleprojectsthataccompanythisbookfromthefollowing
Googlecodeproject:
https://code.google.com/p/getting-started-with-spring-framework-2edition/
Therestofthissectionassumesthatyouhavecreatedaspring-samplesdirectoryinyourlocalfilesystem
thatcontainsallthesampleprojectsthataccompanythisbook.
Tosuccessfullyimportasampleproject,youneedtodothefollowing:
§ConverttheprojectintoanEclipseIDEorIntelliJIDEAproject
§ Configure an M2_REPO classpath variable in the Eclipse IDE (or IntelliJ IDEA). M2_REPO
variable points to the local mavenrepository that contains the JAR files on which the project
depends.
Let’snowlookattheabovementionedstepsindetail.
Importingasampleproject
Each sample project contains a pom.xml file that contains configuration of Eclipse, IntelliJ IDEA and
Tomcatmavenplugins.ThesepluginsareusedbymavenforconvertingasampleprojectintoEclipseIDE
orIntelliJIDEAproject,andfordeployingtheprojectonanembeddedTomcat7instance.Youshould
note that the Tomcat Maven plugin (http://tomcat.apache.org/maven-plugin.html) is configured only for
sample projects that represent web applications. The pom.xml file also specifies the JAR files (like
spring-core,spring-beans,andsoon)onwhichtheprojectdepends.
TocreateEclipseIDEorIntelliJIDEAspecificconfigurationfilesforthesampleproject,followthese
steps:
§ Open the command prompt and set JAVA_HOME environment variable to point to Java SDK
installationdirectory:
C:\>setJAVA_HOME=C:\ProgramFiles\Java\jdk1.7.0_25
§Gotothedirectorycontainingthesampleproject:
C:\>cdspring-samples
C:\spring-samples>cdch01-bankapp-xml
C:\spring-samples\ch01-bankapp-xml>
§AddpathofthebindirectoryofyourmaveninstallationtothePATHenvironmentvariable:
C:\spring-samples\ch01-bankapp-xml>setpath=%path%;C:\apache-maven-3.0.4\bin
§IfyouwanttoimportthesampleprojectintoEclipseIDE,executetheeclipse:eclipsegoalofMaven
EclipsePlugin(http://maven.apache.org/plugins/maven-eclipse-plugin/):
C:\spring-samples\ch01-bankapp-xml>mvneclipse:eclipse
Executing the eclipse:eclipse goal downloads dependencies of the sample project and creates
configurationfiles(like.classpathand.project)forEclipseIDE.
OR
§IfyouwanttoimportthesampleprojectintoIntelliJIDEA,executetheidea:idea goalof Maven
IDEAPlugin(http://maven.apache.org/plugins/maven-idea-plugin/):
C:\spring-web-mvc-samples\ch01-xml-config>mvnidea:idea
Executing the idea:idea goal downloads dependencies of the sample project and creates
configurationfiles(like.ipr,.imland.iws)forIntelliJIDEA.
NOTEApom.xmlfileisalsoprovidedattherootofthesourcecodedistribution,whichbuildsallthe
projects.Youcangotospring-samplesdirectoryandexecutethemvneclipse:eclipse(ormvnidea:idea)
commandtoconvertalltheprojectsintoEclipseIDE(orIntelliJIDEA)projects.
Now,importthesampleprojectintoEclipseIDEbyfollowingthesesteps:
§GotoFileàImportoption.
§SelecttheGeneralàExistingProjectsintoWorkspaceoptionfromthedialogbox,andclickNext.
§Selectthesampleproject(ex.ch01-bankapp-xml)directoryfromthefilesystem,andclickFinish.
ConfiguringtheM2_REPOclasspathvariableintheEclipseIDE
Whenyouexecutetheeclipse:eclipseoridea:ideagoal,dependenciesoftheprojectaredownloadedinto
the<home-directory>/.m2/repositorydirectory.Here,<home-directory>isthehomedirectoryoftheuser.
OnWindows,thisreferstoC:\DocumentsandSettings\myusername\.m2\repositorydirectory.Bydefault,
.classpathfilecreatedbyexecutionofeclipse:eclipsegoalreferstotheJARdependenciesoftheproject
usingM2_REPOclasspathvariable.Forthisreason,youneedtoconfigureanewM2_REPOclasspath
variableinEclipseIDEthatrefersto<home-directory>/.m2/repositorydirectory.
ToconfigureanewM2_REPOvariable,followthesesteps:
§GotoWindowsàPreferencesoption.ThiswillshowthePreferencesdialogbox.
§SelecttheJavaàBuildPathàClasspathVariablesoptioninthedialogboxtoviewtheconfigured
classpathvariables.
§Now,clickNewbuttontoconfigureanewM2_REPOclasspathvariable.Itisimportanttonotethat
yousettheM2_REPOclasspathvariableto<home-directory>/.m2/repositorydirectory.
We have now successfully imported the sample project into the Eclipse IDE and set the M2_REPO
classpath variable. If the project represents a standalone application, you can run the application by
followingthesesteps:
§InEclipseIDE’sProjectExplorertab,right-clickontheJavaclassthatcontainsthemainmethodof
theapplication.You’llnowseethelistofactionsthatcanbeperformedontheselectedJavaclass.
§SelectRunAsàJavaApplicationoption.ThiswillexecutethemainmethodoftheJavaclass.
Let’snowlookathowEclipseIDEisconfiguredtoworkwithTomcat7server.
A-3ConfiguringEclipseIDEwithTomcat7server
YouneedtoopenEclipseIDE’sServersviewtoconfigureEclipseIDEwithTomat7server.Toopenthe
Serversview, select Window à Show View à Serversoption from the Eclipse IDE’s menu bar. To
configureaserverwithEclipseIDE,firstgototheServersview,right-clickintheServersviews,and
selectNewàServeroption.You’llnowseeaNewServerwizardwhichallowsyoutoconfigureaserver
withEclipseIDEinastep-by-stepfashion.Thefirststepis‘DefineaNewServer’,whereinyouneedto
choose the type and version of the server with which you want to configure your Eclipse IDE. The
followingfigureshowsthe‘DefineaNewServer’step:
FigureA-1SelecttheTomcatserverversionthatyouwanttousewithEclipseIDE
SelectApacheàTomcatv7.0Serverastheserver,andset‘Tomcatv7.0’astheservername.Clickthe
NextbuttontogotothenextstepofconfiguringTomcat7serverwithEclipseIDE.Thenextstepisto
specifyinstallationdirectoryofTomcat7server,asshowninfigureA-2.
FigureA-2SpecifyTomcatserverinstallationdirectoryandsettheJavaSDKtobeusedbytheserver.
To set the Tomcat installation directory, click the Browse button (refer figure A-2) and select the
directoryinwhichyouunzippedtheTomcatZIPfile.Also,clicktheInstalledJREsbuttonandconfigure
the Java SDK to be used by Eclipse IDE for running the Tomcat server. Click the Finish button to
complete configuration of Tomcat 7 server with Eclipse IDE. You’ll now be able to see the newly
configuredTomcat7serverintheServersview,asshowninthefollowingfigure:
FigureA-3TheServersviewshowsthenewlyconfiguredTomcat7server
Now,thatwehaveconfiguredTomcat7server,let’slookathowtodeployasamplewebprojecttothe
configuredTomcat7server.
A-4DeployingawebprojectonTomcat7server
Todeployawebproject(ex.ch10-helloworld)onTomcat7server,followthesesteps:
§Right-clickonthesamplewebprojectinEclipseIDE’sProjectExplorertab.You’llnowseethelist
ofactionsthatcanbeperformedontheselectedwebproject.
§ If you want to simply deploy the web project, select Run AsàRun on Server option. This will
deploythewebprojectontheTomcat7serverthatweconfiguredinsectionA-3.
OR
§Ifyouwanttodeployanddebugthewebproject,thenselectDebugAsàDebugonServeroption.
ThiswilldeploythewebprojectontheTomcat7thatweconfiguredinsectionA-3,andallowyou
todebugthewebprojectbysettingbreakpointsintheEclipseIDE.
IfTomcat7serverisconfiguredcorrectlywithEclipseIDE,you’llnoticethatTomcat7serverisstarted
and the web project is deployed on it. If you now open a web browser and go to
http://localhost:8080/<sample-project-folder-name>,you’llseethehomepageofthewebproject.Here,
<sample-project-folder-name>referstothenameofthefolderofthesampleproject.
RunningtheTomcat7serverinembeddedmode
AsimplerwaytodeployandrunasamplewebprojectistouseanembeddedTomcat7server.Inallthe
samplewebprojects,MavenTomcatplugin(http://tomcat.apache.org/maven-plugin-2.0/)isconfiguredin
thepom.xmlfile.Ifyouexecutetomcat7:rungoalofMavenTomcatpluginbygoingtosampleproject’s
directory, the plugin takes care of downloading and starting Tomcat 7 in embedded mode and
automaticallydeployingthesamplewebprojectontheembeddedTomcat7instance.Tostoptheserver,
allyouneedtodoistopressCtrl-C.