Вы находитесь на странице: 1из 749

Pro

I
Fourth Edition

Chris Schaefer
Clarence
Rob Harrop

----I

4-


-
2015
32.973.26-018.2.75
53
681.3.07
""
. ..
/0..
..
"" :
ifo@wiamspublishig.com,http://www.williamspu\ishing.com

, , , , , .
53 Spring 4 , 4- . : . . - . "..
", 2015. - 752 .: . - . . .
ISBN 978-5-8459-1992-2 (.)
32.973.26-018.2.75

.
<t
, <t,
<t ,
APress, Berkeley, .
Authorized tanslation from the English language edition puished APress, !., Copyright 2014
Chris Schaefer, Clarence , Rob Harrop.
AJI rights reserved. No part of this work may reproduced or transmitted in any form or any means,
electronic or mechanical, including photocopying, recording, or any information storage or retrieval sys
tem, without the prior written permission of the copyright owner and the pulisher.
Russian language edition is pulished Williams Puishing House according to the Agreement with
R&I Enterprises lntemational, Copyright 2015.

-
, , Xappon
Spring 4
4-
. .
..
<t 24.06.201S. 70 100/16.
Times.
. '!. . 60,63. 'I.-. . 41,2.
500 . 3180.
Orne<taao

<
142300, , . , . , .1
, ". . ", 127055, r. , . , . 43, . 1

ISBN 978-5-8459-1992-2 (.) 2015, ""


ISBN 978-1-4302-6151-3 (.) 2014 Chris Schaefer, Clarence , Rob Harrop

17

1. Spring 19

2. 39

3. loC DI Spring 53

4. Spring 125

5. -
Spring 199

6. JDBC Spring 285


7. Hibernate Spring 345

8. Spring JPA 2 385

9. 451

1.
487

11. Spring 513

12. Spring 529

13. Spring 575

14. Spring 597

15. Spring 615

16. - Spring 623


17. WebSocket 699
18. Spring: Spring Batch, Spring lntegration,
Spring XD Spring Boot 719

743

15
15
16
17
1. Spring 19
Spring? 19
Spring Framework 20
? 24
25
27
Spring 34
Spring 34
Spring 34
Spring Tool Suite 35
Spring Security 35
Spring Batch Spring lntegration 36
36
Spring 36
JBoss Seam Framework 36
Google Guice 37
PicoContainer 37
J 7 37
37
2. 39
Spring Framework 40
40
Spring GitHub 40
Spring 40
Spring 41
43
Spring Maven 43
Spring 44
Spring "Hello World!" 44
"Hello \.\rld!" 44
51
3. loC DI Spring 53
54
54
Dependency Pull 55
Contextualized Dependency Lookup 56
Constructor Dependency lnjection 57
7
Setter Dependency lnjection 57
58
Setter lnjection Constructor lnjectio 59
Spring 62
Sprig 63
64
BeanFactory 64
ApplicationContext 66
ApplicationContext 67
Sprig 67
Spring 69
73
75
81
101
110
112
117
117
118
120
121
123

4. Spring 125
Spring 126
127
129
138
" Spring" 146
BeanNameAware 147
ApplicationContextAware 149
151
: MessageDigestFactoryBean 152
156
factory-bean factory-method 156
JavaBean 158
159
163
ApplicationContext 166
MessageSource 167
MessageSource 171
MessageSourceResol v 172
172
175
, Jv- 177
ApplicationContext Java 177
Java XML 182
8
182
Spring 183
186
Environment PropertySource 186
, JSR-330 191
, Groovy 195
197
5. -
Spring 199
201
202
202
202
203
Spring 203
203
"Hello \\rld!" 203
Spring 205
ProxyFactory 207
Spring 208
Spring 224
Pointcut 225
242
JDK 242
CGLIB 243
243
248
248
248
250
Pointcut 254
255
255
256
258
264
, 264
264
ProxyFactoryBean 265
270
@AspectJ 276
Spring 280
AspectJ 281
AspectJ 281
281
284
9
. JDBC Spring 285
- 286
286
JDBC 291
JD Spring 296
JD Spri11g 296
297
300
DAO 301
303
JdbcTemplate 305
JdcTemplate DAO 305
JdcTemplate 306
NamedParameterJdcTemplate 308
RowMapper<T> 309

ResultSetExtractor 312
Spri11g, JDBC 316
- JDBC 317
MappingSqlQuery<T> 318
SqlUpdate 323
326
BatchSqlUpdate 330
SqlFunction 336
Spri11g Data: JDBC 343
JDBC 343
344
7. Hibernate Spring 345
346
Hibernate 348
- Hibernate 351
352
" " 356
" " 359
Session Hibernate 363
Hibernate 363
Hibernate 364
375
378
380
Hibernate 382
383
8. Spring JPA 2 385
J 2.1 386
387
1
Entit yManagerFactory J 387
JPA ORM 390
JPA 391
JQL 391
406
409
411
413
I- J 2 420
Spring Data JPA 425
Spring Data JPA 426
Repository Spring Data J
426
ru 431
ru Hibemate Envers 439
440
EntityManagerFactory
ru 441
444
448
, JPA 449
450
9. 451
Spring 452
452
PlatformTransactionManager 454
454
TransactionDefinition 456
TransactionStatus 458
458
Spring Data JPA 459
460
Spring 462
462
L-r 471
475
478
Spring 479
JTA 479
JTA 480
JTA 485
485
1 .
487
488
Spring 488
11
489
Spring 492
Spring 498
499
ConversionServiceFactoryBean 500
Spring 501
Validator Spring 502
JSR-349: Bean Validation 504
I- 512
512

11. Spring 513


513
Spring 514
TaskScheduler 515
516
task 520
522
Spring 523
Spring 526
528

12. Spring 529


JPA 530
532
ContactService 533
- Spring 537
537
539
JMS Spring 541
ActiveMQ 542
JMS Spring 542
JMS Spring 543
JMS 2.0 546
- REST Spring 549
- REST 550
550
- REST 551
Spring MVC - REST 552
curl - REST 559
RestTemplate - REST 563
- REST Spring Security 567
AMQP Spring 570
573
13. Spring 575
576
Spring 578
12

580
580
Spring MVC 581
584
584
585
587
590
594
Selenim 594
595
14. Spring 597
Java 598
Groovy 600
600
602
602
Groovy Spring 603
604
, 604
606
Spring 608
610
613
614
15. Spring 615
JMX Spring 616
Spring JMX 616
VisalVM JMX 618
Hibernate 619
622
16. - Spring 623
625
625
ContactService 626
MVC Spring MVC 632
MVC 632
Spring V 634
Spring MVC 639
639
ContactController 641
642
643
Spring MVC 643
13
645
645

647
648
649
Apache .les 651
658
URL 658
658
662
667
JSR-349 670
jQur jQuery UI 673
jQuery jQuery Ul 674
jQur jQuery UI 674
CKEditor 676
jqGrid ,
678
685
685
686
688
- Sprig Security 689
Spring Security 690
692
695
Servlet 3 696
698
17. WebSocket 699
WebSocket 699
WebSocket Spring 700
WebSocket API 701
SockJS 706
STOMP 711
717

18. Spring: Spring Batch, Spring lntegration,


Spring XD Spring Boot 719
Spring Batch 720
JSR-352 727
Spring I ntegration 731
Spring XD 737
Spring Boot 740
742

743
, , , , ,
,
, .


- ,
Java JVM. ()
, .
, .
- Jv- SkywideSoft Technology Limited
(www. skywidesoft. ),
.
20 ,
,
. Java 2001 ,
2005 J-
, EJB, Spring Framework, Hibernate, JMS WS.
Jv- .

, ,
Java , ,

.
( ,
, , ), , ,
.
SpringSource - ,
Spring Framework.
First Banco. SpringSource
Cake Solutions (,
).
.
.
@robertharrop.


- - ,

.
2010 Springy Award - Community Champion.
( )
. dr_pompeii.
,
Apress:
Pro SpringSource dm Server (2009 .)
Spring Enterprise Recipes (2009 .)
16
Spring Recipes, Second Edition (20 \ .)
Pro Spring lntegration (2011 .)
Pro Spring Batch (2011 .)
Pro Spring (2012 .)
Pro Spring MVC: With Web Flow (2012 .)
Pro Spring Security (2013 .)
Pro ibemate and MongoDB (2013 .)
Pro JPA 2, Second Edition (2013 .)
Practical Spring LDAP (2013 .)
(www. manuelj ordanelera.ogspot. ),
(@dr_pompeii).


, , .
, ,
.
, .
.
, -
. ,
, , ,
.
,
, .
.
:
E-maiJ: info @williamspuishing.
Vv'W'N: http://www.williamspuishing.com
n :
: 127055, . , . , . 43, . 1
: 03150, , / 152

Spring Framework 4,
Spring,
,
Java.
Spring
Java, Hibernate, JPA 2 WebSocket.
,
,
, ,
- , .
, .
(loC) (DI).
- ()
Spring .
- Spring Spring
WebSocket.
- Java 8.
Groovy
.
Sring-
. Jv-,
Spring
. ,
Java.
1
Spring
Java,
, 1840-
. "" - Jv
- , ,
,
.
Java -
""
. ,

, .
- , , Spring.

,
Spring Framework. Sprig,
,

- .
Spring Framework
.
Spring, 2.

Spring?
, Spring
, . Spnng
Jv-,
.
-, Sprig
Java (, , - Java Enterprise
Edition (JEE)) ( Apache Struts,
-).
-,
,
Spring - . Spring
,
20 1. Spring

Spring ( -)
, -
Spring, .
, Spring -
Spring, ,
Spring Framework. ,

.
Spring Framework
Spring Framework Experl
-: J2EE Design and Developmenl (Wrox, 2002 .). Spring
Framework ,
. ,
Spring Framework, ,
Spring,
Spring Framework 4.0.
Spring 0.9
, t
-: J2EE Design and Development
Spring 1..
Spring Core:
Spring Context: ApplicationContext, ,
, JNOI, Enterprise JavaBeans (EJB),

Spring : , Java Oatabase Connec
tivity (JOBC) (data access object - )
Spring ORM: ibemate, iBAJS Java Data Objects (JOO)
Spring : -
(), Alliance
Spring Web: ,
,
-
Spring Web : "--"
(Model-View-Controller - ) -
Spring 2.
L
, XML (XML Schema), .
, ,
,
-
( , )
1. Spring 21
@AspectJ
Java Persistence API (JPA)
POJO (Plain O\d Java Object -
Java), JMS
JDBC, SimpleJdcTemplate,
Java 5+
JDBC (NamedParameterJdbc
Template)
Spring MVC
Port\et V
: JRuby,
Groovy BeanShell
MBean J
TaskExecutor,
Java 5, @Transactional @Required
@AspectJ
Spring 2.5.
@Autowired
JSR-250 (@Resource, @PostConstruct, @PreDestroy)
: @Component, @Repository, @Service,
@Controller

,

: (pointcut) bean ( ... )
(load-time weaving) AspectJ
WebSphere
@Controller Spring V
@RequestMapping, @RequestParam @ModelAttribute

i\es 2
JSF 1.2
JAX-WS 2.0/2.1
Spring TestContext Framework,
,

Spring
JCA
22 1. Spring

Spring 3.0.
Java 5 - , r

Callaes, Futures, ExecutorService,
ThreadFactory
, -
JAR
Spring (Spring Expression Language - SpEL)
Java Config


REST
MVC XML
@CookieValue @RequestHeaders Spring MVC
JSR-303 ("
")
Java 6: @Async/@Asynchronous,
JSR-303, JSF 2.0, JPA 2.0 ..
, HSQL, 2 Dery
Spring 3.1.
Cache
XML; ,
@Profile


Spring XML, @ C ornpone ntScan,
@EnaleTransactionManagernent, @EnaleCaching, @EnaeWebMvc,
@EnaleSch e dul ing, @EnaeAs ync, @EnaleAs pectJAutoPro xy,
@EnaeLoadTirneWeaving @EnaeSpringConfigured
ibemate 4
Spring TestContext Framework
@Configuration
:
Servlet 3
EntityManagerFactory JPA
persistence. xrnl
Spring MVC Flash RedirectAttributes,


1. Spring 23
URI
@Valid
@RequestBody Spring
@RequestPart
Spring
Spring 3.2.
Servlet 3
Spring MVC
@ControllerAdvice @MatrixVariae Spring
R e s tTem plate
@RequestBody
Jackson JSON 2
iles 3
@RequestBody @RequestPart
Errors,

URL
Java Config
@DateTimeFormat Joda ime

,

/
, Gradle
GitHub: https: //githu.com/SpringSource/spring-framework
Java SE 7 / OpenJDK 7
. CGLI ASM Spring.
AspectJ 1.6 AspectJ 1.7
Spring 4.0
Getting
Started - www.spring.io/guides
,
Spring 3
Java 8 Java 6 Update 18
Spring Framework 4.0 Java 6

, (domain-specific language -
DSL), Groovy,
Groovy
24 1. Spring

, ,
-
WebSocket, SockJS STOM
?
Spring Framework (lnversion of
Control - /),
. , Foo
Bar.
Foo Bar, new
- . JoC,
r ( ) Foo
. , ..
, ,
-
(Dependency lnjection - DI). , DI,
3.

! 3,
. Spring
, .

DI Spring Java -
JavaBean . Spring
DI
(, L-,
Java, Groovy).
JavaBean (POJO)
Java,
. 3 , Spring
JavaBean DI;
, Spring, (bean).
, JavaBean, 3
.
DI - . ,
,
, ,
.
DI ,
, . ,
DI,

. Spring
JDK ( Proxy),
.
1. Spring 25

Spring
, ,
, .
Spring DI
, JavaBean;
, ,
, , . ,
, , DI,
JavaBean,
.


Spring DI,

Java. ,
DI ,
DI .
DI
Java (Java Community Process - JCP) JSR-330 ("Dependency
Injection for Java" - " Java") 2009 .
JSR-330 Java (Java Specification Request -
JSR) , Spring
Framework.
JEE 6 JSR-330 ,
. EJB ( 3.0)
;
Enterprise JavaBeans DI.
DI 3,
, DI
.
r . Dl
,
.
,
. ,
, JNDI
, (
) . DI
, JNDI
.
. DI
.
, ,
.
-
26 1. Spring

. 01
. ,
,
PostgreSQL, Orac\e. DI
- ,
Orac\e PostgreSQL.
.
,
, ,
( )
, ( ).
,
. DI
,
.
. DI,
.
. -,
; DAO
, .
- -
. ,
,
,
,
. ,
,
. DI
, ,
- .

-,
HttpServletRequest HttpServletResponse.
.
, Dl
. ,
, ,
,
01.
Java DI
Dl , Spring. Sprig
DI
, DI .
, DI ,
. , DI -
1. Spring 27
, ,
, . ,
DI.
DI (,
),
.
, ,
.


Spring DI
, Spring -
,
DI. Spring
, l-
.
Spring , Spring ,
Spring,
Spring.
Java
Java 8 ,
Spring Framework 4,
- Spring.
Java 8 j ava. time
(JSR-310) . Spring Framework 4.0
Java 8, - JDK 6
Update 18.
Java, 7 8.
- Spring
- ()
, .. ,
,
.
Spring

. JDK,
, ,
.
Eclipse AspecU (www.
eclipse.org/aspectj), ,
,
.
, Spring ,
, 2.0, Spring
AspectJ.
28 1. Spring

.
AspectJ.
@AspectJ
Spring.
, AspectJ 01.
ApplicationContext
Sprig.

! Spring Framework 3.2, @AspectJ


Java Config.

,
Spring
.
AspectJ, Spring .
. ,
,
,
. Spring Framework
, , .
Spring 5,
Spring Framework ,
, ,
, .
Spring (SpEL)
(Expression Language - EL) - ,
Java . EL
:
EL. , Java Server Pages (JSP) Java Server Faces (JSF)
EL, .
(Unified Expression
Language).
Spring Framework ,
,
Spring Framework, Spring.
, 3.0, Spring Spring (Spring
Expression Language - SpEL),
, Java Spring
.
JavaBean.
Spring
-
. -
1. Spring 29
JavaBean, ,
,
- ,
(, -, - REST
(Remote Procedure Catl - RPC)).
Spring L
Validator.
,
,
.
Errors,
.
Spring ValidationUtils,
,

Errors.
, JCP
Bean Validation API (JSR-303),
. ,
@NotNull, ,
, .
3.0, Spring
JSR-303. I-
Local ValidatorFactoryBean Validator ,
Spring. Spring .
Spring Hibemate Validator (hibernate. org / subproj ects /
validator), JSR-303.
(, JSF 2 Google Web Toolkit),
Spring ,
JSR-303 . ,

, .
I .

! Spring Framework 4.0, 1.1


Bean Validation API (JSR-349).

Spring
, ,
Java. Spring
.
Spring JDBC
(Java Database Connectivity - Java)
l-, l
.
30 1. Spring

! Spring Framework 4.0, iBATIS .


MyBatis-Spring Spring;
http: / /mybatis. github. io/spring/.


,
" ". ,
"-"
( NoSQL),
.
Sprig,
Spring Data (http: / /proj ects. spring. io/
spring-data).
.

! Spring .
, , Spring Data
. ,
, .

JDBC Spring JDBC


, . Hibemate, JDO JPA
-,
. l- Spring

, Spring.
9.
Spring
. ,
Oracle, Hibemate
.
Oracle ,
l- JDBC, Spring.
Object to XML Mapping () Spring

.
, r , .
XML.
JavaBean XML .
Sprig
Java XML , ,
. Spring
( JavaBean XML)
( XML Java)
Spring. , Java Architecture
1. Spring 31

for XML Binding (JAXB), Castor, XStream, JiBX XMLBeans.


12 Spring - L
, (Object to
XML Mapping - XML), Spring.

Spring
,
.
.
, ,
, ,
.
9.
JEE
01, Spring,
, DI
EJB JEE. JCP
EJB. 3.0 EJB, l-
DI.
, , EJB
Sring- JEE
(, JTA (Java
Transaction ! - l- Java),
JMS), Spring
. EJB Spring
, JNDI Spring.
Spring
Spring J.
, ,
JNDI, Spring
, JNDI,
.
JNDI, .
MVC -
Spring ,
, ,
-. Spring,

-.
,
, . Spring
- .
, Spring
. JSP JST L (Java Standard Tag
32 1. Spring

Library - Java),
Spring,
Apache Velocity, FreeMarker, Apache 1iles
XSL. , ,
Microsoft Excel, PDF JasperReports.
Spring V
-. Spring
-, Struts, JSF,
Atmosphere, Google Web Toolkit (GW) ..
- .
,
Ajax -
- (Rjch Internet Application - R[A).
,
, .
, HTML5, JavaScript CSS. 16
- Spring V.
WebSocket
Spring Framework 4.0, Java
! WebSocket (JSR-356). WebSocket I-
,
- . WebSocket
,
r .
WebSocket 16.

Java
. Spring,

.
Spring
, RMI (Java Remote Met.hod Invocation -
Java), JAX-WS, Hessian Burlap Caucho, JMS, AMQP (Advanced
Message Queuing Protocol - )
RES. , Spring
,
Java.
, Spring,
,

, .
Spring 12.
1. Spring 33


Spring Framework. Spring
l-
, Spring DI. Spring
JavaMail !.
Spring - DI
, .
,
. Spring
Apache locity,
Jv-.


.
,
-
.
Spring ,
.
,
Uni- cron.
, Spring
. ,
Spring CommonJ,
. Spring
, JDK 1imer ! Quartz,
.
Spring 11.

JDK 6, Java ,
, , JVM.
Groovy, JRuby JavaScript.
Spring
Sring-. , Spring-,
, JavaBean.
, Spring, Groovy, JRuby
BeanShell. Spring
14.

, Spring
- .
Spring ,
Java ,
34 1. Spring

, -
.
,
.
,
, .
Spring : ,
,
.
,
Spring
,
.

Spring
Spring
, , Spring
, CG LI , Apache Geronimo AspectJ.
,
, ;
-
Spring . ,
, Spring .
Spring
, Sprig Expert
One-to-One J2EE Design and Development.
Interface 21 Framework,
.
Spring Framework, .
Spring -
, 1.0 24 2004
. Sprig
Spring Framework 4.0.
Spring
Spring -
, . ,
, , .
, Spring
Jv-,
.
, Spring
, ,
Spring.
1. Spring 35
, ,
Spring ,
. Spring,
.
Spring -
. , , ,
, .

! ,
Spring GitHub
(http: //gi thub. ! spring-proj ects). ,
JIRA Spring (https: //j ira.
springsource.org/secure/Dashboard.j spa).
? , ,
Spring Framework, ,
Spring
.
Spring Tool Suite
Spring
Eclipse Spring Spring IDE.
SpringSource, Spring,
Spring \ Suite (STS),
www.spring.io/tools. ,
. ST S Eclipse IDE, Spring JDE,
Mylyn ( Eclipse, ), Maven for Eclipse, AspectJ
Deve\opment Too\s Eclipse
.
, Groovy,
Spring, Spring
Batch Spring fntegration, Pivotal tc Server.

! SpringSource VMWare Pivotal


Software, lnc.

, Java, Groovy/
Grails \ Suite, ,
Groovy Grails (www.spring.io/tools).
Spring Security
Spring Security (http: //proj ects.spring.io/spring-security),
Acegi Security System for Spring -
Spring. Spring Security
- .
Spring Framework
, , ,
36 1. Spring

.509 (single sign-on - SSO),


, SiteMinder. Spring Security
,
(, )
(Access Control List - ACL). - , Spring
Security -,
16.
Spring Batch Spring lntegration
, u
u .

, Sprig Spring Batch Spring lntegration. Spring
Batch
u , .
(Enterprise
lntegration Patterns - ElP) Spring lntegation
Sring- .

Spring
Spring, ,
.
Spring Boot, Spring XD, Spring for Android, Spring Moblle, Spring Social Spring
Q. - Spring Pivotal
(www.spring.io/projects).

Spring

, , Spring -
, (DI)
.
, . ,
, ,
, Sprig.
JBoss Seam Framework
( Hibernate R), Seam
Framework (www. seamframework. org)
, DI.
- (JSF), - (EJB 3) JPA
. Seam Spring ,
Seam Framework JEE. JBoss
Seam Framework JCP
JSR-299 ("Contexts and Dependency lnjection for the Java Platform" - "
Java ").
1. Spring 37
Google Guice
DI Google Guice (http: // code.
google. com/p/google-guice). Google,
Guice ,
DI .
JSR-330 ("Dependency lnjection for Java" - "
Java").
PicoContainer
PicoContainer (http: //picocontainer. ) -
DI, DI ,
PicoContainer. PicoContainer
DI, ,
, Spring;
Spring . , , -
DI, PicoContainer ,
Spring DI ,
.
JEE 7
, DI
JCP.
, JEE 7 (JSR-342), DI
.

Spring
Framework ,
, .
, Spring .,
, .
,
Sring-. , Spring Framework,
, . ,
2 Spring,
"Hello World!", 01.
2


, . ,
, , Spring.
, Spring ,
, .
, . ,
.
Spring.
JR- Spring. ,

, http: //projects. spring.io/
spring-framework .
Spring,
GitHub Spring (http://github.com/spring-proj ects/
spring-framework).
Spring. Spring ;
, ,

. Sprig ,
, .
JR-
Javadoc JR-.
Spring. - Spring Guides (),
www.spring.io/guides.

Spring.
Spring,
.
.
Spring
. .
, ,
.
40 2.

"Hello World!" Spring. ,


, ,
, - .
,
, DI, "Hetlo World!".
, ;
.
Spring Framework,
3, IoC DI Spring. ,
Spring, ,
.

Spring Framework
Spring,
. :

Spring GitHub.
, Maven Gradle,
, , -

.


Spring Framework (http: //proj ects. spring. io/
spring-framework),
,
RELEASE Spring.
.

Spring GitHub
,
,
GitHub Pivota1. Spring
Git, http: //git-scm.com/,
:
git clone git://github.com/spring-projects/spring-framework.git
README. md
.

Spring
Spring - JR-, ,
. , ,
, , .
2. 41

Spring
4.0.2.RELEASE Spring 20 ,
20 JAR. JR-
. 2.1. JR- spring
aop-4. . 2. RELEASE. j ar, . 2.1 ,
( ).
2.1. Spring
JR-
,
- () Spring.
JR- ,
Spring,
. ,
, AspectJ
aspects ,
AspectJ. , ,
Jv- Spring
AspectJ
beans ,
Spring.
Spring. , ,
L- Spring Jv-
context ,
Spring. , -
ApplicationContext Spring ( 5),
EJB, Java Naming and Directory lnterface (JNDI) Java
Management Extensions (JMX).
Spring,
(, JRuby, Groovy, BeanShell), l- Beans Validation
(JSR-303), ..
context spring
support context.
,
Velocity, FreeMarker JasperReports. ,

, CommonJ Quartz
core , Spring.
JR- ,
Spring (,
). JR-
,
Spring
expression SpEL (Spring
Expression Language - Spring)
instrurnent Spring
Java (Java Virtual Machine - JVM). JR
Spring
AspectJ
42 2.
. 2. 1
JR-
instrurnent- Spring a-
tomcat JVM Tomcat
jd.c , JDBC.
,
. ,
JDBC, JDBC, JDBC ..
jms , JMS
messaging ,
Spring lntegration,
, STOMP
orm JDBC Spring
ORM, Hibernate, JDO,
JPA iBAIS. JR
, JR- spring-jd.c,

oxm (Object/XML Mapping -
XML). ,
XML,
, Castor, JAXB, XMLBeans XStream
test , Spring
.
Spring,
.
, -
HttpServletRequest HttpServletResponse.
, Spring
JUnit,
, JUnit; ,
SpringJUnit4ClassRunner
Applicati onContext
tx ,
Spring.
, Java Transaction API (JTA)

web Spring
n,
ApplicationContext,
,

webmvc MVC
Spring.
MVC, JR- . Spring MVC
16
web-portlet Spring MVC
n
websocket Java API WebSocket (JSR-356)
2. 43

! ASM , ..
Spring.


, Maven Gradle,
.
, Spring or, -
, spring-cor e, spring-beans, spring-context
spring-aop. - Sprig,
spring-web .. ,
Maven,
.
Spring Maven
Apache Software Foundation, Maven (http: //maven. apache. org)

Jv-, ,
.
Maven ,
.
,
. Maven
,
(, Tomcat, JBoss
WebSphere).

Maven.
Maven Central, apache.org; - Maven
Central (http: //sear ch.maven.org)
.
Maven
Maven Central. (, JBoss
Spring Pivotal)
Maven. ,
Maven (Project Object Model -
) .
Maven ,
,
Maven.
Maven Spring Maven.
Maven ,
, . , log4 j
log4j, - log4j - jar.
. , 1.2.16
log4j-l. 2 .16. jar
, .
44 2.

Spring
Spring,
, ,
. Spring Framework ,
, ,
. ,
Spring
Javadoc, ,
. Spring Javadoc
, . -
; ,
, Spring .

Spring "Hello World!"


, Spring ,
, ,
. ,
- .
, Spring ,
, , .
, , ;

.
"Hello World!"
"\\
World!", 2.1 Jv-
.

2.1. "Hello World!"


package com.apress.prospring4.ch2;
puic class HelloWorld {
puic static void main (String [] args) {
System.out.println("Hello World!");

- ,
. ?
, ,
, L-,
?

, -
2. 45

, .
"Hello World!" ,
.
.

, ( 2.2).

2.2. "Hello World!"


package com.apress.prospring4.ch2;
pulic class HelloWorldWithCommandLine
puic static void main(String[] args)
if (args.length > ) {
System.out.println(args[O]);
else {
System.out.println("Hello World!");

, -
, . -
: , ,
.
. ,
; ,
.
,

. ,
,
,
.

MessageProvider getMessage (),
2.3.

2.3. MessageProvider
package com.apress.prospring4.ch2;
puic interface MessageProvider
String getMessage();

2.4 MessageRenderer ,
.
46 2.

2.4. essageRenderer
package com.apress.prospring4.ch2;
pulic interface MessageRenderer {
void render();
void setMessageProvider(MessageProvider provider);
MessageProvider getMessageProvider();

, MessageRenderer render ()
setMessageProvider () JavaBean. MessageRenderer

MessageProvider, . MessageProvider
MessageRenderer.
( 2.5).

2.5. HelloWorldessageProvider
package com.apress.prospring4.ch2;
pulic class HelloWorldessageProvider implements MessageProvider {
@Override
puic String getMessage()
return "Hello World!";

2.5 MessageProvider,
"Hello World!".
StandardOutMessageRenderer ( 2.6) .

2.6. StandardOutessageRenderer
package com.apress.prospring4.ch2;
pulic class StandardOutMessageRenderer implements MessageRenderer
private MessageProvider messageProvider;
@Override
puic void render() {
if (messageProvider == null)
throw new Runtimexception(
"You must set the property messageProvider of class:"
+ StandardOutMessageRenderer.class.getName());
// messageProvider

System.out.println(messageProvider.getMessage());

@Override
puic void setMessageProvider(MessageProvider provider)
this.messageProvider = provider;
2. 47
@Override
puic MessageProvider getMessageProvider()
return this.messageProvider;

main () ,
2.7.
2.7. "Hello World!"
package com.apress.prospring4.ch2;
puic class HelloWorldDecoupled {
puic static void main(String[] args) {
MessageRenderer mr = new StandardOutMessageRenderer();
MessageProvider mp = new HelloWorldessageProvider();
mr.setMessageProvider(mp);
mr.render();

: HelloWorldessage
Provider StandardOutMessageRenderer,
, , MessageProvider MessageRenderer.
, ,
, HelloWorldMessageProvider
StandardOutMessageRenderer .
MessageProvider MessageRenderer
MessageRenderer. render (). ,
"Hello World!".
, ,
. MessageRenderer,
MessageProvider .
, ,

( 2.8).
2.8. essageSupportFactory
package com.apress.prospring4.ch2;
import java.io.FileinputStream;
import java.util.Properties;
puic class MessageSupportFactory
private static MessageSupportFactory instance;
private Properties props;
private MessageRenderer renderer;
private MessageProvider provider;
private MessageSupportFactory()
props = new Properties();
48 2.
try {
props.load(new FileinputStream(
"com/apress/prospring4/ch2/msf.properties"));
String rendererClass = props.getProperty("renderer.class");
String providerClass = props.getProperty("provider.class");
renderer = (MessageRenderer)
Class.forName(rendererClass) .newinstance();
provider = (MessageProvider)
Class.forName(providerClass).newinstance();
catch (Exception ) (
ex.printStackTrace();

static
instance = new MessageSupportFactory();

puic static MessageSupportFactory getinstance()


return instance;

pulic MessageRenderer getMessageRenderer()


return renderer;

pulic MessageProvider getMessageProvider()


return provider;

,
, ,
.
:
renderer.class=com.apress.prospring4.ch2.StandardOutMessageRenderer
provider.class= com.apress.prospring4.ch2.HelloWorldessageProvider
main (), -
2.9.

2.9. MessageSupportFactory
package com.apress.prospring4.ch2;
puic class HelloWorldDecoupledWithFactory
pulic static void main(String[] args) (
MessageRenderer mr = MessageSupportFactory.getlnstance().
getMessageRenderer();
MessageProvider mp = MessageSupportFactory.getlnstance().
getMessageProvider();
mr.setMessageProvider(mp);
mr.render();
2. 49
Spring ,
, . "Hello World!",
, .
: .
: .
: MessageProvider
MessageRenderer.
MessageRenderer
MessageProvider. ,
.
Spring
,
, - .
,
,
. ,
MessageRenderer
MessageProvider. Spring .

MessageSupportFactory
Spring ApplicationContext.
; ,
Spring ,
, Spring. ,
ListaeBeanFactory,
, Sprig ( 2.10).
2.10. ApplicationContext Spring
package com.apress.prospring4.ch2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXrnlApplicationContext;
pulic class HelloWorldSpringDI {
pulic static void main(String[] args) {
ApplicationContext ctx = new ClassPathXrnlApplicationContext
("META-INF/spring/app-context.xml");
MessageRenderer mr = ctx.getBean( "renderer", MessageRenderer.class);
mr.render();

2. 10 , main () ClassPathXml
ApplicationContext (
META-INF / spring / app-context. xml,
), ApplicationContext,
MessageRenderer ApplicationContext. getBean ().
getBean ( ) ; ,
50 2.
( L-),
ApplicationContext Sprig
. L- (app-context. xml)
, , MessageSupportFactory
( 2.11).
2.11. Spring, XML
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="provider"
class="com.apress.prospring4.ch2.HelloWorldessageProvider"/>
<bean id="renderer"
class="com.apress.prospring4.ch2.StandardOutMessageRenderer"
p:messageProvider-ref="provider"/>
</beans>

2.11 ApplicationContext
Spring. Sprig,
beans. beans
, Spring,
( messageProvider renderer
provider) Spring, .
provider
. Spring
ApplicationContext,
.
renderer .
,
MessageProvider. Spring
01, .
p:messageProvider-ref="provider" Spring,
messageProvider .
provider.
Spring , ,
messageProvider
, provider.
, ApplicationContext main ()
MessageRenderer
getBean () ( ,
MessageRenderer) render (); Spring
MessageProvider MessageRenderer.
, - ,
Spring.
Spring
2. 51

. , .
Spring DI .
, Spring
main () . Maven,
, :
mvn clean package dependency:copy-dependencies
Spring,
Maven , spring-context. Maven
, .
dependency: copy-dependencies
dependency target.
,
MANIFEST. MF JR-.
JR- Maven,
( - ),
pom. xml. , Spring DI,
:
cd target; java -jar hello-world-4.0-SNAPSHOT.jar
,
Spring, "Hello W>rld!".

! , "Hello World",
.
, ,
, .
, ,
.

,
Spring. , Spring

GitHub. , Spring,
, .
, , JR-
Spring
. Spring,
Spring Spring,
,
Spring. , Spring
DI, "Hello World!"
.
, Spring
DI Spring. IoC DI Sprig.
3
IoC
DI Spring
2 (lnversion
of Control - [) (Dependency lnjectio - DI).
DI \,
, .
IoC DI,
, Spring
.
\ DI Spring
, DI
Sprig. Dl Spring;
Dr 4. ,
.
. \,
,
(Dependency lnjection), ,
(Dependency Lookup).
\ .
Spring. loC,
Spring, , . ,
Dependency 1njection, Spring, Setter lnjection
( ), Constructor lnjection (
) Method 1njection ( ).
Spring.
loC Spring. DI
, ,
BeanFactory.

ApplicationContext Spring,
BeanFactory
. BeanFactory ApplicationContext
.
54 3. loC 01 Spring

Spring.

ApplicationContext - XML .
Groovy Java 4.
DI, ,
BeanFactory, ,
.


IoC , , DI ,
(
)
. , ,
, IoC, .
, :
(Dependency lnjection) (Dependency Lookup).
loC.
, DI,
loC, loC, 01 (,
Dependency Lookup - IoC).


, loC,
. ,
; ,
, , loC -
; loC.
Dependency Lookup
Jv-. Dependency
Jnjection, ,
Dependency Lookup.
loC Dependency Lookup
, Dependency lnjection
loC. Dependency Lookup
: Dependency Pull ( ) Contextualized Dependency
Lookup ( ), CDL.
Dependency Injection : Constructor Dependency
Jnjection ( ) Setter Dependency lnjection
( ).

! ,
loC , ,
, .
3. loC 01 Spring 55
Dependency Pull
Jv- Dependency PuU loC.
Dependency Pull .
, EJB (2.1
), Dependency PuU (.. l- JNDI
EJB). . 3.1 Dependency Putl .

. 3. 1. JNDI

Spring Dependency Pllll


, ;
2. 3.1 Dependency Pull ,
Spring.

3.1. Dependency Pull Spring


package com.apress.prospring4.ch3;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
pulic class DependencyPull [
pulic static void main (String [] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext
("META-INF/spring/app-context.xml");
MessageRenderer mr = ctx.getBean ("renderer", MessageRenderer.class);
mr.render();

loC J- ( EJ 2.1
), JNDI
,
Spring .
56 3. loC 01 Spring

Contextualized Dependency Lookup


Contextualized Dependency Lookup (CDL)
Dependency Pull, CDL ,
, - ,
. CDL . 3.2.

. 3.2.
CDL ,
3.2.
3.2. CDL
package com.apress.prospring4.ch3;
puic interface ManagedComponent {
void performLookup(Container container);

, ,
.
(, Tomcat JBoss) (,
Spring). 3.3 Container,
Dependency Lookup.
3.3. Container
package com.apress.prospring4.ch3;
puic interface Container {
Object getDependency(String key);

,
performLookup () .
Container,
3.4.
3. loC 01 Spring 57
3.4. CDL
package com.apress.prospring4.ch3;
puic class ContextualizedDependencyLookup implements ManagedComponent
private Dependency dependency;
@Override
puic void performLookup(Container container)
this.dependency = (Dependency) container.getDependency("myDependency");

@Override
puic String toString()
return dependency.toString();

3.4 , Dependency - .

Constructor Dependency lnjection


Costructor Dependency lnjection ,
( ).
,
, IoC
( 3.5).

3.5.
package com.apress.prospring4.ch3;
puic class Constructorinjection {
private Dependency dependency;
puic Constructorinjection(Dependency dependency)
this.dependency = dependency;

@Override
pulic String toString()
return dependency.toString();

Setter Dependency lnjection


Setter Dependency lnjection IoC
JavaBean.
, IoC . 3.6
, Setter Dependency lnjection.
58 3. loC 01 Spring

3.6.
package com.apress.prospring4.ch3;
puic class Setterinjection {
private Dependency dependency;
puic void setDependency(Dependency dependency)
this.dependency = dependency;
@Override
puic String toString() {
return dependency.toString();

,
setDependency (), JavaBean - dependency.
Setter Injection
, loC.


IoC - -
. loC
. , EJ 2.1
IoC ( JNDI), EJB
J.
Spring loC .

! Spring EJB
. Spring
loC ,
.

: ,
- ? : .
3.4 3.5, ,
. ,
Dependency Pull
, CDL
.
, , -
, .

loC,
,
, .
.
,

.
3. loC DI Spring 59
! Dependency lnjection
Spring 13.

,
, . ,
,

.
,
, , .
,
ID-. ,
,
- . ,
, ,
;
. ,
. ,
, .
3.4:
pulic void performLookup(Container container) {
this.dependency = (Dependency) container.getDependency("myDependency");

, :
, null
. , ..
,
. Dependency Lookup
, ,
-
.
Setter lnjection Constructor lnjection
, , IoC ,
- Setter lnjection
Constructor Injection. Constructor lnjection ,

. , Spring,
, ,
Setter lnjection, Constructor Injection
. ,
Constructor lnjection .
Setter lnjection .
,
, Setter lnjection.
Setter Injection ,
60 3. loC DI Spring

, ,
. , -
- defineMeaningOfLife ().
,
setEncyclopedia (), u
. ,
setEncyclopedia () -.
, -.
loC, Spring,
-, -
. .
-, 3.7.
3.7. Oracle
package corn.apress.prospring4.ch3;
pulic interface Oracle {
String defineMeaningOfLife();

, - -
Dependency lnjection. ,
3.8.
3.8. Oracle

package corn.apress.prospring4.ch3;
puic class BookworrnOracle irnplernents Oracle
private Encyclopedia encyclopedia;
puic void setEncyclopedia(Encyclopedia encyclopedia)
this.encyclopedia = encyclopedia;

@Override
puic String defineMeaningOfLife()
return "Encyclopedias are waste of rnoney - use the Internet";

, BookwormOracle Oracle,
Dependency lnjection. Spring
,
-.
- Setter
lnjection,
.
,
, u
-
-.
3. loC DI Spring 61


-,
, Setter lnjection
.
. , ,

, . ,
-, 3.9.
3.9. NewsletterSender
package com.apress.prospring4.ch3;
pulic interface NewsletterSender {
void setSmtpServer(String smtpServer);
String getSmtpServer();
void setFromAddress(String fromAddress);
String getFromAddress();
void send() ;

NewsletterSender ,
. -
send (),
JavaBean. , ,
-? ,
- S- ,
- ;
,
NewsletterSender. :
?
, ,
, ,
.
. Newsletter
Sender, 3.9, S-
.
- ;
.
MessageRenderer 2 MessageProvider
- ,
MessageRenderer .
- , .
,
,
. , S- - ,
NewsletterSender, MessageProvider -
,
MessageRenderer.
62 3. loC DI Spring


.
, -
. Java ,
( -), String
. , , .
, String
, ;
: , int
, String - S
, .
,
-, ,
- .
, NewsletterSender , ,
S- .
, ,
-,
l-, ,
.

! , 2
.
.


,
. JMX Spring.
, Setter lnjection ,
.
,
.
, ,

. ,
,
. ,
,
,
.

Spring
, - ,
Spring. Spring Dependency Injection,
3. loC 01 Spring 63
Depedency Lookup. Spring
,
Dependency I njection. , Spring,
Dependency Injection
,
. Dependency lnjection Spring . 3.3
( Dependency Lookup . 3.2).


BeanFactory

Spring

. 3.3. Spring

Dependency lnjection
,
Dependency Lookup. Spring
Dependency
lnjection,
Dependency Lookup. , Jv-
Spring main ()
( ApplicationContext) .
- V Spring
. ,
Dependency lnjection Spring,
; Dependency
Lookup. ,
, .
loC Spring
Dependency lnjection
Dependency Lookup.
.
Spring Constructor lnjection Setter lnjection,
loC
.
01 Spring
.

Spring
Dependency lnjection Spring ,
4, loC,
.
Dependency Injection Spring, Setter Injection, Constructor I njection
Method lnjectio,
Dependency lnjection Spring.
64 3. loC DI Spring


Dependency lnjection Spring
BeanFactory.
, . Spring
, .
JavaBean,
,
Constmctor lnjection.
DI, DI Spring
BeanFactory.
, BeanFactory,
r .
, ,
BeanFactory .
(, -
ApplicationContext -
ContextLoaderListener,
Spring, web. xml).
. ,
, BeanFactory.
BeanFactory ,
, -
.
, BeanDefinition.
, ,
. BeanFactory,
BeanDefinitionReader, BeanDefinition
PropertiesBeanDefinitionReader,
XmlBeanDefinitionReader. PropertiesBeanDefinitionReader
, XmlBeanDefinitionReader - L
.
, BeanFactory,
, .
( )
. , , ,
(
). .
BeanFactory,
(.. ), .
BeanFactory
BeanFactory ,
. .
, ,
. 3.10 3.11
.
3. loC DI Spring 65
3.1. Oracle
package com.apress.prospring4.ch3;
puic interface Oracle {
String defineMeaningOfLife();

3.11. Oracle
package com.apress.prospring4.ch3;
pulic class BookwormOracle implements Oracle
@Override
puic String defineMeaningOfLife() {
return "Encyclopedias are waste of money - use the Internet";

, Jv-
BeanFactory oracle ( 3.12).
3.12. BeanFactory
package com.apress.prospring4.ch3;
import org.springframework.beans.factory.support.DefaultListaleBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
puic class XmlConfigWithBeanFactory {
puic static void main (String [] args) {
DefaultListaleBeanFactory factory = new DefaultListaleBeanFactory();
XmlBeanDefinitionReader rdr = new XmlBeanDefinitionReader(factory);
rdr.loadBeanDefinitions(new
ClassPathResource("META-INF/spring/xml-bean-factory-config.xml"));
Oracle oracle = (Oracle) factory.getBean("oracle");
System.out.println(oracle.defineMeaningOfLife());

3.12 Defaul tListaeBeanFactory -


BeanFactory, Spring -
BeanDef inition L-
XmlBeanDefinitionReader. , BeanFactory
, Oracle, oracle,
L- . 3.13 L
BeanFactory (xml-bean-factory-config. xml).
66 3. loC DI Spring

3.13. L- Spring
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="oracle" name="wiseworm" class="com.apress.prospring4.ch3.
BookwormOracle"/>
</beans>

! SD- Spring
. Spring SD-
, spring.schemas.
spring-beans,
.
Spring.

Spring,
oracle wiseworm,
. apress. prospring4. h. BookwormOracle.
; .
, 3.12,
, defineMeaningOfLife ().
XmlBeanDefinitionReader Spring
PropertiesBeanDefinitionReader,
, XML.
, ,
.
L-
.
, BeanFactory,
, ;
, BeanFactory,
, BeanFactory.
, - ,
, ,
Defaul tListaeBeanFactory, BeanFactory.
Applica tionCon text
ApplicationContext Spring
BeanFactory. DI ApplicationContext
, ,
(il8n), ..
, Spring,
Spring ApplicationContext.
ApplicationContext Spring
3. loC DI Spring 67

( )
- ContextLoaderListener. ,
ApplicationContext.

ApplicationContext
IoC 01,
BeanFactory Spring,
Sring-.

Sring-. ,
ApplicationContext,
, BeanFactory.
Spring
ApplicationContext,
,
Spring.
Spring
, L-. JDK 5 Spring
Jv- Spring ( Spring 2.5)
ApplicationContext Java.
- L ?
, (
Spring http: / /forum. spring. io).
,
, . L-
Jv-,
DI . Spring
ApplicationContext.

(, , ,
JMS JMX) L-, DI (
) - . , ,
,
.

.
,
XML .
r
L
, Spring, .
3.14 ,
beans Spring.
app-context-xml. xml XML.
68 3. loC 01 Spring

3.14. L- Spring
<?xml version= "l.0" encoding="UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi= "http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

beans Spring
, .
context ApplicationContext, tx
.
.
Spring r
XML ,
3.15. app-context-annotation.xml
XML .

3.15. L- Spring
<?xml version= "l.0" encoding= "UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.apress.prospring4.ch3.annotation" />
</beans>

<context: component-scan> Spring


,
@Component, @Controller, @Repository @Service,
@Autowired @Inj ect ( ero r
). <context: component-scan>
, , .
,
. ,
3.16.

3.16. L- Spring
<?xml version= "l.O" encoding="UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
3. loC DI Spring 69
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.apress.prospring4.ch3.annotation" >
<context:exclude-filter type="assignae"
expression="com.example.NotAService"/>
</context:component-scan>
</beans>

Spring
, , ,
( , ).
.
(type) annotation, regex, assignae,
aspectj custom ( ,
org. springframework. core. type. fil ter. TypeFil ter).
(expression) .

Spring
, -
, Spring,
Spring , ,
. 2, MessageRender
MessageProvider
, . 3.17
.
3.17. MessageRenderer essageProvider
package com.apress.prospring4.ch3;
puic interface MessageRenderer {
void render ();
void setMessageProvider(MessageProvider provider);
MessageProvider getMessageProvider();

package com.apress.prospring4.ch3;
import com.apress.prospring4.ch3.MessageProvider;
import com.apress.prospring4.ch3.MessageRenderer;
puic class StandardOutMessageRenderer implements MessageRenderer {
private MessageProvider messageProvider;
@Override
puic void render() {
if (messageProvider == null)
throw new RuntimeException(
"You must set the property messageProvider of class:"
+ StandardOutMessageRenderer.class.getName());
// messageProvider
70 3. loC DI Spring
System.out.println(messageProvider.getMessage());

@Override
puic void setMessageProvider(MessageProvider provider)
this.messageProvider = provider;

@Override
puic MessageProvider getMessageProvider()
return this.messageProvider;

package com.apress.prospring4.ch3;
puic interface MessageProvider
String getMessage();

package com.apress.prospring4.ch3.xml;
import com.apress.prospring4.ch3.MessageProvider;
puic class HelloWorldessageProvider implements MessageProvider
@Override
pulic String getMessage()
return "Hello World ! ";

L- app-context
xml. xml (. 3.14) <bean>,
3.18.

3.18. Spring ( XML)


<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="messageRenderer"
class= "com.apress.prospring4.ch3.xml.StandardOutMessageRenderer"/>
<bean id="messageProvider"
class="com.apress.prospring4.ch3.xml.HelloWorldMessageProvider"/>
</beans>

, 3.18,
- messageProvider
HelloWorldessageProvider, messageRenderer
StandardOutMessageRenderer.
Spring L-
(app-context-annotation. xml) ;

. apress .prospring4. h. annotation ( 3.19).
3. loC DI Spring 71

3.19. Spring ( )
package com.apress.prospring4.ch3.annotation;
import org.springframework.stereotype.Service;
irnport corn.apress.prospring4.ch3.MessageRenderer;
@Service("rnessageRenderer")
puic class StandardOutMessageRenderer irnplernents MessageRenderer
private MessageProvider rnessageProvider;
@Override
puic void render() {
if (rnessageProvider == null)
throw new RuntirneException(
"You rnust set the property rnessageProvider of class:"
+ StandardOutMessageRenderer.class.getName());
// rnessageProvider

Systern.out.println(rnessageProvider.getMessage());

@Override
puic void setMessageProvider(MessageProvider provider)
this.rnessageProvider = provider;

@Override
puic MessageProvider getMessageProvider()
return this.rnessageProvider;

package corn.apress.prospring4.ch3.annotation;
irnport org.springfrarnework.stereotype.Service;
irnport corn.apress.prospring4.ch3.MessageProvider;
@Service("rnessageProvider")
pulic class HelloWorldessageProvider irnplernents MessageProvider
@Override
puic String getMessage()
return "Hello World!";
})

@Service
, , ;
.
ApplicationContext L-, 3.15,
Spring
.

ApplicationContext. 3.20
.
72 3. loC DI Spring

3.20. Spring ()
package com.apress.prospring4.ch3;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class DeclareSpringComponents {
puic static void main(String [] args) (
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:app-context-xml.xml");
ctx.refresh();
MessageProvider messageProvider = ctx.getBean("messageProvider",
MessageProvider.class);
System.out.println(messageProvider.getMessage());

Defaul tListaeBeanFact ory GenericXml


ApplicationContext. GenericXmlApplicationContext
ApplicationContext
ApplicationContext , L-.

app-context-xml. xml app-context-annotation. xml, ,
- "Hello World!".
3.21 (app-context-xml. xml) 3.22 (app-context-annotation. xml)
XML
, .
3.21. XML (app-context-xml. xml)
<?xrnl version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="messageProvider"
class="com.apress.prospring4.ch3.xml.HelloWorldMessageProvider"/>
</beans>

3.22. (app-context-annotation. xml)


<?xrnl version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan
base-package="com.apress.prospring4.ch3.annotation"/>
</beans>
3. loC 01 Spring 73


Setter 1njection XML
<property> <bean> <property>,
. ,
messageProvider messageRend erer,
<bean> messageRenderer,
3.23.

3.23. ( XML)
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="messageRenderer"
class="com.apress.prospring4.ch3.xml.StandardOutMessageRenderer">
<property name="messageProvider" ref= "messageProvider"/>
</bean>
<bean id= "messageProvider"
class= "com.apress.prospring4.ch3.xml.HelloWorldessageProvider"/>
</beans>

messageProvider messageProvider.
ref (
).
Spring 2.5 L-
, ,
3.24.

3.24.
( XML)
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="messageRenderer"
class="com.apress.prospring4.ch3.xml.StandardOutMessageRenderer"
p:messageProvider-ref="messageProvider"/>
<bean id="messageProvider"
class="com.apress.prospring4.ch3.xml.HelloWorldessageProvider"/>
</beans>


.
74 3. loC DI Spring

! XSD
Spring; , schemaLocation XSD .

.
@Autowired , 3.25.
3.25. ( )
package com.apress.prospring4.ch3.annotation;
import org.springframework.stereotype.Service;
import com.apress.prospring4.ch3.MessageRenderer;
import com.apress.prospring4.ch3.MessageProvider;
@Service("messageRenderer")
puic class StandardOutMessageRenderer implements MessageRenderer {
private MessageProvider messageProvider;
@Override
puic void render() {
if (messageProvider == null)
throw new RuntimeException(
"You must set the property messageProvider of class:"
+ StandardOutMessageRenderer.class.getName());
// messageProvider

System.out.println(messageProvider.getMessage());

@Override
@Autowired
puic void setMessageProvider(MessageProvider provider)
this.messageProvider = provider;

@Override
pulic MessageProvider getMessageProvider()
return this.messageProvider;

<context: component-scan> L-
ApplicationContext Spring
@Autowired .

! @Autowired
@Resource (name ="messageProvider"). @Resource
JSR-250, Jv-
JSE JEE. @Autowired, @Resource
name 01. , Spring
@Inj ect,
JSR-299 ("Contexts and Dependency lnjection for the Java Platform" - "
Java "). @Inject
@Autowired Spring.
3. loC 01 Spring 75

,
3.26.
3.26. ()
package com.apress.prospring4.ch3;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class DeclareSpringComponents {
puic static void main (String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:ETA-INF/spring/app-context-xml.xml");
ctx.refresh();
MessageRenderer messageRenderer = ctx.getBean( "messageRenderer",
MessageRenderer.class);
messageRenderer.render();

, app-context-xml. xml app-context-annotation. xml


;
- "Hello World!".


MessageProvider, HelloWorldMessage
Provider,
getMessage (). Spring
MessageProvider,
( 3.27).
3.27. ConfiguraleessageProvider ( XML)
package com.apress.prospring4.ch3.xml;
import com.apress.prospring4.ch3.MessageProvider;
pulic class ConfiguraeMessageProvider implements MessageProvider
private String message;
puic ConfiguraeMessageProvider(String message)
this.message = message;

@Override
puic String getMessage()
return message;

, ConfiguraeMessageProvider,
, ( null}.
, ,
Constructor lnjection. 3.28 ,
76 3. loC DI Spring

messageProvider ConfiguraeMessageProvider,
Constructor lnjection.

3.28. ( XML)
<?xml version= "l. " encoding="UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi= "http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="messageProvider"
class= "com.apress.prospring4.ch3.xml.ConfiguraleMessageProvider">
<constructor-arg value="Configurae message"/>
</bean>
</beans>

<proper ty>
<constructor-arg>. ,
String,
value ref.

<constructor-arg>
index , ,
. , ,
index,
Spring .
Spring 3.1
, :
<?xml version= "l. " encoding="UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:c= "http://www.springframework.org/schema/c"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="messageProvider"
class= "com.apress.prospring4.ch3.xml.ConfiguraleMessageProvider"
c:message= "This is configurae message"/>
</beans>

! XSD
Spring; , schemaLocation XSD .

Constructor Injection
@Autowired ( 3.29),
Setter lnjection,
3.24.
3. loC 01 Spring 77

3.29. ( )
package com.apress.prospring4.ch3.annotation;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.annotation.Autowired;
import com.apress.prospring4.ch3.MessageProvider;
@Service("messageProvider")
puic class ConfiguraleMessageProvider implements MessageProvider
private String message;

@Autowired
puic ConfiguraleMessageProvider (@Value( "Configurale message")
String message) {
this.message = message;

@Override
puic String getMessage()
return this.message;

3.29 , @Value,
, . Spring
. SpEL
( ).
, ..
. 01
, ,
. ,
Spring ( 3.30).
3.30. Spring
( )
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan
base-package="com.apress.prospring4.ch3.annotation"/>
<bean id="message" class= "java.lang.String"
: O="This is configurae message"/>
</beans>
78 3. loC 01 Spring

3.30 rnessage
java.lang.String. ,
Constructor Injection ,
r .
, @Va l ue
, 3.31.
3.31. @Value
( )
package com.apress.prospring4.ch3.annotation;
package com.apress.prospring4.ch3.annotation;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import com.apress.prospring4.ch3.MessageProvider;
@Service("messageProvider")
puic class ConfiguraeMessageProvider implements MessageProvider
private String message;
@Autowired
pulic ConfiguraleMessageProvider(String message)
this.message = message;

@Override
pulic String getMessage()
return this.message;

rnessage
_r , Spring
. ,
3.32, r XML (app-context-xrnl. xrnl)
(app-context-annotation. xrnl), r
r :
This is configurae message

3.32. s ()
package com.apress.prospring4.ch3;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class DeclareSpringComponents {
pulic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
MessageProvider messageProvider = ctx.getBean("messageProvider",
MessageProvider.class);
System.out.println(messageProvider.getMessage());
3. loC 01 Spring 79
Spring ,
Constructor lnjection. ,
r,
. 3.33.

3.33.
package com.apress.prospring4.ch3.xml;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class ConstructorConfusion {
private String someValue;
puic ConstructorConfusion(String someValue) {
System.out.println("ConstructorConfusion(String) called");
this.someValue = someValue;

puic ConstructorConfusion(int someValue) {


System.out.println("ConstructorConfusion(int) called");
this.someValue = "Numer: " + Integer.toString(someValue);

puic static void main(String[] args) {


GenericXmlApplicationContext ctx =
new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
ConstructorConfusion =
(ConstructorConfusion) ctx.getBean("constructorConfusion");
System.out.println(cc);

puic String toString() {


return someValue; Constructor Injection:constructor confusion

, -
ConstructorConfusion ApplicationContext
. 3.34 (app-context-xml. xrnl).

3.34. ( app-context-xml. xml)


<?xml version= "l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="messageProvider"
class= "com.apress.prospring4.ch3.xml.ConfiguraleMessageProvider"
c:message= "This is configurae message"/>
<bean id="constructorConfusion"
class="com.apress.prospring4.ch3.xml.ConstructorConfusion">
80 . loC 01 Spring
<constructor-arg>
<value>90</value>
</constructor-arg>
</bean>
</beans>

?
:
ConstructorConfusion(String) called
90
, String.
, , Constructor
lnjection, Numer:,
int, , .
, ,
3.35 (app-context-xrnl. xrnl).
3.35.
<?xrnl version="l. " encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="messageProvider"
class="com.apress.prospring4.ch3.xrnl.ConfiguraeMessageProvider"
:message="This is configurae message"/>
<bean id="constructorConfusion"
class="com.apress.prospring4.ch3.xml.ConstructorConfusion">
<constructor-arg type="int">
<value>90</value>
</constructor-arg>
</bean>
</beans>

, <constructor-arg>
type, ,
Spring. :
ConstructorConfusion(int) called
Number: 90

,
, 3.36.
3.36. ( )
package com.apress.prospring4.ch3.annotation;
import org.springframework.stereotype.Service;
3. loC DI Spring 81
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.support.GenericXmlApplicationContext;
@Service("constructorConfusion")
puic class ConstructorConfusion {
private String someValue;
puic ConstructorConfusion(String someValue) {
System.out.println("ConstructorConfusion(String) called");
this.someValue = someValue;

@Autowired
puic ConstructorConfusion(@Value(" 90") int someValue) {
System.out.println("ConstructorConfusion(int) called");
this.someValue = "Numer: " + Integer.toString(someValue);

puic static void main(String [] args) {


GenericXmlApplicationContext ctx =
new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
ConstructorConfusion =
(ConstructorConfusion) ctx.getBean("constructorConfusion");
System.out.println(cc);

puic String toString()


return someValue;

@Autowired
Spring
. ,
.

! @Autowired
.
Spring
ApplicationContext.


,
Setter lnjection Constructor lnjection.
Spring ,
,
Java, .
Setter lnjection Constructor
lnjection
<property> <constructor-args>.
82 3. loC DI Spring


.
, <value>.
<value> String,
. 3.37
, ,
.

3.37. ( XML)
package com.apress.prospring4.ch3.xml;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class InjectSimple
private String name;
private int age;
private float height;
private boolean programmer;
private Long ageinSeconds;
puic static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
InjectSimple simple = (InjectSimple)ctx.getBean("injectSimple");
System.out.println(simple);

puic void setAgeinSeconds(Long ageinSeconds)


this.ageinSeconds = ageinSeconds;

puic void setProgrammer(boolean programmer)


this.programmer = programmer;

puic void setAge(int age)


this.age = age;

puic void setHeight(float height) {


this.height = height;

puic void setName(String name)


this.name = name;

puic String toString()


return "Name :" + name + "\n"
+ "Age:" + age + "\n"
+ "Age in Seconds: " + ageinSeconds + "\n"
+ "Height: " + height + "\n"
+ "Is Programmer?: "+ programmer;
3. loC DI Spring 83

InjectSimple main (),


ApplicationContext InjectSimple
Spring.
. 3.38 (app-context-xml. xml)
.
3.38.
<?xml version="l.O" encoding= "UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi= "http://www.w3.org/2001/XLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="injectSimple" class= "com.apress.prospring4.ch3.xml.
InjectSimple"
p:name="Chris Schaefer" p:age="32" p:height= "l.778"
p:programmer= "true"
p:ageinSeconds="l009843200"/>
</beans>

3.37 3.38 , ,
String,
,
<value>. ,
:
Name: Chris Schaefer
Age: 32
Age in Seconds: 1009843200
Height: 1.778
Is Programmer?: true

@Value .
,
3.39. ( Spring ,
.)
3.39. { )
package com.apress.prospring4.ch3.annotation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.support.GenericXrnlApplicationContext;
import org.springframework.stereotype.Service;
@Service("injectSimple")
pulic class InjectSimple {
@Value("Chris Schaefer")
private String name;
@Value("32")
private int age;
84 3. loC DI Spring
@Value( 11 1.778 11 )

private float height;


@Value( 11 true 11 )

private boolean programmer;


@Value( 11 1009843200 11 )

private Long ageinSeconds;


puic static void main(String[] args) {
GenericXmlApplicationContext ctx =
new GenericXmlApplicationContext();
ctx.load( 1 classpath:META-INF/spring/app-context-annotation.xml 11
1 );

ctx.refresh();
InjectSimple simple = (InjectSimple) ctx.getBean( 11 injectSimple 11 );

System.out.println(simple);

puic String toString() {


return 11 Name: 11 + name + "\n 11
+ "Age: 11 + age + 11 \n 11
+ 11 Age in Seconds: 1 + ageinSeconds 11 \ 11
1 + n
+ 1 Height: 11 + height + 11 \n 11
1

+ 11 Is Programmer?: 1 + programmer;
1

,
XML.
SpEL
Spring 3 -
Spring (Spring Expression Language - SpEL). SpEL
ApplicationContext.
Spring.
, SpEL ,
.
, ,
Spring, ( 3.40).

3.40. SpEL ( XML)


package com.apress.prospring4.ch3.xml;
puic class InjectSimpleConfig {
private String name = 11 Chris Schaefer 11 ;

private int age = 32;


private float height = 1.778f;
private boolean programmer = true;
private Long ageinSeconds = 1009843200L;
puic String getName ()
return name;
3. loC 01 Spring 85
puic void setName(String name) {
this.name = name;

puic int getAge()


return age;

puic void setAge(int age)


this.age = age;

pulic float getHeight()


return height;

puic void setHeight(float height)


this.height = height;

pulic boolean isProgrammer()


return programmer;

puic void setisProgrammer(boolean programmer)


this.programmer = programmer;

puic Long getAgeinSeconds()


return ageinSeconds;

pulic void setAgeinSeconds(Long ageinSeconds)


this.ageinSeconds = ageinSeconds;

L- SpEL
, 3.41 (app-context-xml. xml).
3.41. SpEL ( XML)
<?xml version= "l.O" encoding="UTF-8"?>
<beans xmlns ="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="injectSimpleConfig"
class= "com.apress.prospring4.ch3.xml.InjectSimpleConfig"/>
<bean id="injectSimpleSpel"
class= "com.apress.prospring4.ch3.xml.InjectSimpleSpel"
p:name= "#{injectSimpleConfig.name}"
p:age="#{injectSimpleConfig.age}"
p:height="#{injectSimpleConfig.height}"
p:programmer="#{injectSimpleConfig.programmer}"
p:ageinSeconds= "#{injectSimpleConfig.ageinSeconds}"/>
</beans>
86 3. loC DI Spring

SL- # { injectSimple
Config. name} . (age)
I ,
SpEL .
, 3.42.

3.42. SpEL
package com.apress.prospring4.ch3.xrnl;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class InjectSimpleSpel
private String name;
private int age;
private float height;
private boolean programmer;
private Long ageinSeconds;
pulic String getName()
return this.name;

puic void setName(String name)


this.name = name;

puic int getAge()


return this.age;

puic void setAge(int age)


this.age = age;

puic float getHeight()


return this.height;

puic void setHeight(float height)


this.height = height;
})
puic boolean isProgrammer()
return this.programmer;

puic void setProgrammer(boolean programmer)


this.programmer = programmer;

pulic Long getAgeinSeconds()


return this.ageinSeconds;

puic void setAgeinSeconds(Long ageinSeconds)


this.ageinSeconds = ageinSeconds;

pulic String toString() {


return "Name: " + name + "\n"
3. loC DI Spring 87
+ "Age: " + age + "\n"
+ "Age in Seconds: " + ageinSeconds + "\n"
+ "Height: " + height + "\n"
+ "Is Programmer?: " + programmer;

puic static void main(String[] args) {


GenericXmlApplicationContext ctx =
new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
InjectSimpleSpel simple =
(InjectSimpleSpel)ctx.getBean("injectSimpleSpel");
System.out.println(simple);

:
Name: Chris Schaefer
Age:33
Age in Seconds: 1009843200
Height: 1.778
Is Programmer?: true

@Value SpEL ( 3.43).

3.43. SpEL ( )
package com.apress.prospring4.ch3.annotation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.stereotype.Service;
@Service("injectSimpleSpel")
puic class InjectSimpleSpel {
@Value("#{injectSimpleConfig.name}")
private String name;
@Value("#{injectSimpleConfig.age + 1}")
private int age;
@Value("#{injectSimpleConfig.height}")
private float height;
@Value("#{injectSimpleConfig.programmer}")
private boolean programmer;
@Value("#{injectSimpleConfig.ageinSeconds}")
private Long ageinSeconds;
puic String toString() {
return "Name: " + name + "\n"
+ "Age: " + age + "\n"
+ "Age in Seconds: " + ageinSeconds + "\n"
+ "Height: " + height + "\n"
+ "Is Programmer?: " + programmer;
88 3. loC DI Spring
pulic static void main(String [] args) {
GenericXmlApplicationContext ctx =
new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
InjectSimpleSpel simple =
(InjectSimpleSpel)ctx.getBean("injectSimpleSpel");
System.out.println(simple);

3.44 InjectSimpleConfig,
.

3.44. InjectSimpleConfig ( )
package com.apress.prospring4.ch3.annotation;
import org.springframework.stereotype.Component;
@Component("injectSimpleConfig")
pulic class InjectSimpleConfig {
private String name = "John Smith";
private int age = 35;
private float height = 1.78f;
private boolean programmer = true;
private Long ageinSeconds = 11037600001;

3.44 @Service
@Component. @Component ,
@Service. Spring ,

, , .
InjectSimpleConfig ,
-, @Component .
@Service @Component,
, -
.
.
SpEL Spring
, Spring
.
XML
,
<ref>. 3.45 , ,
.
3. loC DI Spring 89
3.45.
package com.apress.prospring4.ch3.xml;
import org.springframework.context.support.GenericXmlApplicationContext;
import com.apress.prospring4.ch3.0racle;
import com.apress.prospring4.ch3.Bookworm0racle;
puic class InjectRef {
private Oracle oracle;
puic void setOracle(Oracle oracle)
this.oracle = oracle;

puic static void main(String [] args) {


GenericXmlApplicationContext ctx =
new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
InjectRef injectRef = (InjectRef) ctx.getBean("injectRef");
System.out.println(injectRef);

puic String toString() {


return oracle.defineMeaningOfLife();

Spring ,
:
. , ,
<ref> . 3.46
(app-context-xml. xml).

3.46.
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="oracle"
name="wiseworm" class="com.apress.prospring4.ch3.Bookworm0racle"/>
<bean id="injectRef" class="com.apress.prospring4.ch3.xml.InjectRef">
<property name="oracle">
<ref local="oracle"/>
</property>
</bean>
</beans>

3.46 :
Encyclopedias are waste of money - use the Internet
90 3. loC 01 Spring

:
, ;
. ,
,
. ,
, .
InjectRef setOracle (),
Oracle, ,
BookwormOracle - , Oracle.
,
. ,
Java, , Java,
, .
(id) ,
, local <ref>.
" ",
.
local , <ref>
. ,
L- .
L
, local <ref>
bean. 3.47
,
.
3.47.
<?xml version="l.0" encoding= "UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation ="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="oracle" name="wiseworm" class= "com.apress.prospring4.ch3.
BookwormOracle"/>
<bean id="injectRef" class="com.apress.prospring4.ch3.xml.InjectRef">
<property name="oracle">
<ref bean="wiseworm"/>
</property>
</bean>
</beans>

oracle name ,
inj ectRef
bean <ref>.
- .
Inj ectRef ( 3.45) , .
3. loC 01 Spring 91

ApplicationContextpyr

ApplicationContext (, , BeanFactory),
, . , Spring
ApplicationContext, (
BeanFactory)
. ApplicationContext, Spring
-
, .
ApplicationContext Spring
, ,
. ApplicationContext
GenericXmlApplicationContext .
GenericXmlApplicationContext ,
setParent () ApplicationContext,
3.48.
3.48. GenericXmlApplicationContext
package com.apress.prospring4.ch3;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class HierarchicalAppContextUsage {
puic static void main(String [] args) {
GenericXmlApplicationContext parent =
new GenericXmlApplicationContext();
parent.load("classpath:META-INF/spring/parent.xml");
parent.refresh();
GenericXmlApplicationContext child =
new GenericXmlApplicationContext();
child.load("classpath:META-INF/spring/app-context-xml.xml");
child.setParent(parent);
child.refresh();
SimpleTarget targetl = (SimpleTarget) child.getBean("targetl");
SimpleTarget target2 = (SimpleTarget) child.getBean("target2");
SimpleTarget target = (SimpleTarget) child.getBean("target");
System.out.println(targetl.getVal());
System.out.println(target2.getVal());
System.out.println(target.getVal());

3.49 SimpleTarget.
3.49. SimpleTarget
package com.apress.prospring4.ch3;
puic class SimpleTarget
private String val;
92 3. loC DI Spring

pulic void setVal(String val)


this.val = val;

pulic String getVal()


return val;

r ApplicationContext
- ApplicationContext
ApplicationContext,
ApplicationContext r
. r bean
<ref> r parent. 3.50
BeanFactory (parent. xrnl).

3.50. ApplicationContext
<?xml version= "l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:c= "http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="injectBean" class= "java.lang.String" : O= "Bean In Parent"/>
<bean id="injectBeanParent" class= "java.lang.String" : O="Bean In Parent"/>
</beans>

, : inj ectBean
inj ectBeanParent. String Bean In
Parent ( ). 3.51
ApplicationContext (app-context-xml. xml).

3.51. ApplicationContext
<?xml version= "l.0" encoding= "UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi= "http://www.w.org/2001/XLSchema-instance"
xmlns:c= "http://www.springframework.org/schema/c"
xmlns:p= "http://www.springframework.org/schema/p"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="targetl" class= "com.apress.prospring4.ch3.SimpleTarget"
p:val-ref="injectBeanParent"/>
<bean id="target2" class= "com.apress.prospring4.ch3.SimpleTarget"
p:val-ref="injectBean"/>
<bean id="target" class="com.apress.prospring4.ch3.SimpleTarget">
<property name="val">
3. loC DI Spring 93
<ref parent="injectBean"/>
</property>
</bean>
<bean id="injectBean" class="java.lang.String" : O="Child In Bean"/>
</beans>

, . injectBean
injectBean
String,
ApplicationContext ( Bean In Chil_d).
targetl val-ref <bean>
inj ectBeanParent.
BeanFactory, targetl .
. : bean
, ApplicationContext.
,
.
local
ApplicationContext. XML ,
, ,
local,
.
target2 val-ref <bean>
i n j e c t B e a n .
ApplicationContext, target2 injectBean
ApplicationContext.
target <ref>
injectBean ApplicationContext. target
parent <ref>, injectBean,
ApplicationContext, .

! , targetl target2, target


.
, ,
property, .
, - -
, property, (
).

, Hierarchical
AppContextUsage ( 3.48):
Bean In Parent
Bean In Child
Bean In Parent
, targetl target
ApplicationContext, target2 -
ApplicationContext.
94 3. loC DI Spring


,
. , , Spring
. :
<list>, <map>, <set> <props>
List, , Set Properties
, . <props>
String, Properties
String. <list>, <map> <set>
,
. List , Set
List, , Set,
, , List! 3.52 ,
.
3.52. ( XML)
package com.apress.prospring4.ch3.xml;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class Collectioninjection {
private Map<String, Object> map;
private Properties props;
private Set set;
private List list;
puic static void main(String[J args) {
GenericXmlApplicationContext ctx =
new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
Collectioninjection instance =
(Collectioninjection) ctx.getBean("injectCollection");
instance.displayinfo();

puic void setList(List list)


this.list = list;

puic void setSet(Set set)


this.set = set;

puic void setMap(Map <String, Object> map) {


this.map = map;

puic void setProps(Properties props)


this.props = props;
3. loC DI Spring 95
puic void displayinfo() {
System.out.println("Map contents:\n");
for (Map.Entry<String, Object> entry: map.entrySet())
System.out.println("Key: " + entry.getKey() + " - Value: "
+ entry.getValue());

System.out.println("\nProperties contents:\n");)
for (Map.Entry<Object, Object> entry: props.entrySet())
System.out.println("Key: " + entry.getKey() + " - Value: "
+ entry.getValue());

System.out.println("\nSet contents:\n");
for (Object obj: set) {
System.out.println("Value: " + obj);

System.out.println("\nList contents:\n");
for (Object obj: list) {
System.out.println("Value: " + obj);

, .
main () Collectioninjection Spring
displayinfo (). ,
Properties, Set List, Spring. 3.53
,
Collection!njection.
3.53. ( XML)
<?xml version= "l.O" encoding="OTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id= "oracle" name= "wiseworm"
class="com.apress.prospring4.ch3.xml.Bookworm0racle"/>
<bean id= "injectCollection"
class="com.apress.prospring4.ch3.xml.Collectioninjection">
<property name="map">
<map>
<entry key="someValue">
<value>Hello World!</value>
</entry>
<entry key="someBean">
<ref local="oracle"/>
</entry>
</map>
</property>
96 3. loC DI Spring

<property name="props">
<props>
<prop key="firstName">Chris</prop>
<prop key="secondName">Schaefer</prop>
</props>
</property>
<property name="set">
<set>
<value>Hello World 1 </value>
<ref local="oracle"/>
</set>
</property>
<property name="list">
<list>)
<value>Hello World!</value>
<ref local="oracle"/>
</list>
</property>
</bean>
</beans>

Map<String, Object>. JDK 5


Spring
Collection, L-
(app-context-xml. xml).
,
Collectioninjection. map
<map>.
<entry>, String .
, ;
<value>
<ref> String .
props <props>, java. util.
Properties <prop>. ,
<prop> <entry>,
String ,
Properties.
, <list> <set>, :
,
<value> <ref>,
. 3.52 List Set String
.
, 3.52.
, ,
.
contents:
: someValue - Value: Hello World!
: someBean - Value: com.apress.prospring4.ch3.xml.
Bookworm0racle@a4f787b
3. loC DI Spring 97
Properties contents:
: secondName - Value: Schaefer
: firstName - Value: Chris
Set contents: )
Value: Hello World!
Value: com.apress.prospring4.ch3.xml.Bookworm0racle@a4f787b
List contents:
Value: Hello World!
Value: com.apress.prospring4.ch3.xml.Bookworm0racle@a4f787b
, <list>, <map> <set>
, ,
, .
,
;
.


. ,
,
.

, . ,
, -
FTP, (Secure
Protocol - SCP). Spring,
, 3.54.
3.54. ArtworkSender
package com.apress.prospring4.ch3;
puic interface ArtworkSender {
void sendArtwork(String artworkPath, Recipient recipient};
String getFriendlyName(};
String getShortName(};

3.54 Recipient .
ArtworkSender ,
3.55.
3.55. FtpArtworkSender
package com.apress.prospring4.ch3;
puic class FtpArtworkSender implements ArtworkSender
@Override
puic void sendArtwork(String artworkPath, Recipient recipient}
/ / FTP...
98 3. loC DI Spring
@Override
puic String getFriendlyName()
return "File Transfer Protocol";

@Override
puic String getShortName()
return "ftp";

, ArtworkManager,
ArtworkSender.
, List ArtworkManager.
,
getFriendlyName ()
.
,
ArtworkSender. ArtworkManager
.
L-
.
. 3.56
Spring, ,
(app-context-annotation. xml).
3.56. ( )
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:context= "http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<context:annotation-config/>
<context:component-scan
base-package="com.apress.prospring4.ch3.annotation"/>
<util:map id="map" map-class="java.util.HashMap">
<entry key="someValue">
<value>Hello World!</value>
</entry>
<entry key="someBean">
<ref bean="oracle"/>
</entry>
</util:map>)
3. loC DI Spring 99
<util:properties id="props">
<prop key="firstName">Chris</prop>
<prop key="secondName">Schaefer</prop>
</util:properties>

<util: set id="set">


<value>Hello World!</value>
<ref bean="oracle"/>
</util: set>

<util:list id="list">
<value>Hello World!</value>
<ref bean="oracle"/>
</util:list>
</beans>

BookworrnOracle .
3.57.
3.57. BookwormOracle
package com.apress.prospring4.ch3.annotation;
import org.springframework.stereotype.Service;
import com.apress.prospring4.ch3.0racle;
@Service("oracle"}
puic class BookwormOracle implements Oracle
@Override
puic String defineMeaningOfLife(} {
return "Encyclopedias are waste of money - use the Internet";

r 3.56 util,
Spring, , .
Spring
.
@Resource JSR-250 ( 3.58).
3.58. @Resource
package com.apress.prospring4.ch3.annotation;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.springframework.stereotype.Service;
import org.springframework.context.support.GenericXmlApplicationContext;
import javax.annotation.Resource;
@Service ( "injectCollection")
100 3. loC DI Spring
puic class Collectioninjection {
@Resource(name="map")
private Map<String, Object> map;
@Resource(name="props")
private Properties props;
@Resource(name="set")
private Set set;
@Resource(name= "list")
private List list;
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
Collectioninjection instance =
(Collectioninjection) ctx.getBean("injectCollection");
instance.displayinfo();

puic void displayinfo() {


System.out.println("Map contents:\n");
for (Map.Entry<String, Object> entry: map.entrySet())
System.out.println("Key: "+ entry.getKey() +" - Value: "
+ entry.getValue());

System.out.println("\nProperties contents:\n");
for (Map.Entry<Object, Object> entry: props.entrySet())
System.out.println("Key: "+ entry.getKey() +" - Value: "
+ entry.getValue());

System.out.println("\nSet contents:\n");
for (Object obj: set) {
System.out.println("Value: "+ obj); ";

System.out.println("\nList contents:\n");
for (Object obj: list) {
System.out.println("Value: "+ obj);

, ,
L-.

! , @Au tow i red


@Resource. , @Autowired ,
, ,
, .
, , List<Oracle>
@Autowired, Spring Oracle
ApplicationContext ( <util: list>,
),
, Spring Oracle.
Spring
, , @Resource.
3. loC DI Spring 101


Spring
n 01,
(Method lnjection). Method lnjection
- Lookup Method Injection ( )
Method Replacement ( ). Lookup Method lnjection
,
. Method Replacement
,
. Spring
-, CGLIB.
Lookup Method lnjection
Lookup Method lnjection Spring 1.1
, , ,
- , (sigleton)
. Setter lnjection Constructor
lnjection ,
, . ,

.
, LockOpener
. LockOpener
KeyHelper, LockOpener.
KeyHelper ,
. ,
openLock (), KeyHelper.
LockOpener . KeyHelper

KeyHelper ( , Sprig
).
KeyHelper openLock () ,
Lookup Method lnjection.
,
ApplicationContextAware ( ).
, ApplicationContext,
, .
Lookup Method lnjection ,
,
, ,
Sprig .
Lookup Method lnjection
, .

, Spring
. -
102 3. loC 01 Spring
. ,
Method lnjection ,
, , Spring.
, .
,
.
, "" Setter lnjection,
Method Injection. 3.59
MyHelper, .
3.59. yHelper
package com.apress.prospring4.ch3;
puic class MyHelper {
puic void doSomethingHelpful()
// - .

,
. 3.60 DemoBean,
.
3.60. DemoBean
package com.apress.prospring4.ch3;
puic interface DemoBean {
MyHelper getMyHelper();
void someOperation();

DemoBean : getMyHelper () someOperation ().


getMyHelper ()
MyHelper, -
. someOperation () - ,
MyHelper.
3.61 StandardLookupDemoBean,
Setter Injection MyHelper.
3.61. StandardLookupDemoBean
package com.apress.prospring4.ch3;
pulic class StandardLookupDemoBean implements DemoBean
private MyHelper myHelper;
pulic void setMyHelper(MyHelper myHelper)
this.myHelper = myHelper;

@Override
puic MyHelper getMyHelper()
return this.myHelper;
3. loC 01 Spring 103
@Override
puic void someOperation()
myHelper.doSomethingHelpful();

, ,
someOperation ()
MyHelper. 3.62 AstractLookupDemoBean,
Method lnjection MyHelper.
3.62. AstractLookupDemoBean
package com.apress.prospring4.ch3;
puic abstract class AstractLookupDemoBean implements DemoBean {
puic abstract MyHelper getMyHelper();
@Override
puic void someOperation() {
getMyHelper() .doSomethingHelpful();

getMyHelper () ,
someOperation () MyHelper. 3.63
, (app-context-xml. xml).
3.63.
<?xml version="l. " encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="helper"
class="com.apress.prospring4.ch3.MyHelper" scope="prototype"/>

<bean id="abstractLookupBean"
class="com.apress.prospring4.ch3.AstractLookupDemoBean">
<lookup-method name="getMyHelper" bean ="helper"/>
</bean>

<bean id="standardLookupBean"
class="com.apress.prospring4.ch3.StandardLookupDemoBean">
<property name="myHelper">
<ref bean="helper"/>
</property>
</bean>
</beans>

standardLookupBean
. abstractLookupBean
104 3. loC DI Spring

<lookup-method>. name
<lookup-method> Spring ,
. ,
, .
MyHelper - .
bean Spring, .
3.64.
3.64. LookupDemo
package com.apress.prospring4.ch3;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.util.StopWatch;
puic class LookupDemo {
puic static void main(String [ J args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
DemoBean abstractBean = (DemoBean) ctx.getBean("abstractLookupBean");
DemoBean standardBean = (DemoBean) ctx.getBean("standardLookupBean");
displayinfo(standardBean);
displayinfo(abstractBean);

puic static void displayinfo(DemoBean bean)


MyHelper helperl = bean.getMyHelper();
MyHelper helper2 = bean.getMyHelper();
System.out.println("Helper Instances the Same?: "
+ (helperl == helper2));
StopWatch stopWatch = new StopWatch();
stopWatch.start("lookupDemo");
for (int = ; < 100000; ++) {
MyHelper helper = bean.getMyHelper();
helper.doSomethingHelpful();

stopWatch.stop();
System.out.println("100000 gets took "
+ stopWatch. getTotalTimeMillis() + " ms");

abstractLookupBean (

Lookup Method Injection, Spring CG LI
AbstractLookupDemoBean,
) standardLookupBean GenericXMLApplicationContext,
displayinfo ().
displayinfo () MyHelper -
3. loC 01 Spring 105
getMyHelper () .
, stdout ,
, .
abstractLookupBean MyHelper
getMyHelper (), .
standardLookupBean MyHelper
Setter lnjection,
getMyHelper (), .

! StopWatch, ,
, Spring. ,
.

displayinfo ()
, . ,
standardLookupBean ,
, .
LookupDemo ( 3.64) -
:
Helper Instances the Same?: true
100000 gets took 8 rns
Helper Instances the Sarne?: false
100000 gets took 1039 rns
, , ,
standardLookupBean
abstractLookupBean. ,
.

(Lookup Method Injection)
, ,
. Lookup Method
I njection, ,
. 3.64
Lookup Method Injection
DI
. , Lookup Method Injection
,
.
, ,
.
, , ,

.
Setter Injection, Lookup Method Injection
.
106 3. loC DI Spring

Lookup Method lnjection


,
. .
,
displayinfo () . ,
-
, JoC. ,
.
, r ,
.
Method Replacement
Spring (Method Replacement)
, ,
.
. Method Replacement,
,
. ,
, .
,
, - Method Replacement
.

. CGLIB
, , ,
MethodReplacer.
3.65 ,
formatMessage ().
3.65. ReplacementTarget
package com.apress.prospring4.ch3;
puic class ReplacementTarget {
puic String formatMessage(String msg)
return "<hl>" + msg + "</hl>";

puic String formatMessage(Object msg)


return "<hl>" + msg + "</hl>";

Method Replacement, Spring,


ReplacementTarget.
, formatMessage (String),
.
,
MethodReplacer ( 3.66).
3. loC DI Spring 107
3.66. MethodReplacer
package com.apress.prospring4.ch3;
import java.lang.reflect.Method;
import org.springframework.beans.factory.support.MethodReplacer;
puic class FormatMessageReplacer implements MethodReplacer {
@Override
pulic Object reimplement(Object argO, Method method, Object[] args)
throws Throwae {
if (isFormatMessageMethod(method))
String msg = (String) args[O];
return "<h2>" + msg + "</h2>";
else {
throw new IllegalArgumentException("Unae to reimplement method "
+ method.getName());

private boolean isFormatMessageMethod(Method method)


if (method.getParameterTypes().length != l) {
return false;

if (! ("formatMessage".equals(method.getName())))
return false;

if (method.getReturnType{) != String.class) {
return false;

if (method.getParameterTypes() [] != String.class) {
return false;

return true;

MethodReplacer reimplement (},


. : ,
, Method,
, r, . reimplement (}
, ,
.
3.66 FormatMessageReplacer ,
formatMessage (String}; ,
( <h2> </h2>)
.
,
MethodReplacer .
,
MethodReplacer .
108 3. loC DI Spring

3.67 Appl icat ionContext,


Replaceme ntTarget -
formatMessage (String), (app-context-xml. xml).

3.67.
<?xml version="l.0" encoding= "UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi= "http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="methodReplacer"
class= "com.apress.prospring4.ch3.FormatMessageReplacer"/>

<bean id= "replacementTarget"


class= "com.apress.prospring4.ch3.ReplacementTarget">
<replaced-method name= "formatMessage" replacer= "methodReplacer">
<arg-type>String</arg-type>
</replaced-method>
</bean>

<bean id="standardTarget"
class= "com.apress.prospring4.ch3.ReplacementTarget"/>
</beans>

, MethodReplacer Application
Context. <replaced-method>
formatMessage (String) replacementTargetBean.
name <replaced-method>
, replacer - MethodReplacer,
. ,
ReplacementTarget, <arg-type>
. <arg-type>
, String java. lang.String
java.lang.StringBuffer.
3.68 ,
standardTarget replacementTarget Appl icationContext,
formatMessage (String)
, , .

3.68.
package com.apress.prospring4.ch3;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.util.StopWatch;
puic class MethodReplacementExample {
pulic static void main (String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
3. loC DI Spring 109
ctx.load("classpath:META-INF/spring/app-context-xrnl.xrnl");
ctx.refresh();
ReplacernentTarget replacernentTarget = (ReplacernentTarget) ctx
.getBean( "replacernentTarget");
ReplacernentTarget standardTarget = (ReplacernentTarget) ctx
.getBean("standardTarget");
displayinfo(replacernentTarget);
displayinfo(standardTarget);

private static void displayinfo(ReplacernentTarget target)


Systern.out.println(target.forrnatMessage("Hello World!"));
StopWatch stopWatch = new StopWatch();
stopWatch.start("perfTest");
for (int = ; < 1000000; ++) {
String out = target.forrnatMessage{"foo");

stopWatch.stop();
Systern.out.println("lOOOOOO invocations took: "
+ stopWatch.getTotalTirneMillis() + " rns");

,
- . :
<h2>Hello World!</h2>
1000000 invocations took: 396 rns
<hl>Hello World 1 </hl>
1000000 invocations took: 18 rns
, replacementTarget ,
, MethodReplacer.
,
, , .
MethodReplacer
, ,
CGLIB.

,

, . ,
- Java,
-.
,
MethodReplacer
.
MethodReplacer
; String
11 3. loC 01 Spring

, .
, , MethodReplacer
,
. ,
MethodReplacer ,
Dependency lnjection.

Spring ,

. , , ,
ApplicationContext.
Sprig
. <bean> id,
. r id , Spring name,
, , name. (
, name ;
.) id,
name, Spring ,
, , .
id name
, Spring ( org. springframework.
beans. factory. NoSuchBeanDefini tionException)
ApplicationContext. 3.69
, .
3.69.
<bean id="stringl" class="java.lang.String"/>
<bean name="string2" class="java.lang.String"/>
<bean class="java.lang.String"/>

,
? ,
, .
,
. ,
Spring ,
. , , id name,
id .
Spring 3.1 id XML (.. xsd: I D),
, .
Spring 3.1, id xsd: String,
. ,
Spring id
ApplicationContext.
id ,
, .
3. loC 01 Spring 111


Spring .
name <bean> ,
, .
id .
Spring, name
<alias>. 3.70
<bean>,
(app-context-xml. xml).
3. 70.
<?xrnl version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="namel" name="name2 name3,name4;name5" class="java.lang.String"/>
<alias name="namel" alias="name"/>
</beans>

, .
id name ,
(
; ).

. <alias>.
3.71 Jv-,
ApplicationContext ,
.
3.71.
package com.apress.prospring4.ch3.xml;
import org.springframework.context.support.GenericXrnlApplicationContext;
puic class BeanNameAliasing {
puic static void main(String [] args) {
GenericXrnlApplicationContext ctx = new GenericXrnlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xrnl");
ctx.refresh();
String sl = (String) ctx.getBean("namel");
String s2 = (String) ctx.getBean("name2");
String s = (String) ctx.getBean("name");
String s4 = (String) ctx.getBean("name4");
String s5 = (String) ctx.getBean("nameS");
String s = (String) ctx.getBean("name");
System.out.println((sl s2));
System.out.println((s2 == s));
112 3. loC 01 Spring
System.out.println((s == s4));
System.out.println((s4 == s5));
System.out.println((s5 == s));

, 3.70,
true , , ,
, .

ApplicationContext. getAliases (String)
. String
, .
,
.
, , ,
.

, .
: , 50
, Spring,
Foo. 25 StandardFoo
standardFoo, 25 - SuperFoo superFoo.

25 SuperFoo. , .
- standardFoo
SuperFoo. ,
SuperFoo, . ,
_r, , .
- 25
, standardFoo superFoo.
: ,
, ,
.
- ( )
standardFoo standardFoo
superFoo.
.


Spring . , Spring
,
ApplicationContext. getBean ()
. ,
3.71,
== , eguals ().
3. loC DI Spring 113

(singleton) Java 11
: , ,
Singleton.
, - Singleton.
Design Patterns:
Elements / Reusa!e Object Oriented Software . (Addison-Wesley, 1995 r.).
,
Singleton.
Java 3.72.
3. 72. Singleton
package com.apress.prospring4.ch3;
pulic class Singleton {
private static Singleton instance;
static {
instance = new Singleton();

pulic static Singleton getlnstance()


return instance;

,
,
.
Singleton, ,
.
Singleton . ,
,
. , , ,
. Singleton
,
, Singleton,
Singleton .
, ..
Singleton .
, Spring
, Singleton.
Spring Singleton,
Spring .
, Spring
; -
getBean () .
- ,
, Spring
. .
114 3. loC 01 Spring

, - ,
, rr ,
, .

! ,
,
Spring. 4.


, 3.73 (app-context-xml. xml).
3.73.
<?xrnl version=11 l.011 encoding=1 1 UTF-8 11 ?>
<beans xrnlns=11 http://www.springframework.org/schema/beans 11
xrnlns:xsi=11 http://www.w3.org/2001/XMLSchema-instance 11
xrnlns:c=11http://www.springframework.org/schema/c 11
xsi:schemaLocation= 11http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd 11 >
<bean id= 11 nonSingleton 11 class=11 java.lang.String 11 scope=11prototype 11
: 0=11 Chris Schaefer 11 />
</beans>

,
, , scope (
) prototype (). Spring
scope singleton ().
Spring ,
. 3.74 ,
.
3.74.
package com.apress.prospring4.ch3;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class NonSingleton {
puic static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load( 11 classpath:META-INF/spring/app-context-xrnl.xrnl 11);
ctx.refresh();

String sl (String) ctx.getBean( 11 nonSingleton 11 );


String s2 (String) ctx.getBean( 11 nonSingleton 11 );

System.out.println( 11 Identity Equal?: 11 + (sl ==s2));


System.out.println( 11 Value Equal:? 11 + sl.equals(s2));
System.out.println(sl);
System.out.println(s2);
3. loC DI Spring 115

:
Identity Equal?: false
Value Equal:? true
Chris Schaefer
Chris Schaefer
, String ,
, ,
.

,
.
.
.
. ,
, .
, , ,
,
- .
.
, ,
. -
,
.
.
, ,
.
.
.
, ,
,
,
.
,
.
,
,

.
.
.
, ,

.
116 3. loC DI Spring

.
, ,
.
, .
,
Spring,
,
. , ,
,
.


Spring, ,
.
ApplicationContext.
, Spring 4.
. .
Spring loC.
. Spring ,
.
. -. -
Spring V,
-
.
. -. -
Spring MVC,
-
.
. -,
.
Spring
MVC.
. Sprig ,
,
. ,
.
. ,
org. springframework.beans. factory. config.
Scope Spring (
L org. springframework.beans. factory. config.
CustomScopeConfigurer).
3. loC 01 Spring 117


Spring
,
. Spring ,
,
. Spring ,
, , -
. ,
.
, Spring ,
. , beanA
beanB
getBean () . , beanA
beanB ctx. getBean ( "beanB") Spring
. Spring ,
beanA beanB, beanA
beanB. Spring
depends-on
<bean>. 3.75 ,
beanA beanB.

. 75.
<bean id="beanA" class="com.apress.prospring4.ch3.BeanA" depends-on="beanB"/>
<bean id="beanB" class="com.apress.prospring4.ch3.BeanB"/>

, beanA
beanB. Spring
n
beanA.
;
Setter Injection Constructor
ljection. Spring ,
,
Spring Framework.



, .
, Spring
.
. , autowire
.
118 3. loC DI Spring


Spring : byName,
, constructor, default no ( ;
). byName, Spring
, . ,
foo ApplicationContext
foo, foo foo .
Spring
ApplicationContext.
, String
ApplicationContext String, Spring
String String . ApplicationContext
String, Spring ,
, ( org. springframework.
beans. factory. NoSuchBeanDefinitionException).
constructor
, ,
. Spring
. ,
, String, -
String Integer, ApplicationContext
String Integer, Spring .
default Spring
constructor .
( ), Spring , -
constructor.
3. 76 ,

(app-context-xml. xml).
3. 76.
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w.org/2001/XLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="foo" class="com.apress.prospring4.ch3.Foo"/>
<bean id="barl" class="com.apress.prospring4.ch3.Bar"/>
<bean id="targetByName" autowire="byName"
class="com.apress.prospring4.ch3.xml.Target"
lazy-init="true"/>
<bean id="targetByType" autowire="byType"
class="com.apress.prospring4.ch3.xml.Target"
lazy-init="true"/>
<bean id="targetConstructor" autowire= "constructor"
class="com.apress.prospring4.ch3.xml.Target" lazy-init="true"/>
</beans>
3. loC DI Spring 119

. Foo Bar -
. , Target
autowire. , lazy-init true,
Spring
, ,
. 3.77
Jv-, Target
ApplicationContext.

3.77.
package com.apress.prospring4.ch3.xml;
import org.springframework.context.support.GenericXmlApplicationContext;
import com.apress.prospring4.ch3.Foo;
import com.apress.prospring4.ch3.Bar;
puic class Target {
private Foo foo;
private Foo foo2;
private Bar bar;
pulic Target()
}

puic Target(Foo foo) {


System.out.println("Target(Foo) called");

pulic Target( Foo foo, Bar bar) {


System.out.println("Target(Foo, Bar) called");

puic void setFoo(Foo foo) {


this.foo = foo;
System.out.println("Property foo set");

puic void setFoo2(Foo foo) {


this.foo2 = foo;
System.out.println("Property foo2 set");

pulic void setBar(Bar bar) {


this.bar = bar;
System.out.println("Property bar set");

puic static void main( String [] args) {


GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
Target t = null;
System.out.println("Using byName:\n");
t = (Target) ctx.getBean("targetByName");
120 3. loC DI Spring

System.out.println("\nUsing byType:\n");
t = (Target) ctx.getBean("targetByType");

System.out.println("\nUsing constructor:\n");
t = (Target) ctx. getBean("targetConstructor");

Target : ,
, Foo, ,
Foo Bar. Target
, Foo Bar.
. main ()
Target, ApplicationContext,
. ,
:
Using byName:
Property foo set
Using :
Property bar set
Property foo set
Property foo2 set
Using constructor:
Target(Foo, Bar) called
, Spring byName,
foo, ..
.
Spring . foo foo2
foo, bar - barl.
constructor Spring ,

.


,
, .
,
. byName
,
,
. Spring , ,
, Spring , .
, ,
ApplicationContext -
, , -
3. loC DI Spring 121

, .
constructor.
,
,

1 ,
.
.



.
,
.

,
. , Sprig <bean>,
r
ApplicationContext.
, ,

. 3.78 ,
(app-context-xml. xml).
3. 78.
<?xml version="l." encoding="UTE'-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="inheritParent" class="com.apress.prospring4.ch3.xml.SimpleBean"
p:name="Chris Schaefer" p:age="32"/>
<bean id="inheritChild" class="com.apress.prospring4.ch3.xml.SimpleBean"
parent="inheritParent" :g=""/>
</beans>

<bean> inheritChild
parent, , Spring
inheritParent .

ApplicationContext, <bean>, ,
abstract="true". inheritChild
age, Spring .
inheritChild name, Spring
, inheritParent. 3.79
SimpleBean, .
122 3. loC 01 Spring

. 79. SimpleBean
package com.apress.prospring4.ch3.xml;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class SimpleBean
private String name;
private int age;

pulic static void main(String[] args) {


GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();

SimpleBean parent = (SimpleBean) ctx.getBean("inheritParent");


SimpleBean child = (SimpleBean) ctx.getBean("inheritChild");

System.out.println("Parent: \n" + parent);


System.out.println ("Child: \n" + child);

puic void setName(String name)


this.name = name;

pulic void setAge(int age) {


this.age = age;

pulic String toString() {


return "Name: " + name + "\n" + "Age: " + age;

, rnain () SirnpleBean inheritChild


inheritParent ApplicationContext
stdout. ,
:
Parent:
Name: Chris Schaefer
Age: 32
Child:
Name: Chris Schaefer
Age: 33
inheritChild inheritParent
narne,
age.

,
.
.

3. loC DI Spring 123

JI
;
.
,
Java. ,
, .
, .
,
.

, Spring
IoC. IoC

. , loC Ji Spring,
, , .
loC BeanFactory,
loC Spring, ApplicationContext,
BeanFactory .
ApplicationContext
GenericXmlApplicationContext,
Spring L.
01 JI ApplicationContext - Jv
.
IoC
Spring, Setter lnjection, Constructor Injection, Method Injection,
.
,
, XML ,
GenericXmlApplicationContext.
Spring
Spring loC.
IoC , Spring,
, Spring.
4

Spring
(lnversion
of Control - loC) , Spring
Framework. , ,
Spring. Spring ,
loC.
. , .
. ,
,
Spring. ,
,
Spring .
, Spring,
, Spring ,
JavaBean,
JSR-250.
" Spring".
,
ApplicationContext. Spring
, BeanNameAware ApplicationContextAware,

ApplicationContext, .

.
. FactoryBean
, .
FactoryBean ,
BeanFactory Spring.
JavaBean.
PropertyEditor - ,
j ava. beans. ( PropertyEditor)
String.
126 4. Spring

Spring ,
, BeanFactory,
. ,
Spring, , .
.
ApplicationContext.
, ApplicationContext - BeanFactory,
.
ApplicationContext
, ,
.
, loC,
ApplicationContext. ,
ApplicationContext Spring
-.
Jv- r. 3.0 Spring
XML
. 3.0, Spring
ApplicationContext
Jv-.
Sring-.
r. ,
, ,
..
,
.
Groovy r. Spring 4.0
Groovy,

L Java.

Spring
, ,
Spring,
loC. [
, , ,
Spring.
loC ,
, Spring.
, ,
IoC,
, Spring.
Spring,
.
4. Spring 127

.
,
loC; .
,
" " ,
.
. ,
IoC,
- , , ,
. Expert --: J2EE Development without EJB
(Wrox, 2004 .) ;
.

Spring Framework,
. ,
,
- . ,
IoC Spring, , Java.
Jv- Spring
. Spring ,
JEE,
JEE. Spring
-, ,
, ,
JEE. Spring,
, ,
,
, Spring.


JoC, Spring,
,
.
.
:
.
Spring , Spring
,
.
, Spring
.
Spring . ,
Sprig,
, ,
,
, , .
128 4. Spring

Spring ,

: ,
.
, , ,
, , Spring
, .
, , Spring
ApplicationContext ,
, ,
. , ,
JSR-250 , Spring
.
.
, ,
Spring, Spring
, . ,
,
, ,
Spring. ,
, , ,
, .
, Spring ,

, . ,
, ,
, ,
L
. JSR-250 -
, .. , JCP,
, Spring. , loC,
, JSR-250.
,
, .

, , ,
. ,
loC JSR-250, ,
.
,
, , ,
.
- Spring,
,
,
, .
4. Spring 129
. 4.1 , Spring
.


Spring :

11
1

11
11

L-,
BeanNameAware, @PostConstruct, @PreDestroy.
Jv- -
r
setBeanName()
11

i i

i

i

BeanClassLoaderAware,
InitializingBean, DisposaeBean,

afterPropertiesSet() destroy()

i !
setBeanClassLoader()


i

i

ApplicationContextAware. init-method destroy-method
( L- <bean>). ( L- <bean>),
setApplicationContext()

. 4. 1 . Spring


, ,
, . Spring
,
" ", -

. , ,
, ,
, .
,

.
,
Spring .
, Spring

.

; , ,
, . -
130 4. Spring

,
.
, ,
-
, .

! ,
Spring
Quartz.
11.

, r
,

Spring.
,
, Spring.
,
Spring ,
.

ini t-method <bean> . 4.1
.
4.1. SimpleBean
package com.apress.prospring4.ch4;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class SimpleBean
private static final String DEFAULT_NAE = "Luke Skywalker";
private String name;
private int age = Integer.MIN_VALUE;
puic void setName(String name) {
this.name = name;

pulic void setAge(int age)


this. age = age;

puic void init()


System.out.println("Initializing bean"); //
if (name == null) {
System.out.println("Using default name");
//
name = DEFAULT N;
4. Spring 131

if (age == Integer.MIN_VALUE) {
throw new IllegalArgumentException(
" must set the age property of any beans of type "
// age
+ SimpleBean.class);

puic String toString() {


return "Name: " + name + "\nAge: " + age;

puic static void main(String[J args) {


GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
SimpleBean simpleBeanl = getBean("simpleBeanl", ctx);
SimpleBean simpleBean2 = getBean("simpleBean2", ctx);
SimpleBean simpleBean = getBean("simpleBean", ctx);

private static SimpleBean getBean(String beanName, ApplicationContext ctx)


{
try {
SimpleBean bean = (SimpleBean) ctx.getBean(beanName);
System.out.println(bean);
return bean;
catch (BeanCreationException )
System.out.println("An error occured in bean configuration: "
+ ex.getMessage()); //
return null;

, ini t () ,
. init () ,
name, , ,
DEFAULT_NAE. , ,
age, IllegalArgurnentException,
.
main () SimpleBean
GenericXmlApplicationContext, SimpleBean,
getBean () . ,
getBean () .
init () , , age
, Sprig BeanCreationException. getBean ()
,
, null.
4.2 ApplicationContext,
, 4.1 (app-context-xml. xml).
132 4. Spring

4.2. SimpleBean
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p= "http://www.springframework.org/schema/p"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
default-lazy-init= "true">
<bean id="simpleBeanl"
class="com.apress.prospring4.ch4.SimpleBean"
init-method="init" p:name= "Chris Schaefer" p:age="32"/>
<bean id="simpleBean2"
class="com.apress.prospring4.ch4.SimpleBean"
init-method= "init" p:age= "32"/>
<bean id="simpleBean3"
class= "com.apress.prospring4.ch4.SimpleBean"
init-method="init" p:name= "Chris Schaefer"/>
</beans>

, <bean>
init-method, Spring,
ini t (), . simpleBeanl
name age, init ()
. simpleBean2
name, , init (). name
. , simpleBean age.
, init () , ,
IllegalArgumentException. ,
<beans> default-lazy-init = "true",
Spring , ,
, .
, Spring
ApplicationContext
simpleBean. :
Initializing bean
Name: Chris Schaefer
Age: 32
Initializing bean
Using default name
Name: Luke Skywalker
Age: 32
An error occured in bean configuration: Error creating bean with name
'simpleBean3' defined in class path resource [META-INF/spring/
app-context-xml.xml]: Invocation of init method failed; nested exception
is java.lang.IllegalArgumentException: You must set the age property of
any beans of type class com.apress.prospring4.ch4.SimpleBean
:
simpleBean, [META-INF/spring/
- tex t-xml.xml] : ini t;
java. lang. IllegalArgumentException:
age .apress.prospring4. ch4. SimpleBean
4. Spring 133
, simpleBeanl
, r .
simpleBean2 name ,
. ,
simpleBean , .. init () -
age.
,
.
loC, ,
.
, .
, Sprig,
, .
,
,
.
,
,

. ,
Spring, , ,
,
,
. , ,
,
.
Ini tializingBean
InitializingBean, Spring,
, ,
, Spring .
,
, .
InitializingBean afterPropertiesSet (),
, init () 4.1. 4.3
,
InitializingBean.
4.3. Ini tializingBean
package com.apress.prospring4.ch4;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class SimpleBeanWithinterface implements InitializingBean
private static final String DEFAULT N = "Luke Skywalker";
134 4. Spring

private String name;


private int age = Integer.MIN_VALUE;
puic void setName(String name)
this.name = name;

pulic void setAge(int age)


this.age = age;

puic void myinit()


System.out.println("My Init");

@Override
puic void afterPropertiesSet() throws Exception
System.out. println("Initializing bean");
if (name == null) {
System.out.println("Using default name");
name = DEFAULT N;

if (age == Integer.MIN_VALUE)
throw new IllegalArgumentException(
11
You must set the age property of any beans of type " +
SimpleBeanWithinterface.class);

puic String toString()


return 11 Name: + name +
11 11 \nAge: " + age;

pulic static void main( String [] args) {


GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load( 11 classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
SimpleBeanWithinterface simpleBeanl = getBean("simpleBeanl", ctx);
SimpleBeanWithinterface simpleBean2 = getBean("simpleBean2 11 ctx);
,

SimpleBeanWithinterface simpleBean = getBean("simpleBean", ctx);

private static SimpleBeanWithinterface getBean(String beanName,


ApplicationContext ctx) {
try {
SimpleBeanWithinterface bean =
(SimpleBeanWithinterface) ctx.getBean(beanName);
System.out.println(bean);
return bean;
catch (BeanCreationException )
System.out.println( An error occured in bean configuration: "
11

+ ex.getMessage());
return null;
4. Sprig 135
, .
, ,
InitializingBean,
InitializingBean. afterPropertiesSet (). 4.4
(app-context-xml. xml).

4.4.
Ini tializingean
<?xml version="l. " encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
default-lazy-init="true">
<bean id="simpleBeanl"
class="com.apress.prospring4.ch4.Simple8eanWithinterface"
p:name="Chris Schaefer" p:age="32"/>
<bean id="simpleBean2"
class="com.apress.prospring4.ch4.SimpleBeanWithinterface"
p:age="32"/>
<bean id="simple8ean3"
class="com.apress.prospring4.ch4.SimpleBeanWithinterface"
p:name="Chris Schaefer"/>
</beans>

4.4 4.2 .
ini t-method.
SimpleBeanWithlnterface InitializingBean,
Spring ,
, .
, :
Initializing bean
Name: Chris Schaefer
Age: 32
Initializing bean
Using default name
Name: Luke Skywalker
Age: 32
An error occured in bean configuration: Error creating bean with name
'simple8ean3' defined in class path resource [META-INF/spring/app
context-xml.xml]: Invocation of init method failed; nested exception is
java.lang.IllegalArgumentException: You must set the age property of any
beans of type class com.apress.prospring4.ch4.SimpleBeanWithinterface
:
simpleBean, [META-INF/
spring/app-context-xml.xml]: init;
java. lang. IllegalArgumentException:
age com.apress.prospring4.ch4.
SimpleBeanWithinterface
136 4. Spring

@PostConstruct JSR-250
, ,
@PostConstruct,
JSR-250. Spring 2.5,
JSR-250 , Spring ,
, ,
. 4.5 ,
@PostConstruct.
4.5. @PostConstruct
package com.apress.prospring4.ch4;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class SimpleBeanWithJSR250 {
private static final String DEFAULT_NAE = "Luke Skywalker";
private String name;
private int age = Integer.MIN_VALUE;
puic void setName(String name)
this.name = name;

pulic void setAge(int age)


this.age = age;

@PostConstruct
pulic void init() throws Exception {
System.out.println("Initializing bean");
if (name == null) {
System.out.println("Using default name");
name = DEFAULT N;

if (age == Integer.MIN_VALUE)
throw new IllegalArgumentException(
" must set the age property of any beans of type " +
SimpleBeanWithJSR250.class);

puic String toString() {


return "Name: " + name + "\nAge: " + age;

puic static void main(String[] args) {


GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh ();
SimpleBeanWithJSR250 simpleBeanl = getBean("simpleBeanl", ctx);
SimpleBeanWithJSR250 simpleBean2 = getBean("simpleBean2", ctx);
SimpleBeanWithJSR250 simpleBean = getBean("simpleBean", ctx);
4. Spring 137
private static SimpleBeanWithJSR250
getBean(String beanName, ApplicationContext ctx) {
try {
SimpleBeanWithJSR250 bean =
(SimpleBeanWithJSR250) ctx.getBean(beanName);
System.out.println(bean);
return bean;
catch (BeanCreationException )
System.out.println("An error occured in bean configuration: "
+ ex.getMessage());
return null;

, init-method;
init () @PostConstruct.
, .
, ,
<context: annotation-config>
context:
<?xml version= "l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
default-lazy-init="true">
<context:annotation-config/>
<bean id="simpleBeanl"
class="com.apress.prospring4.ch4.SimpleBeanWithJSR250"
p:name="Chris Schaefer" p:age="32"/>
<bean id="simpleBean2"
class="com.apress.prospring4.ch4.SimpleBeanWithJSR250"
p:age="32"/>
<bean id="simpleBean"
class="com.apress.prospring4.ch4.SimpleBeanWithJSR250"
p:name="Chris Schaefer"/>
</beans>
, , -
:
Initializing bean
Name: Chris Schaefer
Age: 32
Initializing bean
Using default name
138 4. Spring

Narne: Luke Skywalker


Age: 32
Initializing bean
An error occured in bean configuration: Error creating bean with narne
'sirnpleBean': Invocation of init rnethod failed; nested exception is
java.lang.IllegalArgurnentException: You rnust set the age property of any
beans of type class corn.apress.prospring4.ch4.SirnpleBeanWithJSR250
:
simpleBean: ini t;
java.lang.IllegalArgumentException: age
com.apress.prospring4.ch4.SimpleBeanWithJSR250
.
,
Spring,
, .
InitializingBean
,
Spring. ,
, loC JSR-250.

. ,
;
InitializingBean,

- .

.
Spring , @PostConstruct,
InitializingBean. afterPropertiesSet () ,,
, . ,
,
,
Spring.


ApplicationContext,
DefaultListaeBeanFactory ( GenericXml
ApplicationContext getDefaultListaeBeanFactory ()),
ConfiguraeBeanFactory. destroySingletons ()
BeanFactory
.
, ,
.
, , ,
, .
4. Spring 139

destroy
Singletons () , ,
.
.

, .

,
,
destroy-method <bean>
. Spring
(
). 4.6
destroy-method.

4.6. destroy-method
package com.apress.prospring4.ch4;
import java.io.IOException;
import java.io.File;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class DestructiveBean implements InitializingBean {
private File file;
private String filePath;

@Override
puic void afterPropertiesSet() throws Exception {
System.out.println("Initializing Bean"); //
if (filePath == null) {
throw new IllegalArgumentException(
"You must specify the filePath property of "
// filePath
+ DestructiveBean.class);

this.file = new File(filePath);


this.file.createNewFile();
System.out.println("File exists: " + file.exists());
//

puic void destroy() {


System.out.println("Destroying Bean"); //
if( ! file.delete()) {
// :
System.err.println("ERROR: failed to delete file.");

System.out.println("File exists: " + file.exists());


//
140 4. Spring
puic void setFilePath(String filePath) {
this.filePath = filePath;

puic static void main(String[] args) throws Exception {


GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
DestructiveBean bean = (DestructiveBean) ctx.getBean("destructiveBean");
System.out. println ( "Calling destroy ()") ; / / destroy()
ctx.destroy();
System.out.println("Called destroy ()"); // destroy()

de s t r () ,
. main () Destr ucti veBean
GenericXmlApplicationContext destroy () (,
, ConfiguraleBeanFactory. destroySingletons (),
ApplicationContext), Spring ,
.
,
, . 4.7
destructi veBean (app-context-xml. xml).
4.7. destroy-method
<?xml version="l.0" encoding="OTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:p= "http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="destructiveBean"
class="com.apress.prospring4.ch4.DestructiveBean"
destroy-method="destroy"
p:filePath=
"#{systemProperties['java.io.tmpdir'] )#{systemProperties[
'file.separator'] )test.txt"/>
</beans>

, destroy ()
destroy-method.
filePath SpEL,
test. txt
java. io. tmpdir file. separator,
. :
4. Spring 141
Initializing Bean
File exists: true
Calling destroy()
Destroying Bean
File exists: false
Called destroy()
, Spring ,
DestructiveBean File .
destroy () Spring n
( )
, .
DestructiveBean
, .
Disposa.eBean
, Spring
, DisposaeBean,
.
DisposaeBean destroy (),
.
InitializingBean. 4.8
DestructiveBean, DisposaeBean.
4.8. DisposaleBean
package com.apress.prospring4.ch4;
import java.io.IOException;
import java.io.File;
import org.springframework.beans.factory.DisposaleBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class DestructiveBeanWithinterface implements InitializingBean,
DisposaeBean {
private File file;
private String filePath;

@Override
pulic void afterPropertiesSet() throws Exception {
System.out.println("Initializing Bean"); //
if (filePath == null) {
throw new IllegalArgumentException(
"You must specify the filePath property of "
// filePath
+ DestructiveBeanWithinterface.class);

this.file = new File(filePath);


this.file.createNewFile();
System.out.println("File exists: " + file.exists());
//
142 4. Spring

@Override
puic void destroy()
System.out.println("Destroying Bean"); //
if(!file.delete()) {
// :
System.err.println("ERROR: failed to delete file.");

System.out.println("File exists: " + file.exists());


//

pulic void setFilePath(String filePath)


this.filePath = filePath;

puic static void main(String [] args) throws Exception {


GenericXmlApplicationContext ctx = new GenericXmlApplicationContext{);
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
DestructiveBeanWithinterface bean =
(DestructiveBeanWithinterface) ctx.getBean("destructiveBean");
System.out.println("Calling destroy() "); // destroy()
ctx.destroy();
System.out.println("Called destroy() "); // destroy()

, , ,
, .
. 4.9
(app-context-xml. xml).
4.9. DisposaleBean
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="destructiveBean"
class="com.apress.prospring4.ch4.DestructiveBeanWithinterface"
:filePath=
"#{systemProperties['java.io.tmpdir'] }#{systemProperties[
'file.separator']}test.txt"/>
</beans>


destroy-method.
:
4. Spring 143
Initializing Bean
File exists: true
Calling destroy()
Destroying Bean
File exists: false
Called destroy()
@PreDes troy JSR-250

@PreDestroy, JSR-250,
@PostConstruct. 4.10
DestructiveBean, @PostConstruct
@PreDestroy ,
.

4.1 . Disposaleean @PreDes troy


@PostDestroy
package com.apress.prospring4.ch4;
import java.io.File;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class DestructiveBeanWithJSR250
private File file;
private String filePath;
@PostConstruct
puic void afterPropertiesSet() throws Exception
System.out.println("Initializing Bean");
if (filePath == null) {
throw new IllegalArgumentException(
"You must specify the filePath property of " +
DestructiveBeanWithJSR250.class);

this.file = new File(filePath);


this.file.createNewFile();
System.out.println( "File exists: " + file.exists());

@PreDestroy
pulic void destroy()
System.out.println("Destroying Bean");
if(!file.delete()) {
System. err.println("ERROR: failed to delete file. ");

System.out.println("File exists: " + file.exists() );

puic void setFilePath(String filePath) {


this.filePath = filePath;
144 4. Spring
puic static void main(String[J args) throws Exception {
GenericxmlApplicationContext ctx = new GenericXlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
DestructiveBeanWithJSR250 bean =
(DestructiveBeanWithJSR250) ctx.getBean("destructiveBean");
System.out.println("Calling destroy()");
ctx.destroy();
System.out.println("Called destroy()");

4.11 L-r ,
<context: annotation-config> (app-context-annotation. xml).
4.11. Disposaleean
JSR-250
<?xml version= "l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean id="destructiveBean"
class="com.apress.prospring4.ch4.DestructiveBeanWithJSR250"
p:filePath=
"#{systemProperties['java.io.tmpdir']}#{systemProperties[
'file.separator'] }test.txt"/>
</beans>

-
,
. -
, :
, DisposaeBean @PreDestroy. ,
n ;
, , DisposaeBean
JSR-250, .


,
. Spring
, @PreDestroy, DisposaleBean.
destroy () , , ,
XML.
4. Spring 145


Spring ,
, ..
AbstractApplicationContext. destroy ().
, destroy ()
destroy () . ,
. , .
Java (shutdown hook) - ,
.
destroy () AstractApplicationContext (
1-1 ApplicationContext).
registerShutdownHook ()
AbstractApplicationContext.
Spring
JVM. 4.12 .
4. 12.
package com.apress.prospring4.ch4;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.File;
import org.springframework.context.support.GenericXrnlApplicationContext;
puic class DestructiveBeanWithinterface
private File file;
private String filePath;

@PostConstruct
puic void afterPropertiesSet() throws Exception
System.out.println("Initializing Bean");
if (filePath == null) {
throw new IllegalArgumentException(
" must specify the filePath property of " +
DestructiveBeanWithinterface.class);

this.file = new File(filePath);


this.file.createNewFile();
System.out.println("File exists: " + file.exists());

@PreDestroy
puic void destroy()
System.out.println("Destroying Bean");
if(!file.delete()) {
System.err.println("ERROR: failed to delete file.");

System.out.println("File exists: " + file.exists());


146 4. Spring
puic void setFilePath(String filePath) {
this.filePath = filePath;

pulic static void main(String[] args) throws Exception {


GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.registerShutdownHook();
ctx.refresh();
DestructiveBeanWithinterface bean =
(DestructiveBeanWithinterface) ctx.getBean("destructiveBean");

L- (app-context-annotation.
xml):
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
< id="destructiveBean"
class="com.apress.prospring4.ch4.DestructiveBeanWithinterface"
p:filePath=
"#{systemProperties['java.io.tmpdir'] 1
#{systemProperties['file.separator'] )test.txt"/>
</beans>
:
Initializing Bean
File exists: true
Destroying Bean
File exists: false
, destroy () , ,
.

"
Spring"

,
, . ,

, Spring , Google
4. Spring 147
Guice, , , PicoContajner.
,
,
- . ,
,
ApplicationContext.
(.. , ApplicationContext),
.
,
Spring. -
,

-. , ,
.
, ,
.
, , ,
, , - ,
.

BeanNameAware
BeanNameAware, ,
, : setBeanName (String). Spring
setBeanName () ,
(
), . 4.1.
setBeanName () , ,
, - .
4.13 ,
BeanNameAware .
4.1 . BeanNameAware
package com.apress.prospring4.ch4;
import org.springframework.beans.factory.BeanNameAware;
puic class BeanNamePrinter implements BeanNameAware (
private String beanName;
@Override
pulic void setBeanName(String beanName)
this.beanName = beanName;

puic void someOperation () (


System.out.println ( "Bean [" + beanName + "] - someOperation () ");
148 4. Spring

. ,
BeanNameAware. setBeanName () ,
ApplicationContext. getBean (),
someOperation () ,
. 4.14
(app-context-xml. xml).
4.14. LoggingBean
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanNamePrinter" class="com.apress.prospring4.ch4.BeanNamePrinter"/>
</beans>

, :
BeanNameAware . 4.15
, BeanNamePrinter ApplicationContext
someOperation ().

4.15. LoggingBeanExample
package com.apress.prospring4.ch4;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class BeanNamePrinterExample {
pulic static void main (String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
BeanNamePrinter bean = (BeanNamePrinter) ctx.getBean("beanNamePrinter");
bean.someOperation();

;
someOperation ():
Loading XML bean definitions from class path resource
[META-INF/spring/app-context-xml.xml]

Bean [beanNamePrinter] - someOperation()


BeanNameAware ,
, .
- ,
; , Spring,
, .
4. Spring 149
, Nameae
( ), setName (),
.
, ,
,
-.
Applica tionCon textAware
ApplicationContextAware
ApplicationContext,
. , ,
ApplicationContext ,
, Spring ,
getBean ().
, .
getBean ()
, ,
Spring Framework
.
, ApplicationContext
; . ,

. ,
, ApplicationContext
.
ApplicationContextAware, ,
ApplicationContext
. 4.16.
4.16. Shu tdownHookBean
package com.apress.prospring4.ch4;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.GenericApplicationContext;
puic class ShutdownHookBean implements ApplicationContextAware
private ApplicationContext ctx;
@Override
puic void setApplicationContext(ApplicationContext ctx)
throws BeansException {
if (ctx instanceof GenericApplicationContext) {
((GenericApplicationContext) ctx).registerShutdownHook();
150 4. Spring

.
ApplicationContextAware s etApplication
Context (ApplicationContext), Spring
ApplicationContext. 4.16
ShutdownHookBean , ApplicationContext
Gene ricApplicationContext, register
ShutdownHook (); , ApplicationContext
. 4.17 ,
DestructiveBeanWithlnterface (app-context-annotation. xml).

4.17. Shutdownookean
<?xml version="l. " encoding="UTF-8 "?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean id="destructiveBean"
class="com.apress.prospring4.ch4.DestructiveBeanWithinterface"
:filePath=
"#{systemProperties['java.io.tmpdir']}
#{systemProperties['file.separator'] }test.txt"/>
<bean id="shutdownHook"
class="com.apress.prospring4.ch4.ShutdownHookBean"/>
</beans>

, .
4.18 , ShutdownHookBean
.

4.18. ShutdownHookean
package com.apress.prospring4.ch4;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.File;
import org.springframework.context.support.GenericxmlApplicationContext;
puic class DestructiveBeanWithinterface
private File file;
private String filePath;

@PostConstruct
pulic void afterPropertiesSet() throws Exception
System.out.println("Initializing Bean");
4. Spring 151
if (filePath == null) {
throw new IllegalArgumentException(
"You must specify the filePath property of 11 +
DestructiveBeanWithinterface.class);

this.file = new File(filePath);


this.file.createNewFile();
System.out.println("File exists: 11 + file.exists());

@PreDestroy
puic void destroy()
System.out.println( 11 Destroying Bean");
if(!file.delete()) {
System.err.println("ERROR: failed to delete file.");

System.out.println("File exists: " + file.exists());

puic void setFilePath(String filePath) {


this.filePath = filePath;

puic static void main(String[] args) throws Exception {


GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.registerShutdownHook();
ctx. refresh();
DestructiveBeanWithinterface bean =
(DestructiveBeanWithinterface) ctx.getBean("destructiveBean");

. Spring
ApplicationContext, destructiveBean
, Applic ationContext
shutdownHook .
, , :
Initializing Bean
File exists: true
Destroying Bean
File exists: false
, destroy ()
ShutdownHookean ,
destroy () .


Spring
,
new. Spring
152 4. Spring

FactoryBean, ,
Spring.
,
new, ,
, . , FactoryBean -
, .
ApplicationContext ,
Spring FactoryBean
, FactoryBean,
FactoryBean. getObj ect () .
Spring ,
,
9, JNDI. ,

Spring; -
, ..
IoC, .

:
MessaqeDiqes tFactoryBean

; ,
.
Java MessageDigest,
. MessageDigest
;
MessageDigest. getinstance ()
, . ,
MD5, MessageDigest
:
MessageDigest rnd5 = MessageDigest. getinstance ( "MD5");
MessageDigest
Spring, , FactoryBean -
, algori thrnNarne,
MessageDigest. getinstance ().
FactoryBean, .
, MessageDigest,
, , rnessageDigest, FactoryBean
. 4.19 FactoryBean,
, .

4.19. MessageDigestFactoryean
package com.apress.prospring4.ch4;
import java.security.MessageDigest;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
4. Spring 153
puic class MessageDigestFactoryBean implements
FactoryBean<MessageDigest>, InitializingBean
private String algorithmName = "MD5";
private MessageDigest messageDigest = null;
@Override
pulic MessageDigest getObject() throws Exception
return messageDigest;

@Override
puic Class<MessageDigest> getObjectType()
return MessageDigest.class;

@Override
puic boolean isSingleton()
return true;

@Override
pulic void afterPropertiesSet() throws Exception {
messageDigest = MessageDigest.getinstance(algorithmName);

pulic void setAlgorithmName(String algorithmName)


this.algorithmName = algorithmName;

FactoryBean : g e t Obje c t ( ) ,
getObjectType() isSingleton(). Spring
getObject() , FactoryBean.
, , FactoryBean
. 4.19 , MessageDigestFactoryBean
MessageDigest,
InitializingBean. afterPropertiesSet ().
getObj ectType() Spring,
. null,
(,
,
), , Spring .
MessageDigest ( ,

, ).
, , (
,
MessageDigest).
isSingleton() Spring ,
. ,
singleton <bean> Spring
,
.
154 4. Spring

, .
4.20 ,
MessageDigest ,
digest ().
4.20. MessageDigester
package com.apress.prospring4.ch4;
import java.security.MessageDigest;
pulic class MessageDigester {
private MessageDigest digestl;
private MessageDigest digest2;
puic void setDigestl(MessageDigest digestl)
this.digestl = digestl;

puic void setDigest2(MessageDigest digest2)


this.digest2 = digest2;

pulic void digest(String msg)


System.out.println("Using digestl");
digest(msg, digestl);
System.out.println("Using digest2");
digest(msg, digest2);

private void digest(String msg, MessageDigest digest) {


System.out.println("Using alogrithm: " + digest.getAlgorithm());
digest.reset();
byte [ J bytes = msg. getBytes ();
byte [] out = digest.digest(bytes);
System.out.println(out);

4.21 MessageDigest
FactoryBean, SHAI, -
(MD5) (app-context-xml. xml).

4.21. MessageDigestFactoryBean
<?xml version="l.0" encoding="UTE'-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="shaDigest" class="com.apress.prospring4.ch4.MessageDigestE'actoryBean"
p:algorithmName="SAl"/>
<bean id="defaultDigest"
class= "com.apress.prospring4.ch4.MessageDigestE'actoryBean"/>
4. Spring 155
<bean id="digester"
class="com.apress.prospring4.ch4.MessageDigester"
p:digestl-ref="shaDigest"
p:digest2-ref="defaultDigest"/>
</beans>

, MessageDigestFactory
Bean, MessageDigester, M essageDigestFactoryBean
digestl digest2.
defaul tDigest algorithmName ,
, (MD5),
. 4.22 ,
MessageDigester .

4.22. MessageDigester
package com.apress.prospring4.ch4;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class MessageDigestExample {
pulic static void main (String(J args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:ETA-INF/spring/app-context-xml.xml");
ctx.refresh();
MessageDigester digester = (MessageDigester) ctx.getBean("digester");
digester.digest("Hello World!");

:
Using digestl
Using alogrithm: SAl
[B@77cd7a0
Using digest2
Using alogrithm: MDS
[B@204f30ec
, M e s s a ge Dig est
MessageDigest, SHAI MD5, , M essageDigest
. .
,
, new.
, ,
Spring,
,
Spring IoC.
156 4. Spring


, Spring
, , :
? : , .
: getBean ()
, 4.23.
4.23.
package com.apress.prospring4.ch4;
import java.security.MessageDigest;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class AccessingFactoryBeans {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
MessageDigest digest = (MessageDigest) ctx.getBean("shaDigest");
MessageDigestFactoryBean factoryBean =
(MessageDigestFactoryBean) ctx.getBean("&shaDigest");
try {
MessageDigest shaDigest = factoryBean.getObject();
System.out.println(shaDigest.digest("Hello world".getBytes()));
catch (Exception ) {
ex.printStackTrace();

:
[B@77cd7a0
Spring,
- .
FactoryBean
,
IoC. FactoryBean
getObj ect () , Spring;
,
, .

factory-bean factory-method
JavaBean,
, Spring.
, , ,
,
JavaBean, Spring.
4. Spring 157
factory-bean factory-method <bean> .
Spring.
, , 4.24
MessageDigestFactory,
MessageDigest.

4.24. MessageDigestFactory
package com.apress.prospring4.ch4;
import java.security.MessageDigest;
puic class MessageDigestFactory {
private String algorithmName = "MDS";
puic MessageDigest createinstance() throws Exception
return MessageDigest.getinstance(algorithmName);

puic void setAlgorithmName(String algorithmName)


this.algorithmName = algorithmName;

4.25 ,
. MessageDigest (app-context
xml. xml).

4.25. MessageDigestFactory
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="shaDigestFactory"
class="com.apress.prospring4.ch4.MessageDigestFactory"
p:algorithmName="SAl"/>
<bean id="defaultDigestFactory"
class="com.apress.prospring4.ch4.MessageDigestFactory"/>
<bean id="shaDigest"
factory-bean="shaDigestFactory"
factory-method="createinstance">
</bean>
<bean id="defaultDigest"
factory-bean="defaultDigestFactory"
factory-method="createinstance"/>
<bean id="digester"
class="com.apress.prospring4.ch4.MessageDigester"
p:digestl-ref="shaDigest"
p:digest2-ref="defaultDigest"/>
</beans>
158 4. Spring

, MessageDigest
Factory, SHAI, - .
shaDigest defaultDigest r factory-bean
Spring
MessageDigestFactory r factory
method , .
4.26 , .

4.26. essageDigestFactory
package com.apress.prospring4.ch4;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class MessageDigestFactoryExample (
puic static void main(String [] args) (
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
MessageDigester digester = (MessageDigester) ctx.getBean("digester");
digester.digest("Hello World!");

:
Using digestl
Using alogrithm: SHAl
[B@le397ed7
Using digest2
Using alogrithm: MDS
[@490905

JavaBean
JavaBean,
, PropertyEditor ( ) - ,
String.

(String) .
,
, , Spring.
- , ,
Spring, BeanFactory,
. , , ,
String. , Spring
String
, r String,
, .
4. Spring 159


Spring 4 13 PropertyEditor,
BeanFactory. 4.27
, 13 , ,
.

4.27.
package com.apress.prospring4.ch4;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.regex.Pattern;
import java.text.SimpleDateFormat;
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class PropertyEditorBean {
private byte [ J bytes; // ByteArrayPropertyEditor
private Class cls; // ClassEditor
private Boolean trueOrFalse; // CustomBooleanEditor
private List<String> stringList; // CustomCollectionEditor
private Date date; // CustomDateEditor
private Float floatValue; // CustomNumerEditor
private File file; // FileEditor
private InputStream stream; // InputStreamEditor
private Locale locale; // LocaleEditor
private Pattern pattern; // PatternEditor
private Properties properties; // PropertiesEditor
private String trimString; // StringTrimmerEditor
private URL url; // URLEditor
puic void setCls(Class cls)
//
System.out.println("Setting class: " + cls.getName());
this.cls = cls;

puic void setFile(File file) {


//
System.out.println("Setting file: " + file.getName());
this.file = file;

puic void setLocale(Locale locale) {


//
System. out.println( "Setting locale: " + locale.getDisplayName());
this.locale = locale;
160 4. Spring

puic void setProperties(Properties properties)


//
System.out.println("Loaded " + properties.size() + " properties");
this.properties = properties;

puic void setUrl(URL url) {


// URL
System.out.println("Setting URL: " + url.toExternalForm(}};
this.url = url;

puic void setBytes(byte [] bytes) {


//
System.out.println("Adding " + bytes.length + " bytes");
this.bytes = bytes;

puic void setTrueOrFalse(Boolean trueOrFalse) {


//
System.out.println("Setting Boolean: " + trueOrFalse);
this.trueOrFalse = trueOrFalse;

puic void setStringList(List<String> stringList) {


//
System.out.println("Setting string list with size: "
+ stringList.size());
this.stringList = stringList;
for (String string: stringList)
// String
System.out.println("String memer: " + string);

puic void setDate( Date date)


//
System.out.println("Setting date: " + date);
this.date = date;

puic void setFloatValue(Float floatValue)


//
System.out.println("Setting float value: " + floatValue);
this.floatValue = floatValue;

puic void setStream(InputStream stream)


//
System.out.println("Setting stream: " + stream);
this.stream = stream;

pulic void setPattern(Pattern pattern)


//
System.out.println("Setting pattern: " + pattern);
this.pattern = pattern;
4. Spring 161
puic void setTrimString(String trimString) {
//
System.out.println("Setting trim string: " + trimString);
this.trimString = trimString;

pulic static class CustomPropertyEditorRegistrar


implements PropertyEditorRegistrar {
@Override
puic void registerCustomEditors(PropertyEditorRegistry registry) {
SimpleDateFormat dateFormatter = new SimpleDateFormat ( "/dd/");
registry.registerCustomEditor(Date.class,
new CustomDateEditor(dateFormatter, true));
registry.registerCustomEditor(String.class,
new StringTrimmerEditor(true) );

pulic static void main(String[] args) throws Exception


File file = File.createTempFile("test", "txt");
file.deleteOnExit();
GenericXmlApplicationContext ctx = new GenericXrnlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
PropertyEditorBean bean =
(PropertyEditorBean) ctx.getBean("builtinSample");

4.27 , PropertyEdi torBean 13 ,


. 4.28
,
(app-config-xml. xml).
4.28. ,
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="customEditorConfigurer"
class="org.springframework.beans.factory.config.CustomEditorConfigurer"
p:propertyEditorRegistrars-ref="propertyEditorRegistrarsList"/>

<util:list id ="propertyEditorRegistrarsList">
<bean class="com.apress.prospring4.ch4.
PropertyEditorBean$CustomPropertyEditorRegistrar"/>
</util:list>
162 4. Spring

<bean id="builtinSarnple" class="com.apress.prospring4.ch4.PropertyEditorBean"


p:bytes= "Hello World"
p:cls="java.lang.String"
p:trueOrFalse="true"
p:stringList-ref= "stringList"
p:stream= "test.txt"
p:floatValue= "l23.45678"
p:date="OS/03/13"
p:file="#{systemProperties['java.io.tmpdir'J}
#{systemProperties['file.separator'J }test.txt"
p:locale= "en_US"
p:pattern="a*b"
p:properties= "narne= Chris age= 32"
:trimString=" String need trimming
p:url="http://www.springframework.org"
/>
<util:list id="stringList">
<value>String memer l</value>
<value>String member 2</value>
</util:list>
</beans>

, PropertyEdi torBean String,


.
CustomDateEditor StringTrimmerEditor,
Spring .
:
Adding 11 bytes
Setting class: java.lang.String
Setting date: Wed 03 00:00:00 EST 13
Setting file: test.txt
Setting float value: 123.45678
Setting locale: English (United States)
Setting pattern: *
Loaded 1 properties
Setting stream:
sun.net.www.protocol.jar.JarURLConnection$JarURLinputStream@57elbOc
Setting string list with size: 2
String member: String memer 1
String member: String memer 2
Setting trim string: String need trimming
Setting Boolean: true
Setting URL: http://www.springframework.org
, Spring
.
. 4.1 ,
Spring.
4. Spring 163
4.1. Spring


ByteArrayPropertyEditor String
ClassEditor
Class.
,
,
GenericxrnlApplicationContext;
ClassNotFoundException
CustomooleanEditor Jv- Boolean
CustomCollectionEditor (,
util Spring)
Collection
CustomDateEditor
java. util. Date.
ApplicationContext
CustomNumerEditor ,
Integer, Long, Float Doue
FileEditor File.
Spring
InputStreamEditor (,
file:D:/temp/test. txt
classpath:test.txt)
LocaleEditor ,
en-GB, java. util.Locale
Pattern JD- Pattern
PropertiesEditor l=l
2=2 n=n java.
util. Properties
StringTrimmerEditor .

URLEditor URL
java.net.URL


Spring
, URL.



,
,
. Spring
; ,
164 4. Spring

j ava. beans. PropertyEdi tor ,


-
. , JDK 5
PropertyEditorSupport,
, . setAsText () .

. , Narne -
. 4.29.
4.29. Name
package com.apress.prospring4.ch4;
puic class Name {
private String firstName;
private String lastName;
puic Name(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;

puic String getFirstName()


return firstName;

puic void setFirstName(String firstName) {


this.firstName = firstName;

pulic String getLastName()


return lastName;

pulic void setLastName(String lastName) {


this.lastName = lastName;

puic String toString()


return "First name: " + firstName + " - Last name: " + lastName;


, -
Narne. 4.30.
4.30. NamePropertyEdi tor
package com.apress.prospring4.ch4;
import java.beans.PropertyEditorSupport;
pulic class NamePropertyEditor extends PropertyEditorSupport
@Override
pulic void setAsText(String text) throws IllegalArgumentException
String[] name = text.split("\\s");
4. Spring 165
setValue(new Name(name[O], name[l]));

. PropertyEditorSupport JDK
setAsText (). String
, .
Name , ,
- . ,
setValue ().
NamePropertyEditor ,
ApplicationContext. 4.31
ApplicationContext,
CustomEditorConfigurer NamePropertyEditor (app-context-xml. xml).
4.31. CustomEdi torConfigurer
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:p= "http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="customEditorConfigurer"
class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="com.apress.prospring4.ch4.Name"
value="com.apress.prospring4.ch4.NamePropertyEditor"/>
</map>
</property>
</bean>
<bean id="exampleBean" class="com.apress.prospring4.ch4.CustomEditorExample"
p:name="Chris Schaefer"/>
</beans>

. -,
CustomEdi torConfigurer
customEdi tors . -,
-
, . ,
NamePropertyEditor . apress. prospring4. ch4. Name, .. ,
.
4.32 CustomEditorExample,
4.31.
4.32. CustomEdi torExample
package com.apress.prospring4.ch4;
import org.springframework.context.support.GenericXmlApplicationContext;
166 4. Spring

puic class CustomEditorExample


private Name name;
pulic Name getName()
return name;

pulic void setName(Name name)


this.name = name;

puic static void main(String[] args) {


GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
CustomEditorExample bean =
(CustomEditorExample) ctx.getBean("exampleBean");
System.out.println(bean.getName());

. :
First name: Chris - Last name: Schaefer
toString (), Name;
, Spring
NamePropertyEditor.
3, Spring Converter SPI (service
provider interface - ) Formatter SPI,
l-
.
-. Converter SPI Formatter SPI
I .


ApplicationContext
ApplicationContext , ,
, BeanFactory,
ApplicationContext. Spring
BeanFactory ,
,
Spring. , , BeanFactory,
ApplicationContext
.
ApplicationContext
, .
ApplicationContext ( BeanFactory)
, .
Spring, BeanFactoryPostProcessor,
4. Spring 167

, ,
Spring.
ApplicationContext
, Spring
.
, Spring
ApplicationContext ,
- ApplicationContext.
-
Spring, ApplicationContext
-.
ApplicationContext .
,
, ApplicationContext
:
;
;
;
;
.

ApplicationContext DI.

MessageSource
, Spring
, (il8n).
MessageSource ,
, . ,
, ,
. ,
-, ,
" ",
, , msg;
"The quick brown fox jumped over the lazy dog",
- "Priserne zlutoucky kun upel dabelske 6dy".
MessageSource
ApplicationContext, MessageSource

.
,
Spring , Spring
-.
ApplicationContextAware -
168 4. Spring

, " MessageSource
" .
i 18n Java, ,
Javadoc (http: //download. java. net/
jdk8/docs/api/index. html).
Appl.icationContext essageSource
A pplicationContext Spring
ssgSur: ResourceBundleMessageSource, ReloadaleResource
BundleMessageSource StaticMessageSource.
StaticMessageSource
, , ,
, il8n .
ResourceBundleMessageSource
Jv- ResourceBundle.
ReloadaleResourceBundleMessageSource ,
.
MessageSource
HierarchicalMessageSource,
MessageSource. , ApplicationContext
MessageSource.
MessageSource, Application
Context, MessageSource
messageSource. ApplicationContext MessageSource
,
ApplicationContext.
.
4.33 ,
.
4.33. essageSource
package com.apress.prospring4.ch4;
import java.util.Locale;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class MessageSourceDemo {
puic static void main(String[] args} {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:ETA-INF/spring/app-context-xml.xml");
ctx.refresh(};
Locale english = Locale.ENGLISH;
Locale czech = new Locale("cs", "CZ"};
System.out.println(ctx.getMessage("msg", null, english)};
System.out.println(ctx.getMessage("msg", null, czech)};
System.out.println(ctx.getMessage("nameMsg", new Object[] { "Chris",
"Schaefer" } , english}} ;
4. Spring 169
getMessage () ;
. ,
. 4.34 ,
(app-context-xml. xml).
4.34. essageSource
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basenames-ref= "basenames"/>
<util:list id="basenames">
<value>buttons</value>
<value>labels</value>
</util:list>
</beans>

ResourceBundleMessageSource
messageSource, ,
. ResourceBundle Java,
ResourceBundleMessageSource,
, .
ResourceBundle ,
. , foo
en-GB ( ),
ResourceBundle foo_en_GB. properties.
(labels_en. properties)
(labels_cs_CZ. properties) , ,
4.35 4.36.
4.35. laels_en. properties
msg=The quick brown fox jumped over the lazy dog
nameMsg=My name is {} {1}

4.36. laels_cs_cz. properties


msg=Priserne zlutoucky kun upel dabelske 6dy

MessageSourceDemo 4.33
:
170 4. Spring

The quick brown fox jumped over the lazy dog


Priserne zlutoucky kun upel dabelske 6dy
name is Chris Schaefer
.
getMessage ()? ApplicationContext. getMessage (),
ResourceBundleMessageSource ?
.
getessage ()
MessageSource
getMessage (), . 4.2.
4.2. essageSource. getessage ()

getMessage(String, getMessage() .
Object [] , Locale) String ,
. 4.33
getMessage() msg,

en: msg=The quick brown fox jumped over the
lazy dog. Object []
.
getMessage () 4.33
String. ,
nameMsg, name is {} { 1}.
,
,
. , Locale,
ResourceBundleMessageSource,
.
getMessage() ,
,
Locale, getMessage()
getMessage(String, getMessage
Object [] , String, Locale) (String, Obj ect [] , Locale),
String,
,
, Locale
getMessage(
MessageSourceResolvae, ,
Locale) " MessageSourceResolv"

App1icationContext essageSource
ApplicationContext
MessageSource,
- Spring. , ,
ApplicationContext MessageSource,
ApplicationContext ( -
4. Spring 171
).
ApplicationContext -
MVC, Spring.
Spring MVC Control ler.
, Struts,
, Spring
Controller (
@Controller). , Spring
,
. ( )
ApplicationObj ectSupport,
,
ApplicationContext.
, - ApplicationContext
. Appl ica t ionObj ectSupport
ApplicationContext,
MessageSourceAccessor
getMessageSourceAccessor (). MessageSourceAccessor
MessageSource.
;
MessageSource.
ApplicationContext
MessageSource -.
ApplicationContext MessageSource
, Spring, , ApplicationContext
MessageSource . ,
JSP (JSTL), Spring,
<spring :message> ApplicationContext,
JSTL <fmt: message> .
, -
MessageSource ApplicationContext,
MessageSource . ,
,
MessageSource messageSource.

MessageSource
MessageSource ,
Spring
MessageSource ApplicationContext,
MessageSource .
,
ApplicationContextAware,
BeanFactory. -
, .
MessageSource .
172 4. Spring

MessaqeSourceResolvale
MessageSource
, MessageSourceResol v, .

Spring Error
.


ApplicationContext, BeanFactory,
,
ApplicationContext . ,
.

- , ApplicationEvent,
java. uti 1. EventObj ect.
, ApplicationListener<T>;
Appli tionContext
, , .
ApplicationEventPulisher. puishEvent (),

ApplicationContext ( ApplicationEventPuisher).
- , ..
Spring Framework,
ApplicationContext .
,
ApplicationContextAware.
4.37 .
4.37.
package com.apress.prospring4.ch4;
import org.springframework.context.ApplicationEvent;
pulic class MessageEvent extends ApplicationEvent {
private String msg;
puic MessageEvent(Object source, String msg) {
super(source);
this.msg = msg;

pulic String getMessage()


return msg;

; , ,
ApplicationEvent ,
. MessageEvent.
4. Spring 173
4.38 .

4.38. MessageEventListener
package com.apress.prospring4.ch4;
import org.springframework.context.ApplicationListener;
puic class MessageEventListener implements ApplicationListener<MessageEvent>
@Override
puic void onApplicationEvent(MessageEvent event) {
MessageEvent msgEvt = (MessageEvent) event;
System.out.println("Received: " + msgEvt.getMessage());

ApplicationListener
onApplicationEvent (), Spring,
. MessageEventListener
MessageEvent ( ),
ApplicationListener. MessageEvent
stdout. ;
ApplicationEventPuisher. puishEvent (),
4.39.

4.39.
package com.apress.prospring4.ch4;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.ClassPathXmlApplicationContext;
puic class Pulisher implements ApplicationContextAware
private ApplicationContext ctx;
@Override
puic void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.ctx = applicationContext;

puic void puish(String message)


ctx.puishEvent(new MessageEvent(this, message));

puic static void main(String [] args) {


ApplicationContext ctx = new ClassPathXmlApplicationContext(
"classpath:META-INF/spring/app-context-xml.xml");
Pulisher pub = (Puisher) ctx.getBean("pulisher");
pub.puish("Hello World!");
pub.puish("The quick brown fox j umped over the lazy dog");
174 4. Spring

Puisher ApplicationContext
puish () MessageEvent
ApplicationContext. Puisher
ApplicationContext ApplicationContextAware.
4.40 (app-context-xml. xml).
4.40. ApplicationListener
<?xrnl version= "l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi= "http://www.w.org/2001/XLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="puisher" class= "com.apress.prospring4.ch4.Puisher"/>
<bean id="messageEventListener"
class="com.apress.prospring4.ch4.MessageEventListener"/>
</beans>

, MessageEventListener Application
Context ; Spring
. :
Received: Hello World!
Received: The quick brown fox jumped over the lazy dog



.
-
, JMS.
,
, .
,
, .

. ,
,
. ,
-.
:
,
, , , .
,
, , ,
,
.
JMS ,
-
4. Spring 175

. Spring
.
, ,
.

, (
, ) .
, -,
JMS ,
RabbltMQ. J MS
, ,
JMS ,
-, .


.
,
, , JR- ,
- , .
Spring
. ,
, : ,
.
Spring org. spring
framework. core. io. Resource. Resource
: contentLength (), exists (), getDescription (), getFile (),
getFileName (), getURI (), getURL (), isOpen (), isReadae () lastModified ().
, :
createRelative (). createRelative () Resource,
, .
Resource,
,
( FileSystemResource), (
ClassPathResource) URL-pecypca ( UrlResource).
Resource Spring
, ResourceLoader,
Defaul tResourceLoader.
DefaultResourceLoader,
ResourceLoader -ApplicationContext.
4.41 ,
ApplicationContext.
4.41.
package com.apress.prospring4.ch4;
import java.io.File;
import org.springframework.context.ApplicationContext;
176 4. Spring
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
puic class ResourceDemo {
puic static void rnain(String[] args) throws Exception{
ApplicationContext ctx = new ClassPathXmlApplicationContext();
File file = File.createTempFile("test", "txt");
file.deleteOnExit();
System.out.println(file.getPath());
Resource resl = ctx.getResource("file://" + file.getPath());
displayinfo(resl);
Resource res2 = ctx.getResource("classpath:test.txt");
displayinfo(res2);
Resource res = ctx.getResource( "http://www.google. ");
displayinfo(res);

private static void displayinfo(Resource res) throws Exception{


System.out.println(res.getClass());
System.out.println(res.getURL().getContent());
System.out.println("");

, getResource () URI
. file: http:,
resl res. classpath:, res2,
Spring , ResourceLoader
. :
class org.springframework.core.io.UrlResource
java.io.BufferedinputStream@a024a67
class org.springframework.core.io.ClassPathResource
sun.net.www.content.text.PlainTextinputStrearn@4de8b406
class org.springframework.core.io.UrlResource
sun.net.www.protocol.http.HttpURLConnection$HttpinputStrearn@48eff760
, file: http: Spring
UrlResource. FileSystemResource,
DefaultResourceLoader . ,
Spring U RL
, (.. file: http:).
FileSystemResource , FileSystemResourceLoader.
Resource,
, getFile (), getinputStream () getURL ().
, , http:, getFile ()
FileNotFoundException.
getinputStream (), ,
, .
4. Spring 177

, Jv-
L ApplicationContext
Jv-. Spring JavaConfig,
, Spring 3.0, ,
Jv-, Spring Framework.
, Jv-
ApplicationContext, L
.
ApplicationContext Java
ApplicationContext
Jv- ,
3. 4.42

.
4.42. MessageProvider ConfiguraleessageProvider
package com.apress.prospring4.ch4;
pulic class ConfiguraleMessageProvider implements MessageProvider
private String message = "Default message";
pulic ConfiguraleMessageProvider()

pulic ConfiguraleMessageProvider(String message)


this.message = message;

puic void setMessage(String message)


this.message = message;

@Override
puic String getMessage()
return message;

4.43 MessageRenderer Standard


OutMessageRenderer.
4.43. essageRenderer StandardOutessageRenderer
package com.apress.prospring4.ch4;
pulic interface MessageRenderer {
void render();
void setMessageProvider(MessageProvider provider);
MessageProvider getMessageProvider();

package com.apress.prospring4.ch4;
178 4. Spring
puic class StandardOutMessageRenderer implements MessageRenderer
private MessageProvider messageProvider;
@Override
pulic void render() (
if (messageProvider = = null)
throw new RuntimeException(
"You must set the property messageProvider of class:"
+ StandardOutMessageRenderer.class.getName() );

System.out.println(messageProvider.getMessage());

@Override
puic void setMessageProvider(MessageProvider provider) (
this.messageProvider = provider;

@Override
puic MessageProvider getMessageProvider()
return this.messageProvider;

4.44 L- ApplicationContext
(app-context-xml. xml).
4.44. L-
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="messageRenderer"
class="com.apress.prospring4.ch4.StandardOutMessageRenderer"
p:messageProvider-ref="messageProvider"/>
<bean id="messageProvider"
class="com.apress.prospring4.ch4.ConfiguraeMessageProvider"
c:message="This is configurale message"/>
</beans>

, 4.45 .

4.45. L-
package com.apress.prospring4.ch4;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
puic class JavaConfigXMLExample {
4. Spring 179
puic static void main(String[] args)
ApplicationContext ctx = new
ClassPathXmlApplicationContext(
"classpath:META-INF/spring/app-context-xml.xml");
MessageRenderer renderer =
ctx.getBean("messageRenderer", MessageRenderer.class);
renderer.render();

:
This is configurale message
Jv- XML

JavaBean,
Jv-r Spring. 4.46 Jv-,
L-r 4.44.
4.46. Jv-
package com.apress.prospring4.ch4;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
pulic class AppConfig {
@Bean
puic MessageProvider messageProvider()
return new ConfiguraeMessageProvider();

@Bean
puic MessageRenderer messageRenderer()
MessageRenderer renderer = new StandardOutMessageRenderer();
renderer.setMessageProvider(messageProvider());
return renderer;

AppConfig @Configuration
Spring , ,
Java. Spring 01
@Bean. @Bean <bean>,
- id <bean>.
MessageRender
,
, ref XML. 4.47
, ApplicationContext Jv-r.
180 4. Spring

4.47. Jv-
package com.apress.prospring4.ch4;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationC
ontext;
puic class JavaConfigSimpleExample {
puic static void main(String [] args)
ApplicationContext ctx = new
AnnotationConfigApplicationContext(AppConfig.class);
MessageRenderer renderer =
ctx.getBean("messageRenderer", MessageRenderer.class);
renderer.render();

AnnotationConfigApplicationContext,
(

JDK). ApplicationContext
.
:
Default message
Jv-
.
(message .properties)
ConfiguraleMessageProvider Constructor
lnjection. message. properties :
message=Hello from Spring Java Configuration
,
, @PropertySource,
. 4.48
, Spring Jv-.
, @EnaleTransactionManagement
spring-tx (. 4.3).
4.3. Spring



org.springframework spring-tx 4.0.2.RELEASE Spring

4.48. Java-nacc AppConfig ()


package com.apress.prospring4.ch4;
import org.springframework.beans.factory.annotation.Autowired;
4. Spring 181
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Scope;
import org.springframework.core.env.Environment;
import org.springframework.transaction.annotation.
EnaeTransactionManagement;
@Configuration
@ImportResource(value="classpath:META-INF/spring/app-context-xml.xml")
@PropertySource(value="classpath:message.properties")
@ComponentScan(basePackages= {"com.apress.prospring4.ch4"})
@EnaleTransactionManagement
puic class AppConfig {
@Autowired
Environment env;
@Bean
@Lazy(value=true)
pulic MessageProvider messageProvider()
return new ConfiguraleMessageProvider(env.getProperty("message"));

@Bean(name= "messageRenderer")
@Scope(value="prototype")
@DependsOn(value="messageProvider")
puic MessageRenderer messageRenderer()
MessageRenderer renderer = new StandardOutMessageRenderer();
renderer.setMessageProvider(messageProvider());
return renderer;

4.48
Jv-.
, .
@PropertySource
ApplicationContext r (
). L
<context: property-placeholder>.
@ImportResource
L-,
L Jv- ,
. XML Java
,
L-, Jv-.
182 4. Spring

@ImportResource
@Import, ,
Jv- (,
, -
..).
@Component Scan ,
Sprig .
<context: component-scan> L
r.
. @Lazy Spring
, ( ,
lazy-init="true" XML), @DependsOn Spring ,
, Spring
. @Scope
.
Jv
. , @EnaeTransactionManagement ,
Spring,
9.
@Autowired env
Environment. Environment,
Sprig. .
:
Hello from Spring Java Configuration
, message. properties.
Java XML
, Jv-
ApplicationContext, XML.
? ,
DI - XML
Jv-. , .
, : ,
,
, Jv- L-.
.

, Spring,
r. , Spring
ApplicationContext, ,
.
.
4. Spring 183

Spring
FoodProviderService,
, (kidergarten)
(high school). FoodProviderService
provideLunchSet (),
.
Food - ,
name. Food 4.49.
4.49. Food
package corn.apress.prospring4.ch4;
pulic class Food {
private String narne;
pulic Food() {

puic Food(String narne)


this.narne = narne;

puic String getNarne()


return narne;

puic void setNarne(String narne)


this.narne = narne;

4.50 FoodProviderService.
4.50. FoodProviderService
package com.apress.prospring4.ch4;
import java.util.List;
pulic interface FoodProviderService
List<Food> provideLunchSet();

, ,
.
, -
. , FoodProviderService,
,
. 4.51 4.52.
4.51. FoodProviderService
package com.apress.prospring4.ch4.kindergarten;
irnport java.util.ArrayList;
184 4. Spring
import java.util.List;
import com.apress.prospring4.ch4.Food;
import com.apress.prospring4.ch4.FoodProviderService;
puic class FoodProviderServicelmpl implements FoodProviderService
@Override
pulic List<Food> provideLunchSet() {
List<Food> lunchSet = new ArrayList<Food>();
lunchSet.add(new Food("Milk"));
lunchSet.add(new Food("Biscuits"));
return lunchSet;

4.52. FoodProviderService
package com.apress.prospring4.ch4.highschool;
import java.util.ArrayList;
import java.util.List;
import com.apress.prospring4.ch4.Food;
import com.apress.prospring4.ch4.FoodProviderService;
puic class FoodProviderServiceimpl implements FoodProviderService
@Override
puic List<Food> provideLunchSet() {
List<Food> lunchSet = new ArrayList<Food>();
lunchSet.add(new Food("Coke"));
lunchSet.add(new Food("Hamurger"));
lunchSet.add(new Food("French Fries"));
return lunchSet;

,
FoodProviderService,
. , ,
; ,
Spring.
L-.
L- ,
. 4.53 4.54
, .

4.53. L- (kindergarten-config. xml)


<?xml version="l.O" encoding= "UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi= "http://www.w.org/2001/XLSchema-instance"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
profile= "kindergarten">
4. Spring 185
<bean id="foodProviderService"
class="com.apress.prospring4.ch4.kindergarten.FoodProviderServiceimpl"/>
</beans>

4.54. L- (highschool-config. xml)


<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
profile="highschool">
<bean id="foodProviderService"
class="com.apress.prospring4.ch4.highschool.FoodProviderServiceimpl"/>
</beans>


profile="kindergarten" profile= "highschool" <beans>.
Spring , ,
. ,
, Applicati onConte xt .
4.5 5.

4.55. L-
package com.apress.prospring4.ch4;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class ProfileXmlConfigExample {
pulic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:ETA-INF/spring/*-config.xml");
ctx.refresh();
FoodProviderService foodProviderService =
ctx.getBean("foodProviderService", FoodProviderService.class);
List<Food> lunchSet = foodProviderService.provideLunchSet();
for (Food food: lunchSet) {
System.out.println("Food: "+ food.getName());

ctx.load () kindergarten-config. xrnl highschool


config.xml, .. .
profile Spring
kindergarten-config. xml, N-r
-Dspring.profiles .active= "kindergarten".
186 4. Spring

:
Food: Milk
Food: Biscuits
,
.
highschool (-Dspring. profiles. acti ve= 11 highschool 11 ); :
Food: Coke
Food: Hamburger
Food: French Fries
, , .
, ctx. getEnvironment () . setActi veProfiles (
II kinder gar ten 11) ,
, JavaConfig,
@Profile.


Spring
,
(, Maven).
/
Jv- (JAR WAR )
. Spring

, JVM.
Spring
,
JVM. , ,
(dev, hibernate), (prd, jdbc) ..,
( )
(ibernate JDBC).
.
. ,

Jv-
(,
JVM ).
.
:
,
.

Environment PropertySource

Environment. ,
Spring.
4. Spring 187
Environment
u u - .
,
, ..
Environment PropertySource Spring
u u,
. u ,
Environment,
Spring ApplicationContext.
4.56 .
4.56. Environment
package com.apress.prospring4.ch4;
import java.util.HashMap;
import java.util.Map;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.env.ConfiguraleEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutaePropertySources;
puic class EnvironmentSample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.refresh();
ConfiguraleEnvironment env = ctx.getEnvironment();
MutaePropertySources propertySources = env.getPropertySources();
= new HashMap();
appMap.put("application.home", "application_home");
propertySources.addLast(new MapPropertySource( "PROSPRING4_", ));
System.out.println("user.home: "+ System.getProperty("user.home"));
System.out.println("JAVA_HOE: "+ System.getenv("JAVA_HOME"));
System.out.println("user.home: "+ env.getProperty("user.home"));
System.out.println("JAVA_HOE: "+ env.getProperty("JAVA_HOE"));
System.out.println("application.home: "
+ env.getProperty("application.home"));

4.56 ApplicationContext
ConfiguraeEnvironment.
MutaePropertySources (
PropertySources,
). ,
MapPropertySource ( PropertySource,
) . ,
MapPropertySource MutaePropertySources
addLast ().
188 4. Spring
, :
user.home: /home/chris
JAVA : /home/chris/bin/java
user.home: /home/chris
JAVA : /home/chris/bin/java
application.home: application_ home
NM user. home
JAVA_HOME , ( System
JVM). , ,
,
Environment. ,
Environment
.
PropertySource Spring
:
JVM;
;
, .
,
, user. home, Environment
MutaePropertySources. , , -
user. home N, , .
Spring ,
Environment . 4.56
, . 4.57
( ).
4.57. Environment
package com.apress.prospring4.ch4;
import java.util.HashMap;
import java.util.Map;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.env.ConfiguraeEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutaePropertySources;
puic class EnvironmentSample {
puic static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.refresh();
ConfiguraeEnvironment env = ctx.getEnvironment();
MutalePropertySources propertySources = env.getPropertySources();
= new HashMap();
appMap.put("user.home", "application_home");
propertySources.addFirst(new MapPropertySource("PROSPRING4_AP", ));
4. Spring 189
System.out.println("user.home: " + System.getProperty("user.home"));
System.out.println("JAVA_HOME: " + System.getenv("JAVA_HOME"));
System.out.println("user.home: " + env.getProperty("user.home"));
System.out.println("JAVA_HOME: " + env.getProperty("JAVA_HOME"));

4.57 user .home


addFirst ()
MutalePropertySources.
:
user.home: /home/chris
JAVA : /home/chris/bin/java
user.home: application_home
JAVA : /home/chris/bin/java
, ..
- getProperty () getenv ()
System JVM. Environment ,
user. home ,
.

Environment .
$ { } (, $ { application. home})
Spring.
.
, AppProperty,
, .
4.58.
4.58. Spring
package com.apress.prospring4.ch4;
puic class AppProperty {
private String applicationHome;
private String userHome;
puic String getApplicationHome()
return applicationHome;

puic void setApplicationHome(String applicationHome)


this.applicationHome = applicationHome;

pulic String getOserHome()


return userHome;

puic void setOserHome(String userHome) {


this.userHome = userHome;
190 4. Spring

4.59 application. properties,


.

4.59. application.properties
application.home=application_home
user.home=/home/chris-new

,
user. home. L- Spring,
4.60 (app-context-xml. xml).

4.60. Spring
<?xml version="l.0" encoding="UTF'-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context 11
xsi:schemaLocation= 11 http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd 11 >
<context:property-placeholder location=11 classpath:application.properties 11 />
<bean id ="appProperty" class= 11 com.apress.prospring4.ch4.AppProperty 11 >
<property name="applicationHome 11 value="${application.home} 11 />
<property name=11 userHome 11 value=11 ${user.home} 11 ></property>
</bean>
</beans>

<context :property-placeholder>
Sring- Environment,
ApplicationContext. ,
AppProperty. 4.61 .

4.61. Spring
package com.apress.prospring4.ch4;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class PlaceHolderSample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF'/spring/app-context-xml.xml");
ctx.refresh();
AppProperty appProperty = ctx.getBean( appProperty", AppProperty.class);
11

System.out.println ( application.home: 1 + appProperty.getApplicationHome());


11 1

System.out.println( 11 user.home: " + appProperty.getUserHome());


4. Spring 191

:
application.home: application_home
user.home: /home/chris
, application. home
, user. home -
JVM, ,
PropertySource. Spring
application.properties,
<context :property-placeholder> local-override="true":
<context:property-placeholder local-override= "true"
location="classpath:env/application.properties"/>
local-override Spring
,
. , , user. home
application .properties:
application.home: application_home
user.home: /home/chris-new

, JSR-330
1, J 6 uu
JSR-330 ("Dependency lnjection for Java" - " Java"),
DI
JEE loC.
Spring ,
JEE 6,
JSR-330 Spring. JSR-330
Spring JEE 6
loC (, Google Guice).

JSR-330.
JSR-330 , . 4.4.
4.4. JSR-330




javax.inject javax.inject JSR-330

4.62 MessagePro vider Configurae


MessageProvider.
4.62. ConfiguraleessageProvider (JSR-330)
package com.apress.prospring4.ch4;
puic interface MessageProvider
String getMessage();
192 4. Spring
package corn.apress.prospring4.ch4;
irnport javax.inject.Inject;
irnport javax.inject.Narned;
@Narned("rnessageProvider")
pulic class ConfiguraleMessageProvider irnplernents MessageProvider
private String rnessage = "Default rnessage";
pulic ConfiguraleMessageProvider()
}
@Inject
@Narned("rnessage")
puic ConfiguraleMessageProvider(String rnessage)
this.rnessage = rnessage;

puic void setessage(String rnessage)


this.rnessage = rnessage;

@Override
puic String getMessage()
return rnessage;

, jav ax.inject,
JSR-330. @Named
. -,
( @Component @Service Spring).
@Named ( "messageProvider") , ConfiguraleMessageProvider
, messageProvider, ..
, name <bean> Spring. -,
, @Inject ,
. @Narned
, , message.
MessageRenderer StandardOutMessageRenderer
4.63 .

4.63. StandardOutessageRenderer (JSR-330)


package corn.apress.prospring4.ch4;
puic interface MessageRenderer {
void render();
void setMessageProvider(MessageProvider provider);
MessageProvider getMessageProvider();

package corn.apress.prospring4.ch4;
irnport javax.inject.Inject;
irnport javax.inject.Narned;
irnport javax.inject.Singleton;
@Narned("rnessageRenderer")
4. Spring 193
@Singleton
puic class StandardOutMessageRenderer implements MessageRenderer {
@Inject
@Named("messageProvider")
private MessageProvider messageProvider = null;
@Override
pulic void render() {
if (messageProvider == null)
throw new RuntimeException(
"You must set the property messageProvider of class:"
+ StandardOutMessageRenderer.class.getName());

System.out.println(messageProvider.getMessage());

@Override
pulic void setMessageProvider(MessageProvider provider)
this.messageProvider = provider;

@Override
puic MessageProvider getMessageProvider()
return this.messageProvider;

4.63 @Named
. @Singleton. ,
JSR-330 ,
Spring. , ,
JSR-330 , @Singleton.
Spring ,
Spring
. ,
Sprig , JSR-330.
messageProvider @Inject
,
messageProvider.
4.64 L- Spring
(app-context-annotation. xml).
4.64. L- Spring (JSR-330)
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
194 4. Spring

<context:component-scan base-package="com.apress.prospring4.ch4"/>
<bean id="message" class="java.lang.String">
<constructor-arg value="You are running JSRO!"/>
</bean>
</beans>

JSR-330 - ;
Spring.
<context: component-scan> Spring
DI , Spring JSR-330. ,
Spring message
ConfiguraleMessageProvider. 4.65 .
4.65. JSR-330
package com.apress.prospring4.ch4;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class Jsr330Example {
pulic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh() ;
MessageRenderer renderer
= ctx.getBean("messageRenderer", MessageRenderer.class);
renderer.render();

:
You are running JSRO!
JSR-330
IoC, JSR-330 (, ,
JEE 6, DI Google Guice). ,
Spring ,
JSR-330. .
@Autowired Spring
required, , Dl (
@Required
Spring), @Inject JSR-330 .
, Spring @Qualifier,

.
JSR-330
, Spring
, -.
Spring @Lazy, Spring
. JSR-330
.
4. Spring 195
Spring JSR-330 .
, - ,
.
JSR-330, ,
Spring . ,
01.
,
Sprig JSR-330, .. Spring ,
,
IoC.

, Groovy
Spring Framework 4.0
ApplicationContext
Groovy. ,
XML / .
ApplicationContext Groovy
Java GenericGroovyApplicationContext
.
Groovy Java.
4.66 J- Contact.
4.. J- Contact
package com.apress.prospring4.ch4;
pulic class Contact {
private String firstName;
private String lastName;
private int age;
puic void setFirstName(String firstName) {
this.firstName = firstName;

pulic String getFirstName()


return firstName;

puic void setLastName(String lastName)


this.lastName = lastName;

pulic String getLastName()


return lastName;

puic void setAge(int age)


this.age = age;

puic int getAge()


return age;
196 4. Spring

@Override
puic String toString()
return "First name: " + firstName + Last name: " + lastName
+ 11 Age: 1 + age;
,
1

, Jv- ,
. Jv-
, Groovy
Groovy . ,
Groovy (beans. groovy),
( 4.67).
4.67. Groovy
package com.apress.prospring4.ch4
beans {
contact(Contact, firstName: 'Chris', lastName: 'Schaefer', age: 32)

Groovy beans,
Spring.
(contact),
(Contact),
. Java,
Groovy, 4.68.
4.68. Java Groovy
package com.apress.prospring4.ch4;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericGroovyApplicationContext;
puic class GroovyBeansFromJava {
puic static void main(String[J args) {
ApplicationContext context
= new GenericGroovyApplicationContext( 11 classpath:beans.groovy 1 1);

Contact contact = context.getBean( 11 contact", Contact.class);


System.out.println(contact);

, ApplicationContext
, GenericGroovyApplicationContext
Groovy,
.
, ,
, . 4.5.
4. Spring 197
4.5. Groovy



org.codehaus.groovy groovy-all 2.2.2 Groovy

4.68 :
First name: Chris, Last name: Schaefer, Age: 32
, , Java
Groovy, :
ApplicationContext Groovy?
Groovy (GroovyConfig. groovy), 4.69.
4.69. ApplicationContext Groovy
package com.apress.prospring4.ch4
import org.springframework.context.support.GenericApplicationContext
import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader
def ctx = new GenericApplicationContext ()
def reader = new GroovyBeanDefinitionReader(ctx)
reader.beans {
contact(Contact, firstName: 'Chris', lastName: 'Schaefer', age: 32)

ctx.refresh ()
println ctx.getBean("contact")

, :
First name: Chris, Last name: Schaefer, Age: 32
GenericApplicationContext,
GroovyBeanDefin itionReader,
. , ,
J-, ApplicationContext
Contact. , !
, ,
Groovy Spring 4.
Groovy,
.
ApplicationContext, ,
, .. ,
.

Spring,
loC. ,
198 4. Spring

Spring.
loC .
,

String. ,
, ApplicationContext, i\8n,
.
, Jv-
Groovy L-r, ,
. ,
JSR-330 Spring.
, Spring Framework
DI, ,
Sprig Framework. Spring
, , ,
-.
5
-


Spring
(Dependency lnjection - DI),
Spring Framework -r
().
.
,
.
,
, ,
.

, . ,

. , ,

. ,
,
.
, -
(), .
, .
,
,
, .
, ,
. ,
,
, .
200 5. - Spring

, .
. Spring,
. ,
, Spring
. ,
.
. : .
,
AspectJ (http: / / eclipse. org / aspectj /),
,
. ,
Spring,
.
, .

, .
Spring. Spring
,
, AspectJ.
, Sprig,
, ,
Spring.
Spring. -
Spring, ,
. : JDK
CGLIB. ,
,
,
Spring.
Spring.
.
"Hel\o World!", ,
, Spring,
.
. ComposaePointcut
ControlFlowPointcut, ,
.
. Spring
.
( ProxyFactoryBean,
@AspectJ)
,
, ,
.
5. - Spring 201
AspectJ. AspectJ
. AspectJ Spring
, AspectJ
( , ),
Spring . AspectJ
, Spring,
Spring. AspectJ ,
, Spring ,
.


,
, .
.
. Uoipoint) -
.
, (Method Invocation),
.
,
.
. ,
, (advice), .
, ,
, ,
.
. (pointcut) - ,
, .
, ,
. ,

. ,
, .
. (aspect) - ,
. ,
, , .
. (weaving)
.
.

. AspectJ
, (load-time
weaving - LTW),
JVM -,
.
202 5. - Spring
. (target) - ,
- . ,
.
. (introduction) ,

.

, .
, ;
, . , ,
, Spring,
, - Spring
.
Spring.


, : .
, ,
, .



. Java
-
, .
,
- Java,
, , .
, ,
,
, .
AspectJ.


, Spring,
,
. , , ,
Spring
, .
, ,
, .


.
5. - Spring 203


- .
,
- .

. ,
,
Spring , AspectJ.
Spring . , ,
, , Sprig
, ,
.
,
,
. Spring
, AspectJ,
.

Spring
Spring
, - ,
, ( Spring
[). - ,
. Spring,
EJB,
, .


(ht tp: // aopalliance. sourceforge. net/)

. ,
, Spring
, .
,
.
"Hello World!"
, Spring,
. , "World",
,
"Hello World!". MessageWriter
5.1.
204 5. - Spring

5.1. MessageWri ter


package com.apress.prospring4.ch5;
puic class MessageWriter {
puic void writeMessage() {
System.out.print("World");

,
, wri teMessage () "Hello World!".
,
( "Hello "),
- ( "!"). ,
.
writeMessage (). 5.2
MessageDecorator, "".

5.2. ""
package com.apress.prospring4.ch5;
import org.aopalliance.intercept.Methodinterceptor;
import org.aopalliance.intercept.Methodinvocation;
puic class MessageDecorator implements Methodinterceptor
@Override
puic Object invoke(Methodinvocation invocation) throws Throwae
System.out.print("Hello ");
Object retVal: invocation.proceed();
System.out.println("!");
return retVal;

Methodinterceptor -
"" .
Methodinvocation , ,
, .
"",
, , .
5.2 "Hello ",
Methodinvocation. proceed ()
"!".
MessageDecorator
( - invoke ()) .
MessageWriter, .. , ,
MessageDecorator.
5.3 .
5. - Spring 205
5.. MeageDecorator
package com.apress.prospring4.ch5;
import org.springframework.aop.framework.ProxyFactory;
pulic class HelloWorldAOPExample {
puic static void main( String [] args) {
MessageWriter target = new MessageWriter();
ProxyFactory pf = new ProxyFactory();
pf.addAdvice(new MessageDecorator());
pf.setTarget(target);
MessageWriter proxy = (MessageWriter) pf.getProxy();
target.writeMessage();
System.out.println("");
proxy.writeMessage();

, ,
ProxyFactory
. MessageDecorator ProxyFactory
addAdvice (),
setTarget (). , ,
ProxyFactory, getProxy () . ,
writeMessage () -.
5.3 :
World
Hello World !
, writeMessage ()

. MessageDecorator,
"Hel\o World!".
Spring ;
Spring , , ,
,
. , , Spring,
,
, , .

Spring
Spring .
, ,
ProxyFactory ,
ProxyFactory , .
ProxyFactory -
.
; -
206 5. - Spring

, Spring ( ProxyFactoryBean,
@AspectJ),
. , , ,
,
Spring.
Spring
, ApplicationContext,
- (
).
-. - (..
, ) .
. 5.1 Spring .

-
(
Spring R R)



______ ,..._ - - - - - - - - -

. 5. 1. Spring
Spring :
JDK CGLI. , , ,
- ,
Spring JDK. ,
, (, - ,
),
CGLI. ,
JDK .
" " .
Spring
Spring
: . ,
,
, AspectJ,
, Spring .
5. - Spring 207

(Method lnvocation)
,
,
. ,
, ,
Spring AspectJ .
Spring
Spring l(Jlacca,
Advisor. Spring
Advisor, ,
Advisor.
Advisor: IntroductionAdvisor PointcutAdvisor.
PointcutAdvisor Advisor,
.
Spring ,
IntroductionAdvisor l(Jlacca,
.
PointcutAdvisor
" Spring" .
ProxyFactory
ProxyFactory
Spring. 1 ,
. ,
setTarget (). ProxyFactory
DefaultAopProxyFactory, , ,
Cglib2AopProxy, JdkDynamicAopProxy,
.
.
ProxyFactory addAdvice (),
5.3, ,
, . addAdvice ()
Defaul tPointcutAdvisor,
PointcutAdvisor, ,
l(JI .
Advisor ,
Advisor addAdvisor ()
ProxyFactory.
ProxyFactory
, . ,
ProxyFactory removeAdvice () removeAdvisor (),
ProxyFactory Advisor,
. , ProxyFactory
, adviceincluded (),
.
208 5. - Sprig

Spring
Spring ,
. 5.1.
5.1. Spring


org.springframework. "",
(before) aop.MethodeforeAdvice
. Spring
- ,

.
""
, ,
,
.
""
,
( )
,

org.springframework.aop " "
.AfterReturningAdvice
(after . "
returning) " ,
, ,
.
,
,
.
, " "
,

org.springframework. " "
(after aop.AfterAdvice ,
(finally)) . ""

, .
,
, ,

org.aopalliance. Spring ""
(around) intercept. n-
Methodinterceptor .
,
,
.
,

5. - Spring 209
. 5. 1



org.springframework. ""
(throws) aop.ThrowsAdvice , ,

.
,
,
, ,
,
org.springframework.aop. Spring
(introduction) Introductioninterceptor .
,
,


ProxyFactory,
addAdvice () ,
Advisor addAdvisor ().
Advice Advisor , Advisor Advice
Pointcut, ,
Advice . Spring
.
. 5.2.

<<interface>>
org.aopalliance.aop.Advice

interface interface <<interface>>


org.springframework.aop.AfterReturningAdvice org.aopalliance.intercept.lnterceptor org.springframework.aop.Beforedvice

<<interface>>
<<interface>>
org.aopalliance.intercept.Methodlnterceptor
org.springframework.aop.MethodBeforeAdvice
+invoke( invocation : Methodlnvocator) : Object

. 5.2. , Spring
210 5. - Spring

-
,
, , addAdvice ()
ProxyFactory,
ProxyFactory.
""
"" ,
Spring. , ,
r .
"":
, , ,
.
5.4 SimpleBeforeAdvice.
5.4. SimpleBeforeAdvice
package com.apress.prospring4.ch5;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
puic class SimpleBeforeAdvice implements MethodBeforeAdvice
pulic static void main(String (] args) {
MessageWriter target = new MessageWriter();
ProxyFactory pf = new ProxyFactory();
pf.addAdvice(new SimpleBeforeAdvice());
pf.setTarget(target);
MessageWriter proxy = (MessageWriter) pf.getProxy();
proxy.writeMessage();

@Override
pulic void before(Method method, Object(] args, Object target)
throws Throwae {
System.out.println("Before method: " + method.getName());


MessageWriter SimpleBeforeAdvice.
MethodBeforeAdvice, SimpleBeforeAdvice,
before (),
. ,
, addAdvice (),
. before () :
, , r , Object,
. SimpleBeforeAdvice Method
before () ,
.
5. - Spring 211

:
Before method: writeMessage
World
, , wri teMessage (), ,
, SimpleBeforeAdvice.
''"
"",
,
. , ,
. , ,
.

. ,
,
.

! "".
, Spring,
Spring Security,
.

5.5 SecureBean.
.

5.5. SecureBean
package com.apress.prospring4.ch5;
puic class SecureBean {
puic void writeSecureMessage()
System.out.println("Every time I learn something new, "
+ "it pushes some old stuff out of my brain");

SecureBean ,
.
, ,
. 5.6 Userinfo,
.

5.6. User!nfo
package com.apress.prospring4.ch5;
pulic class Userinfo {
private String userName;
private String password;
212 5. - Spring

puic Userinfo(String userName, String password) {


this.userName = userName;
this.password = password;

puic String getPassword()


return password;

puic String getUserName()


return userName;

,
- . 5.7
SecurityManager,
.
5.7. Securityanager

package com.apress.prospring4.ch5;
puic class SecurityManager {
private static ThreadLocal<Userinfo> threadLocal =
new ThreadLocal<Userinfo>();
puic void login(String userName, String password)
threadLocal.set(new Userinfo(userName, password));

puic void logout() {


threadLocal.set(null);

puic Userinfo getLoggedOnUser()


return threadLocal.get();

SecurityManager
,
. login ().
login ()
LDAP, ,
. login () Userinfo
ThreadLocal. logout ()
null , ThreadLocal. ,
getLoggedOnUser () Userinfo
. ,
null.
5. - Spring 213
, , ,
SecureBean, ,
Userlnfo,
SecurityManager. getLoggedOnUser (),
. SecurityAdvice, ,
5.8.

5.8. Securi tyAdvice


package com.apress.prospring4.ch5;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
puic class SecurityAdvice implements MethodBeforeAdvice
private SecurityManager securityManager;
puic SecurityAdvice() {
this.securityManager = new SecurityManager();

@Override
puic void before(Method method, Object[] args, Object target)
throws Throwae {
Userinfo user = securityManager.getLoggedOnUser();
if (user == null) {
System.out. println( 1 No user authenticated 11
1 );

throw new SecurityException(


"You must login before attempting to invoke the method: 1 1

+ method.getName());
else if ( chris equals( user.getUserName()))
11 11

System.out.println( 1 Logged in user is chris - ! ") ;


1

else {
System.out.println( "Logged in user is + user.getUserName()
11

+ NOT GOOD : ( ") ;


11

throw new SecurityException( "User 1 + user.getUserName()


1

+ " is not allowed access to method " + method. getName()) ;

SecurityAdvice SecurityManager
. ,
SecurityAdvice
SecurityManager, ..
ThreadLocal. before () ,
chris . ,
, .
, Userlnfo
null, , .
5.9 ,
SecurityAdvice SecureBean.
214 5. - Spring

5.9. Securi tyExample


package com.apress.prospring4.ch5;
import org.springframework.aop.framework.ProxyFactory;
pulic class SecurityExample {
pulic static void main (String [] args) {
SecurityManager mgr = new SecurityManager();
SecureBean bean = getSecureBean();
mgr.login("chris", "pwd");
bean.writeSecureMessage();
mgr.logout();
try {
mgr.login ("invaliduser", "pwd");
bean.writeSecureMessage();
catch(SecurityException ) {
System.out.println("Exception Caught: " + ex.getMessage());
finally {
mgr.logout();

try {
bean.writeSecureMessage();
catch(SecurityException ) {
System.out.println("Exception Caught: " + .getMessage());

private static SecureBean getSecureBean() {


SecureBean target = new SecureBean();
SecurityAdvice advice = new SecurityAdvice();
ProxyFactory factory = new ProxyFactory();
factory.setTarget(target);
factory.addAdvice(advice);
SecureBean proxy = (SecureBean)factory.getProxy();
return proxy;

getSecureBean () SecureBean,
Securi tyAdvice.
.
,
Secur i tyAdvice ,
. main () , SecureBean.
wri teSecureMessage ()
. SecurityAdvice
,
chris, , 5.9
. :
5. - Spring 215
Logged in user is chris - !
Every time I learn something new, it pushes some old stuff out of my brain
Logged in user is invaliduser NOT GOOD: (
Exception Caught: Oser invaliduser is not allowed access to method
writeSecureMessage
No user authenticated
: invaliduser
writeSecureessage

Exception Caught: You must login before attempting to invoke the method:
writeSecureMessage
: , i
: writeSecureMessage
, SecureBean. writeSecureMessage ()
.
SecurityException, SecurityAdvice.
, "".
- "",
, , .
" "
" " ,
. , ,
. ,
,
. ; ,
, " "
. " "
. " "
,
, .
"
" .
. ,
" " .
, KeyGenerator,
. -
, ,
. - ,
, . DES
256 . 4
, 12 - .
(1 252),
, , , .
" ", ,
KeyGenerator,
.
216 5. - Spring

!
Applied Cryptography (Wiley, 1996 .).

5.10 SimpleAfterReturningAdvice,
" "
.
5.1 . SimpleAfterReturningAdvice
package com.apress.prospring4.ch5;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.framework.ProxyFactory;
pulic class SimpleAfterReturningAdvice implements AfterReturningAdvice
puic static void main(String[] args) {
MessageWriter target = new MessageWriter();
ProxyFactory pf = new ProxyFactory();
pf.addAdvice(new SimpleAfterReturningAdvice());
pf.setTarget(target);
MessageWriter proxy = (MessageWriter) pf.getProxy();
proxy.writeMessage();

@Override
pulic void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwae {
System.out.println("");
System.out.println("After method: " + method.getName());

, AfterReturningAdvice
afterReturning (),
, , , ,
. :
World
After method: writeMessage
, "",
, , ,
writeMessage ().
" "
, , ,
.
, .

, ,
. " ",
.
5. - Spring 217
5.11 .
5.11. KeyGenerator
package com.apress.prospring4.ch5;
import java.util.Random;
puic class KeyGenerator
protected static final long WEAK_KEY = OxFFFFFFFOOOOOOOL;
protected static final long STRONG_KEY = OxACDFOF590AE56L;
private Random rand = new Random ();
pulic long getKey () {
int = rand.nextint();
if ( == 1) {
return W ;

return STRONG ;

.
,
. 5.12 WeakKeyCheckAdvice,
, , getKey (), t.
5.12.
package com.apress.prospring4.ch5;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
puic class WeakKeyCheckAdvice implements AfterReturningAdvice
@Override
puic void afterReturning(Object returnValue, Method method,
Object[] args,Object target) throws Throwae {
if ((target instanceof KeyGenerator)
&& ("getKey".equals(method.getName()))) {
long key = ((Long) returnValue).longValue();
if (key == KeyGenerator.WEAK_KEY) {
throw new SecurityException(
" Generator generated weak key. Try again");
/ / . .

afterReturning () , ,
, getKey (). ,
. -
218 5. - Spring
, getKey () - ,
SecurityException, .
5.13 , .
5.13. WeakeyCheckAdvice
package com.apress.prospring4.ch5;
import org.springframework.aop.framework.ProxyFactory;
pulic class AfterAdviceExample {
private static KeyGenerator getKeyGenerator()
KeyGenerator target = new KeyGenerator();
ProxyFactory factory = new ProxyFactory();
factory.setTarget(target);
factory.addAdvice(new WeakKeyCheckAdvice());
return (KeyGenerator)factory.getProxy();

pulic static void main(String [ J args) {


KeyGenerator keyGen = getKeyGenerator();
for(int = ; < 10; ++) {
try {
long key = keyGen.getKey();
System.out.println("Key: " + key);
catch(SecurityException ) {
//
System.out.println("Weak Generated!");

KeyGenerator
AfterAdviceExample .
SecurityException,
, ,
; .
:
: 48658904092028502
: 48658904092028502
: 48658904092028502
Weak Generated!
: 48658904092028502
: 48658904092028502
: 48658904092028502
Weak Generated !
: 48658904092028502
: 48658904092028502
, KeyGenerator, ,
, WeakKeyCheckAdvice ,
SecurityException.
5. - Spring 219
"r"
"" "" "",
-
. ,
. , ""
. "" Sprig
Methodinterceptor.
, ,
Spring,
, .
I
, .
I ,
5.2,

. , invoke () Methodinterceptor
,
MethodBeforeAdvice AfterReturningAdvice, ..
, . ,
Methodinvocation,
invoke (). .

, , ,
. StopWatch,
Spring, , , , Methodinterceptor, ..
StopWatch StopWatch
.
5.14 WorkerBean,
StopWatch "".
5.14. WorkerBean
package com. apress.prospring4.ch5;
pulic cla ss WorkerBean {
puic void doSomeWork(int noOfTimes)
for(int = ; < noOfTimes; ++) {
work();

priva te void work()


System. out.print("");

, WorkerBe an . doSomeWork ()
noOfTimes work ()
noOfTimes . work ()
220 5. - Spring

System.out.print () .
,
work () , , .
5.15 Profilinginterceptor,
StopWatch .ll.lI .
/I WorkerBean, 5.14.

5.15. Profilinginterceptor
package com.apress.prospring4.ch5;
import java.lang.reflect.Method;
import org.aopalliance.intercept.Methodinterceptor;
import org.aopalliance.intercept.Methodinvocation;
import org.springframework.util.StopWatch;
puic class Profilinginterceptor implements Methodinterceptor
@Override
puic Object invoke(Methodinvocation invocation) throws Throwae
StopWatch sw = new StopWatch();
sw.start(invocation.getMethod().getName());
Object returnValue = invocation.proceed();
sw.stop();
dumpinfo(invocation, sw.getTotalTimeMillis());
return returnValue;

private void dumpinfo(Methodinvocation invocation, long ms) {


Method m = invocation.getMethod();
Object target = invocation.getThis();
Object[J args = invocation.getArguments();
System.out.println("Executed method: " + m.getName());
//
System.out.println("On object of type: " +
target.getClass().getName()); //
System.out.println("With arguments:"); //
for (int = ; < args.length; ++) {
System.out.print(" > " + args (]);

System.out.print("\n");
System.out.println("Took: " + ms + " ms"); //

i nvoke (),
Methodinterceptor, StopWatch ,
Methodinvocation.
proceed ().
StopWatch
Methodinvocation dumpinfo (). ,
Obj ect, Methodinvocation. proceed (),
5. - Spring 221
.
- ;
. ,
,
.
dumpinfo ()
, ,
. dumpinfo () ,
Methodinvocation , ,
.
5.16 ProfilingExample,
WorkerBean Profilinginterceptor
doSomeWork ().
5.16. ProfilingExample
package com.apress.prospring4.ch5;
import org.springframework.aop.framework.ProxyFactory;
puic class ProfilingExample {
puic static void main(String[] args)
WorkerBean bean = getWorkerBean();
bean.doSomeWork(lOOOOOOO);

private static WorkerBean getWorkerBean()


WorkerBean target = new WorkerBean();
ProxyFactory factory = new ProxyFactory();
factory.setTarget(target);
factory.addAdvice(new Profilinginterceptor());
return (WorkerBean)factory.getProxy();

:
Executed method: doSomeWork
On object of type: com.apress.prospring4.ch5.WorkerBean
With arguments:
> 10000000
Took: 477 ms
, , ,
, .
""
"" " " ,
, , ""
, . ""
" " ,
. "" r-
222 5. - Spring

- .
, ,
. ,
. ,
l-,
. ""
J- -
. , ""
,
, .
. 5.2, ""
ThrowsAdvice. , ,
ThrowsAdvice ;
, Spring.
, Spring "",
, .
Spring
. Spring .
. 5.17
, .
5.17. ErrorBean

package com.apress.prospring4.ch5;
puic class ErrorBean {
puic void errorProneMethod() throws Exception {
throw new Exception("Foo");

puic void otherErrorProneMethod() throws IllegalArgumentException


throw new IllegalArgumentException( "Bar");

5.18 SirnpleThrowsAdvice,
, Spring "".
5.18. SimpleThrowsAdvice
package com.apress.prospring4.ch5;
import java.lang.reflect.Method;
import org.springframework.aop.ThrowsAdvice;
import org.springframework.aop.framework.ProxyFactory;
puic class SimpleThrowsAdvice implements ThrowsAdvice
puic static void main(String(] args) throws Exception
ErrorBean errorBean = new ErrorBean();
ProxyFactory pf = new ProxyFactory();
pf.setTarget(errorBean);
pf.addAdvice(new SimpleThrowsAdvice());
5. - Spring 223
ErrorBean proxy = (ErrorBean) pf.getProxy();
try {
proxy.errorProneMethod();
catch (Exception ignored) {

try
proxy.otherErrorProneMethod();
catch (Exception ignored) {

@Override
pulic void afterThrowing(Exception ) throws Throwae
System.out.println("***");
System.out.println("Generic Exception Capture");
//
System.out.println("Caught: " + ex.getClass() .getName());
//
System.out.println("***\n");

@Override
puic void afterThrowing(Method method, Object[] args, Object target,
IllegalArgumentException ) throws Throwae {
System.out.println("***");
System.out.println("IllegalArgumentException Capture");
// IllegalArgumentException
System.out.println("Caught: " + ex.getClass().getName());
//
System.out.println("Method: " + method.getName()); //
System.out.println("***\n");

, Spring "" -
afterThrowing (). ,
, void,
. afterThrowing ()
SimpleThrowsAdvice Exception.
, ,
, ,
. , Exception
Exception,
afterThrowing ().
afterThrowing ()
, , ,
, . ,
. ,
afterThrowing () IllegalArgumentException
( ). :
224 5. - Spring
***
Generic Exception Capture
Caught: java.lang.Exception
***
***
IllegalArgumentException Capture
Caught: java.lang.IllegalArgumentException
Method: otherErrorProneMethod
***
, Exception,
afterThrowing (), IllegalArgumentException
afterThrowing (). Spring
afterThrowing () , ,
5.18, Spring ,
. ,
"" afterThrowing (),
Exception, ,
- , Spring afterThrowing ()
.
"" ;
,
. , , "
" , ..
, .

,
. ,
"", "".
"" ,
, .
, ,
. ,
.
"",
, ""
.
.
, .

Spring
, ,
ProxyFactory. addAdvice (). " "
addAdvisor (),
DefaultPointcutAdvisor ,
.
. , , , -
5. - Spring 225
, ,
, .
, , ,
, .
,
.
, ,
; .

. ,
, .
. ,
,
.
,
, , Spring
, , .
, , .

, , ,
.
,
. " ",
,
KeyGenerator. , ,
, .
.
,
- ..
. ,
;
, .
.
, ,
.
Poin t.cu t.
Spring Pointcut,
5.19.
5.19. Pointcut
package org.springframework.aop;
pulic interface Pointcut {
ClassFilter getClassFilter ();
Methoc!atcher getMethoc!atcher();
226 5. - Spring

, Pointcut ,
getClassFil ter () getMethodMatcher (),
ClassFilter MethodMatcher. ,
Pointcut, . ,
, , Spring
Pointcut, , ,
.
, Pointcut ,
Spring , Pointcut ,
ClassFilter, Pointcut. getClass
Filter (). ClassFilter 5.20.
5.20. ClassFilter
org.springframework.aop;
puic interface ClassFilter {
boolean matches(Class<?> clazz);

, ClassFilter matches (),


Class, ,
. matches () true, ,
false - .
Methodatcher ClassFilter;
5.21.
5.21. Methodatcher
package org.springframework.aop;
puic interface Methodatcher {
boolean matches(Method m, Class<?> targetClass);
boolean isRuntime();
boolean matches(Method m, Class<?> targetClass, Object[J args);

Spring MethodMatcher,
, isRuntime ().
MethodMatcher Spring isRuntime ()
, Methodatcher ,
false, , true.
Spring matches (Method, Class<T>)
MethodMatcher ,
.
,
, matches ().
Spring -
matches (Method, Class<T>) ,
.
, true, Spring -
5. - Spring 227
, matches (Method,
Class<T>, Obj ect [] ) . , Methodatcher
, , ,
. , ,
Integer, 100.
matches (Method, Class<T>, Obj ect [ J )
.
, ,
.. .
, .
,
. ,
,
.

Pointcut , Spring
, . ,
Pointcut, .
Pointcut
Spring 4.0 Pointcut:
,
, ,
:
;
;
;
;
AspectJ;
,
.
. 5.2 Pointcut.
5.2. Pointcut

org.springframework. , Jv
aop.support.annotation. .
AnnotationatchingPointcut JDK 5
org.springframework.aop.aspectj. ,
AspectJExpressionPointcut AspectJ ,
AspectJ
org.springframework.aop. ComposaePointcut
support.ComposalePointcut
, union () intersection ()
228 5. - Spring

. 5.2

org.springframework.aop. ControlFlowPointcut ,
support.ControlFlowPointcut ,

- . . ,


org.springframework.aop.support. DynamicMethodatcherPointcut
DynamicMethodatcherPointcut
org.springframework.aop. JdkRexepMethodPointcut
support.JdkRegexpMethodPointcut
JDK 1.4.
JDK 1.4
org.springframework.aop. NameMatchethodPointcut
support.NameMatchMethodPointcut ,

org.springframework.aop.support. StaticMethodatcherPointcut
StaticMethodatcherPointcut

. 5.3 U L rI Pointcut.
DynamicMethodMatcherPointcut

MethodMatcher ExpressionPointcut

StaticMethodMatcherPointcut AnnotationMatchingPointcut AbstractExpressionPointcut

AbstractRegexpMethodPointcut NameMatchMethodPointcut

AspectJExpressionPointcut

JdkRegexpMethodPointcut

. 5.3. Pointcut
5. - Spring 229
Defaul tFointcutAdvisor
Pointcut,
Advisor , , PointcutAdvisor.
n ( " Spring"), Advisor
Spring - ,
, ,
. Spring PointcutAdvisor,
- DefaultPointcutAdvisor.
DefaultPointcutAdvisor - PointcutAdvisor
Pointcut Advice.

StaticethodatcherPointcut
,
StaticMethodMatcherPointcut. StaticMethod
MatcherPointcut StaticMethodMatcher ( ),
MethodMatcher,
matches (Method, Class<?>); Pointcut
.
, (
StaticMethodMatcherPointcut),
getClassFilter (), ,
.
, BeanOne BeanTwo,
. 5.22 BeanOne.

5.22. BeanOne
package com.apress.prospring4.ch5;
pulic class BeanOne {
puic void foo() {
System.out.println("foo");

puic void bar () {


System.out.println("bar");

BeanTwo , BeanOne.
,
DefaultPointcutAdvisor, foo ()
BeanOne. , SimpleStaticPointcut,
5.23.
230 5. - Spring

5.23. SimpleStaticPointcut
package com.apress.prospring4.ch5;
import java.lang.reflect.Method;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.StaticMethodatcherPointcut;
puic class SimpleStaticPointcut extends StaticMethodatcherPointcut
@Override
puic boolean matches(Method method, Class<?> cls)
return ("foo".equals(method.getName()));

@Override
puic ClassFilter getClassFilter (}
return new ClassFilter() {
pulic boolean matches(Class<?> cls)
return (cls == BeanOne.class);

};

matches (Method, Class<?>)


StaticMethodatcher. true,
foo, false - .
, getClassFilter () ;
ClassFilter, matches () true
BeanOne.
BeanOne , , foo () .
5.24 SimpleAdvice,
.
5.24. SimpleAdvice
package com.apress.prospring4.ch5;
import org.aopalliance.intercept.Methodinterceptor;
import org.aopalliance.intercept.Methodinvocation;
puic class SimpleAdvice implements Methodinterceptor
@Override
puic Object invoke(Methodlnvocation invocation) throws Throwale {
System.out.println(">> Invoking " + invocation.getMethod() .getName());
Object retVal = invocation.proceed();
System.out.println(">> Done");
return retVal;

5.25
, DefaultPointcutAdvisor
SimpleAdvice SimpleStaticPointcut.
5. - Spring 231
5.25. StaticPointcutExample
package com.apress.prospring4.ch5;
import org.aopalliance.aop.Advice;
import org.springframework.aop.Advisor;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
puic class StaticPointcutExample {
puic static void main(String[J args) {
BeanOne one = new BeanOne();
BeanTwo two = new BeanTwo();
BeanOne proxyOne;
BeanTwo proxyTwo;
Pointcut = new SimpleStaticPointcut();
Advice advice = new SimpleAdvice();
Advisor advisor = new DefaultPointcutAdvisor(pc, advice);
ProxyFactory pf = new ProxyFactory();
pf.addAdvisor(advisor);
pf.setTarget(one);
proxyOne = (BeanOne)pf.getProxy();
pf = new ProxyFactory();
pf.addAdvisor(advisor);
pf.setTarget(two);
proxyTwo = (BeanTwo)pf.getProxy();
proxyOne.foo();
proxyTwo.foo();
proxyOne.bar();
proxyTwo.bar();

, DefaultPointcutAdvisor
: BeanOne BeanTwo.
, foo () bar () .
:
>> Invoking foo
foo
>> Done
foo
bar
bar
, , SirnpleAdvice,
foo () BeanOne, . ,
, ,
,
.
232 5. - Spring

,,
Dynamicethoda tcherPoin tcu t

,
, 5.26.
5.26. SampleBean
package com.apress.prospring4.ch5;
puic class SampleBean {
puic void foo (int ) {
System.out.println("Invoked foo() with: " + );

puic void bar () {


System.out.println ("Invoked bar()");

foo (),
, , int
, 100.
,
Spring - DynamicMethodMatcherPointcut.
matches (Method, Class<?>,
Object []) ( MethodMatcher),
, , ,
matches (Method, Class<?>) .
SimpleDynamicPointcut 5.27.
5.27. SimpleDynamicPointcut
package com.apress.prospring4.ch5;
import java.lang.reflect.Method;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.DynamicMethodatcherPointcut;
pulic class SimpleDynamicPointcut extends DynamicMethodatcherPointcut
@Override
pulic boolean matches(Method method, Class<?> cls) {
//
System.out.println("Static check for " + method.getName());
return ("foo".equals(method.getName()));

@Override
pulic boolean matches(Method method, Class<?> cls, Obj ect [] args)
//
System.out.println("Dynamic check for " + method.getName());
int = ((Integer) args[O]).intValue();
return ( != 100);
5. - Sprig 233
@Override
puic ClassFilter getClassFilter() {
return new ClassFilter() {
puic boolean matches(Class<?> cls)
return (cls == SampleBean.class);

};

, 5.27, ,
getClassFilter () 5.23.

- , .
,
. , , , bar ()
.
, Spring
. ,
, Spring ,
, .
,
. , Spring
bar ().
getClassFilter (), -
matches (Method, Class<?>) - matches (Method,
Class<?>, Object []).
, .
matches (Method, Class<?>, Object []) true,
, int foo (), 100, false -
. ,
, foo () ,
.
5.28 .
5.28. DynamicPointcutExample
package com.apress.prospring4.ch5;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
pulic class DynamicPointcutExample {
puic static void main (String [ J args) {
SampleBean target = new SampleBean();
Advisor advisor = new DefaultPointcutAdvisor(
new SimpleDynamicPointcut(), new SimpleAdvice());
ProxyFactory pf = new ProxyFactory ();
pf.setTarget(target);
pf.addAdvisor(advisor);
SampleBean proxy = (SampleBean)pf.getProxy();
234 5. - Spring
proxy.foo(l);
proxy.foo(lO);
proxy.foo(lOO);
proxy.bar();
proxy.bar();
proxy.bar();

, ,
.
foo ().
foo (),
bar (). :
Static check for foo
Static check for bar
Static check for toString
Static check for clone
Static check for foo
Dynamic check for foo
>> Invoking foo
Invoked foo() with: 1
>> Done
Dynamic check for foo
>> Invoking foo
Invoked foo() with: 10
>> Done
Dynamic check for foo
Invoked foo() with: 100
Static check for bar
Invoked bar()
Invoked bar()
Invoked bar()
,
foo (). , bar (),
bar () .
, foo () :
, , .
,
, , -

.


, .
StaticMethodMatcherPointcut
NameMatchMethodPointcut ( StaticMethodMatcherPointcut)
.
5. - Sprig 235
NameMatchMethodPointcut,
, , , foo () foo ( int),
foo.
5.29 .

5.29. NameBean
paekage eom.apress.prospring4.eh5;
pulie elass NarneBean {
pulic void foo() {
System.out.println("foo");

puic void foo(int ) {


System.out.println("foo " + );

pulie void bar() {


System.out.println("bar");

puic void yup() {


System.out.println("yup");


foo (), foo ( int) bar () NameMatchMethodPointcut;
foo bar. 5.30.

5.30. NameatchethodPointcut
package com.apress.prospring4.ch5;
import org.springfrarnework.aop.Advisor;
import org.springframework.aop.framework.ProxyFaetory;
import org.springfrarnework.aop.support.DefaultPointcutAdvisor;
import org.springfrarnework.aop.support.NarneMatchethodPointcut;
puie elass NamePointcutExarnple {
puie static void main(String [] args) {
NameBean target = new NameBean();
NameMatchMethodPointcut = new NarneMatchMethodPointcut();
.addethodNarne("foo");
.addethodNarne("bar");
Advisor advisor = new DefaultPointcutAdvisor(pc, new SimpleAdviee());
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
NarneBean proxy = (NameBean)pf.getProxy();
proxy.foo();
proxy.foo(999);
proxy.bar();
proxy.yup();
236 5. - Spring

;
NarneMatchethodPointcut. ,
, foo bar, addMethodName ().
:
>> Invoking foo
foo
>> Done
>> Invoking foo
foo 999
>> Done
>> Invoking bar
bar
>> Done
yup
, foo (), foo ( int) bar ()
, yup () .

,
. ,
, ,
? , ,
get?
JdkRegexpMethodPointcut,
.
5.31 .
5.31. RegexpBean
package com.apress.prospring4.ch5;
puic class RegexpBean {
pulic void fool() {
System.out.println("fool");

puic void foo2() {


System.out.println("foo2");

puic void bar() {


System.out.println("bar");

,
, foo.
5.32.
5.32.
package com.apress.prospring4.ch5;
import org.springframework.aop.Advisor;
5. - Spring 237
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
puic class RegexpPointcutExample {
puic static void main (String [] args) {
RegexpBean target = new RegexpBean();
JdkRegexpMethodPointcut = new JdkRegexpMethodPointcut();
pc.setPattern(".*foo.*");
Advisor advisor = new DefaultPointcutAdvisor(pc, new SimpleAdvice());
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
RegexpBean proxy = (RegexpBean) pf.getProxy();
proxy.fool ();
proxy.foo2();
proxy.bar();

, ;
JdkRegexpMethodPointcut
. , .
Sprig , .. fool ()
com. apress. prospring4. chS. RegexpBean. fool,
. * . ,

,
. :
>> Invoking fool
fool
>> Done
>> Invoking foo2
foo2
>> Done
bar
, fool ()
foo2 (), .. bar () .
AspectJ
JDK
AspectJ. ,
L-
Spring AspectJ. ,
Spring @AspectJ,
AspectJ. ,

AspectJ. Spring AspectJExpressionPointcut
AspectJ. -
238 5. - Spring

AspectJ Spring
AspectJ - aspectjrt.jar aspectjweaver.jar.
, . 5.3.
5.3. Maven AspectJ


org.aspectj aspectjrt 1.7.4 (1.8..1 Java 8)
AspectJ
org.aspectj aspectjweaver 1.7.4 (1.8.0.1 Java 8)
AspectJ


JDK ,
AspectJ. 5.33 , ,
5.31; .
5.33. AspectjexpBean
package com.apress.prospring4.ch5;
puic class AspectjexpBean {
puic void fool() {
System.out.println("fool");

puic void foo2() {


System.out.println("foo2");

puic void bar() {


System.out.println("bar");

, AspectJ,
, ,
foo. 5.34.
5.34. AspectJ
package com.apress.prospring4.ch5;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
puic class AspectjexpPointcutExample {
puic static void main(String[J args) {
AspectjexpBean target = new AspectjexpBean();
AspectJExpressionPointcut = new AspectJExpressionPointcut();
pc.setExpression("execution(* foo*(..))");
Advisor advisor = new DefaultPointcutAdvisor(pc, new SimpleAdvice());
5. - Spring 239
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
AspectjexpBean proxy = (AspectjexpBean) pf.getProxy();
proxy.fool();
proxy.foo2();
proxy.bar();

setExpression () AspectJExpression
Pointcut .
"execution (* foo* ( ..) ) " ,
, , foo,
.
,
JDK.
,
,
, ..
. Spring
AnnotationMatchingPointcut
. ,
.
AdviceRequired,
, .
5.35.
5.35.
package com.apress.prospring4.ch5;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
pulic @interface AdviceRequired {
}


@interface , @Target ,
@AdviceRequired ,
.
5.36 @AdviceRequired.
240 5. - Spring
5.36. SampleAnnotationean
package com.apress.prospring4.ch5;
puic class SampleAnnotationBean
@AdviceRequired
puic void foo(int ) {
System.out.println("Invoked foo() with: " +);

puic void bar() {


System.out.println("Invoked bar()");

foo () @Advice
Required .
5.37 .
5.37. ,
package com.apress.prospring4.ch5;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.annotation.
AnnotationMatchingPointcut;
puic class AnnotationPointcutExample {
puic static void main(String [] args)
SampleAnnotationBean target = new SampleAnnotationBean();
AnnotationMatchingPointcut = AnnotationMatchingPointcut
.forMethodAnnotation(AdviceRequired.class);
Advisor advisor = new DefaultPointcutAdvisor(pc, new SimpleAdvice());
ProxyFactory pf = new ProxyFactory ();
pf.setTarget(target);
pf.addAdvisor(advisor);
SampleAnnotationBean proxy = (SampleAnnotationBean) pf.getProxy();
proxy.foo(lOO);
proxy.bar();

AnnotationatchingPointcut
forMethodAnnotation (),
. , ,
.
, forClassAnnotation (). ,
:
>> Invoking foo
Invoked foo() with: 100
>> Done
Invoked bar()
5. n- Spring 241
, foo () ,
.

Advisor
Pointcut Spring
Advisor, .
, NameMatchMethod
Pointcut Defaul tPointcutAdvisor
NameMatchMethodPointcutAdvisor ( 5.38).

5.38. NameatchethodPointcutAdvisor
package com.apress.prospring4.ch5;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.NameMatchMethodPointcutAdvisor;
import com.apress.prospring4.ch5.staticpc.SimpleAdvice;
pulic class NamePointcutOsingAdvisor {
puic static void main(String[J args) {
NameBean target = new NameBean();
NameMatchMethodPointcutAdvisor advisor = new
NameMatchMethodPointcutAdvisor(new SimpleAdvice());
advisor.addethodName( "foo");
advisor.addethodName("bar");
ProxyFactory pf = new ProxyFactory () ;
pf.setTarget(target);
pf.addAdvisor(advisor);
NameBean proxy = (NameBean) pf.getProxy();
proxy.foo();
proxy. foo(999);
proxy.bar();
proxy.yup();

, NameMatchMethodPointcut
NameMatchethodPointcut
Advisor. NameMatchMethodPointcutAdvisor
Advisor, Pointcut.
Advisor
Javadoc org. springframework. . s upport.
,

. , ,
. ,
.
242 5. - Spring


,
ProxyFactory. , Spring : n JDK,
Proxy JDK, CGLI,
Enhancer CGLI. ,
n,
Spring.
.
,
, ,
. ,
Spring.

.

. ,
AopContext ( );

. ,
ProxyFactory. setExposeProxy (),
.
Advised, , ,
, . ,
, this (.. ),
, .
, ,
JDK CGLIB.
JDK
JDK ,
Spring. CGLI, JDK
, . , ,
, .
,
,
. CGLI.
JDK JV
invoke () . invoke () ,
( , ),
, .
invoke () , .
JDK
invoke (). , ,
, invoke () - ,
, . , -
5. - Spring 243
n,

, .
ProxyFactory
JDK,
setinterfaces () ( AdvisedSupport, ProxyFactory
).
CGLIB
JDK
.
CGLI - ,
.
CGLIB , CGLI
Spring , . ,
, invoke () JDK,
CGLIB . CGLIB
-, ,
. , CGLIB -
, , ,
, . CGLI ,
this, ,
, .
CGLIB
JDK . -
, .

, . CGLIB
,
, .


.
CGLI JDK.
S i m pleB e a n
DefaultSimpleBean,
. SimpleBean DefaultSimpleBean
5.39 5.40.
5.39. SimpleBean
package com.apress.prospring4.ch5;
puic interface SimpleBean
void advised ();
void unadvised();
244 5. - Sprig

5.40. DefaultSimpleBean
package com.apress.prospring4.ch5;
puic class DefaultSimpleBean implements SimpleBean {
private long dummy = ;
@Override
pulic void advised() {
dummy = System.currentTimeMillis();

@Override
puic void unadvised()
dummy = System.currentTimeMillis();

5.41 TestPointcut,
, .

5.41. TestPointcut
package com.apress.prospring4.ch5;
import java.lang.reflect.Method;
import org.springframework.aop.support.StaticMethodatcherPointcut;
puic class TestPointcut extends StaticMethodatcherPointcut
@Override
pulic boolean matches(Method method, Class cls)
return ("advised".equals(method.getName()));

5.42 NoOpBeforeAdvice,
"", .

5.42. NoOpBeforeAdvice
package com.apress.prospring4.ch5;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
puic class NoOpBeforeAdvice implements MethodBeforeAdvice
@Override
puic void before(Method method, Object[] args, Object target)
throws Throwae {
//

, 5.43 .
5. - Spring 245
5.43.
package com.apress.prospring4.ch5;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
puic class ProxyPerfTest {
pulic static void main(String[] args) {
SimpleBean target = new DefaultSimpleBean();
Advisor advisor = new DefaultPointcutAdvisor(new TestPointcut(),
new NoOpBeforeAdvice());
runCglibTests(advisor, target);
runCglibFrozenTests(advisor, target);
runJdkTests(advisor, target);

private static void runCglibTests(Advisor advisor, SimpleBean target) {


ProxyFactory pf = new ProxyFactory();
pf.setProxyTargetClass(true);
pf.setTarget(target);
pf.addAdvisor(advisor);
SimpleBean proxy = (SimpleBean)pf.getProxy();
// CGLIB
System.out.println("Runnig CGLIB (Standard) Tests");
test(proxy);

private static void runCglibFrozenTests(Advisor advisor, SimpleBean target)


{
ProxyFactory pf = new ProxyFactory();
pf.setProxyTargetClass(true);
pf.setTarget(target);
pf.addAdvisor(advisor);
pf.setFrozen(true);
SimpleBean proxy = (SimpleBean)pf.getProxy();
// CGLIB
System.out.println("Running CGLIB (Frozen) Tests");
test(proxy);

private static void runJdkTests(Advisor advisor, SimpleBean target) {


ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
pf.setinterfaces(new Class[] {SimpleBean.class});
SimpleBean proxy = (SimpleBean)pf.getProxy();
// JDK
System.out.println("Running JDK Tests");
test(proxy);
246 5. - Spring
private static void test(SimpleBean bean)
long before = ;
long after = ;
// ,
System.out.println("Testing Advised Method");
before = System.currentTimeMillis();
for(int = ; < 500000; ++) {
bean.advised();
after = System.currentTimeMillis();
//
System.out.println("Took " + (after - before) + " ms");
// ,
System.out.println("Testing Unadvised Method");
before = System.currentTimeMillis();
for(int = ; < 500000; ++) {
bean.unadvised();

after = System.currentTimeMillis();
//
System.out.println("Took " + (after - before) + " ms");
// equals()
System.out.println("Testing equals() Method");
before = System.currentTimeMillis();
for(int = ; < 500000; ++) {
bean.equals(bean);

after = System.currentTimeMillis();
//
System.out.println("Took " + (after - before) + " ms");
// hashCode()
System.out.println("Testing hashCode() Method");
before = System.currentTimeMillis();
for(int = ; < 500000; ++) {
bean.hashCode();

after = System.currentTimeMillis();
//
System.out.println("Took " + (after - before) + " ms");
Advised advised = (Advised)bean;
// Advised.getProxyTargetClass()
System.out.println("Testing Advised.getProxyTargetClass() Method");
before = System.currentTimeMillis();
for(int = ; < 500000; ++) {
advised.getTargetClass();
}
after = System.currentTimeMillis();
//
System.out.println("Took " + (after - before) + " ms");
System.out.println(">>>\n");
5. - Spring 247
: CGLI,
CGLIB (..
setFrozen () ProxyConfig, ProxyFactory
, CGLI ,
) JDK.
.
, ( 1). , .
"", -
, .
, ( 2). ,
. , .
, , ,
.
equals ( 3).
, equals (). ,
Hashap .
hashcode ( 4). equals () , hashCode () ,
HashMap .
Advised ( 5). ,
Advised,
, n.
,
Advised n.
. 5.4.
5.4.
( )
CGLIB CGLIB
JDK
() ()
, 245 135 224
, 92 42 78
equals() 9 6 77
hashCode () 29 13 23
Advised.getProxyTargetClass() 9 6 15

, CGLJB
JDK , ,
. ,
JDK.
n CGLI
. equals ()
hashCode (), ,
CGLI. Adv i sed -
248 5. - Spring

CGLIB. , Advised
intercept () , l!
, .


, , .
CGLIB , 11 ,
JDK - .
JDK CGLJB ( ,
, ).
CGLIB CGLI
. l! ,
CGLIB, .. ,
. CGLIB l! ,
optimize ProxyFactory true
setOptimize ().



Pointcut, Spring; ,
. ,
. Spring
Pointcut, ComposaePointcut ControlFlowPointcut,
.


Spring, ControlFlowPointcut,
cflow, ,
. , Spring
,
. , ,
, .
5.44 SimpleBeforeAdvice,
, .
5.44. SimpleeforeAdvice
package com.apress.prospring4.ch5;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
pulic class SimpleBeforeAdvice implements MethodBeforeAdvice
@Override
pulic void before(Method method, Object[] args, Object target)
throws Throwae {
System.out.println("Before method: " + method);
5. - Spring 249
, ControlFlow
Pointcut. 5.45 - ,
.
5.45. Testean
package com.apress.prospring4.ch5;
puic class TestBean {
pulic void foo() {
System.out.println("foo()");

foo (), .
-
, .
5.46
.
5.46. ControlFlowPointcut
package com.apress.prospring4.ch5;
import org.springframework.aop.Advisor;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.ControlFlowPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
puic class ControlFlowExample {
pulic static void main(String [] args) {
ControlFlowExample = new ControlFlowExample();
.run();

puic void run()


TestBean target = new TestBean();
Pointcut = new ControlFlowPointcut(ControlFlowExample.class, "test");
Advisor advisor = new DefaultPointcutAdvisor(pc, new SimpleBeforeAdvice());
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
TestBean proxy = (TestBean) pf.getProxy();
//
System.out.println("Trying normal invoke");
proxy.foo();
// ControlFlowExample.test()
System.out.println("Trying under ControlFlowExample.test()");
test(proxy);

private void test(TestBean bean)


bean.foo();
250 5. - Spring
5.46 ControlFlow
Pointcut foo () :
run () test ().
:
Pointcut = new ControlFlowPointcut(ControlFlowExample.class, "test");
ControlFlowPointcut test ()
ControlFlowExample. , : "
, ControlFlowExample. test () ". ,
" ",
" ,
Ad v is r,
ControlFlowPointcut".
5.46 :
Trying normal invoke
foo()
Trying under ControlFlowExample .test()
Before method: pulic void com.apress .prospring4.ch5.TestBean.foo()
foo()
, foo ()
test (), . foo ()
, test (),
ControlFlowPointcut ,
foo (), . ,
test () ,
, .
,
,
. ,
.
. ,
, TransactionService
AccountService. "", ,
AccountService. updateBalance () TransactionService.
reverseTransaction (),
.
.
. . 5.4 UML
.



Advisor. ,

.
5. - Spring 251

: TransactionService AccountServiceProxy AccountService Emai!NotificationAdvice


'
1 1 1 1
1 :reverseTransaction() 1 1 1
v 1 1 1
1.1 :updateBalance() 1 1 1

v 1 1
1
1. 1. 1 :updateBalance() : 1
1
1
-------- 1
1
)
1
: yr verseTransaction() 1
1
1.1.2:sendEmailotification() 1

-------------------: 1
1 1
1 1
1
1 1
(-----------1 1 1
1 1
1 1 1
(--------------1 1 1
1 1
1 1
1 1
1

. 5.4. UML

,
.
, . ,
,

ComposablePointcut.
ComposaePointcut : union () intersection ().
Comp o salePoint cut
ClassFilter, ,
MethodMatcher, ,
ClassFilter MethodMatcher.
union () intersection () ClassFilter
MethodMatcher.
ComposaePointcut. union ()
Clas s Filter, MethodMatcher
Poi n t c ut. ,
ComposaePointcut ""
.
ComposaePointcut. intersection (),
"" "", ,
ClassFilter, MethodMatcher Pointcut ComposalePointcut
, .
WHERE SQL-apoce, union ()
OR, intersection () - AND.
252 5. - Spring

,
, . 5.47
.

5.47. SampleBean
package com.apress.prospring4.ch5;
pulic class SampleBean {
puic String getName() {
return "Chris Schaefer";

puic void setName(String name)


}
puic int getAge()
return 32;

,
ComposalePointcut,
ComposaePointcut union () intersection ().
SampleBean ,
. 5.48 .

5.48. ComposalePointcut
package com.apress.prospring4.ch5;
import java.lang.reflect.Method;
import org.springframework.aop.Advisor;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.ComposaePointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.StaticMethodatcher;
pulic class ComposaePointcutExample {
puic static void main(String[] args) {
SampleBean target = new SampleBean();
ComposaePointcut = new ComposalePointcut(ClassFilter.TRUE,
new GetterMethodatcher());
// l
System.out.println("Test l");
SampleBean proxy = getProxy(pc, target);
testinvoke(proxy);
// 2
System.out.println("Test 2");
pc.union(new SetterMethodatcher());
proxy = getProxy(pc, target);
testinvoke(proxy);
5. - Spring 253
// 3
System.out.println("Test 3");
pc.intersection(new GetAgeMethodatcher());
proxy = getProxy(pc, target);
testinvoke(proxy);

private static SampleBean getProxy(ComposalePointcut ,


SampleBean target) {
Advisor advisor = new DefaultPointcutAdvisor(pc,
new SimpleBeforeAdvice());
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
return (SampleBean) pf.getProxy();

private static void testinvoke(SampleBean proxy)


proxy.getAge();
proxy.getName();
proxy.setName("Chris Schaefer");

private static class GetterMethodatcher extends StaticMethodatcher


@Override
puic boolean matches(Method method, Class<?> cls)
return (method.getName() .startsWith("get"));

private static class GetAgeMethodatcher extends StaticMethodatcher


@Override
puic boolean matches(Method method, Class<?> cls) {
return "getAge".equals(method.getName());

private static class SetterMethodatcher extends StaticMethodatcher


@Override
puic boolean matches(Method method, Class<?> cls)
return (method.getName() .startsWith("set"));

, ,
MethodMatcher.
GetterMethodMatcher ,
get. Methodatcher,
ComposaePointcut. ,
SampleBean
getAge () getName () .
SetterMethodMatcher ,
set, ComposaePointcut union ()
254 5. - Spring

.
MethodMatcher: , get,
- , set. ,
.
GetAgeMethodMatcher
getAge (). MethodMatcher
ComposaePointcut intersection () .
GetAgeMethodMatcher intersection (),

getAge (), .. ,
MethodMatcher.
:
Test 1
Before method: puic int com.apress.prospring4.ch5.SampleBean.getAge()
Before method: puic java.lang.String com.apress.prospring4.ch5.
SampleBean.getName()
Test 2
Before method: puic int com.apress.prospring4.ch5.SampleBean.getAge()
Before method: puic java.lang.String com.apress.prospring4.ch5.
SampleBean.getName()
Before method: puic void com.apress.prospring4.ch5.SampleBean.
setName(java.lang.String)
Test 3
Before method: puic int com.apress.prospring4.ch5.SampleBean.getAge()
, -
getAge () getName () .
, SetterMethodMatcher union (),
.
GetAgeMethodatcher getAge ().
MethodMatcher
, ClassFil ter
.
Methodatcher ClassFilter.
Poin tcu t
,
MethodMatcher ClassFilter.
,
Pointcut.

org. springframework. . support. Pointcuts.
. intersection () union ()
. ,
matches ( Pointcut, Method, Class, Obj ect [] ) ,
, ,
.
5. - Spring 255
Pointcuts .
, MethodMatcher ClassFilter Pointcut,
CornposaePointcut.
, Pointcuts .


Spring Pointcut,
, , .
, , ,
, Pointcut,
MethodMatcher ClassFilter.
.
, ,
.
Pointcut DefaultPointcutAdvisor
Pointcut .
,
Spring, Pointcut
Advisor. , , Pointcut
PointcutAdvisor, PointcutAdvisor. getPointcut (),
this. Spring,
StaticMethodMatcherPointcutAdvisor.
, ..
Pointcut Advisor.
,
Pointcut Advisor
. , Advisor
Pointcut; , Advisor
Pointcut.
, ,
, , ,
. ,
Pointcut ,
. ,
- .



, Spring.
.
Spring .
:
,
? .
,
.
256 5. - Spring


Spring , -
"".
, ;
. ,
, .
Introductioninterceptor,
Methodinterceptor DynamicintroductionAdvice. . 5.5
.

interface
org.aopalliance.aop.Advice

1
interface> >
org.aopalliance.intercept.lnterceptor

1
interface
org.aopalliance.interceptor.Methodlnterceptor
interface
org.springframework.aop.DynamiclntroductionAdvisor

+invoke(invocation: Methodlnvocator): Object + implementslnterface(intf: Class< ?>) : boolean


interface
/
org.springframework.aop.lntroductionlnterceptor

. 5.5.

, Methodinterceptor invoke ().




.
, , ,
, .
, Spring Introductioninterceptor
Delegatingintroductioninterceptor,
.
Delegatingintroductioninterceptor, ,
Delegatingintroductioninterceptor ,
. Delegatingintroductioninterceptor
.
, ;
.
5. - Spring 257
, PointcutAdvisor
, IntroductionAdvisor
. IntroductionAdvisor
DefaultintroductionAdvisor, ,
, . ,
ProxyFactory. addAdvice ()
AopConfigException. addAdvisor ()
IntroductionAdvisor.
- .. -
.
Spring ,
.
, ,

.
. ,
,
DefaultintroductionAdvisor, .
,
,
.
, "" setFirstName ()
Contact. . 5.6 ,
Contact.

Contact
1
1
1
1
1
I Joh Smith
1
1

"" ScottTiger
setFirstName ()

1
1
I Clarece
1
1
----------------
. 5.6.
,
Contact,
Contact (, isModified, ,
).
Contact ,
. 5.7.
258 5. Spring

R Contact
,-----------------------------
1 1
: :
1 1
1 1
1 1
1
1
John Smith
1
1
1
1
1
1
1
1 Scott Tiger
1
1
1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1
1 Clarence 1
1
1 1
1 1
L-----------------------------

. 5. 7.

. ,
.


- .

.
, ,
.

,
, .
, ,
,
, , .
null , ,
. ,
, ,
.
, -
.
5. - Sprig 259
. , ,
, - ,
,
,
.
,
.

, .
IsModified,

.
JavaBean, ,
. ,
- , ,
, , .
,
, -
. , Contact
firstName. , firstName
Peter John.
. ,

Peter.
. ,

.
.

Isodified

IsModified,
.
, IsModified,
.
IsModified 5.49.

5.49. IsModified
package com.apress.prospring4.ch5;
pulic interface IsModified
boolean isModified();

- isModified (),
, .
260 5. - Spring


,
IsModified ; (mixin).
,
Delegatin gintroductioninterceptor,
Introductioninterceptor. ,
IsModifiedMixin, Delegatin gintroductioninterceptor
IsModified. IsModifiedMixin
5.50.

5.50. IsModifiedixin
package com.apress.prospring4.ch5;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.aopalliance.intercept.Methodinvocation;
import org.springframework.aop.support.Delegatingintroductioninterceptor;
puic class IsModifiedixin extends Delegatingintroductioninterceptor
implements IsModified {
private boolean isModified = false;
private Map<Method, Method> methodCache = new HashMap<Method, Method>();
@Override
puic boolean isModified()
return isModified;

@Override
puic Object invoke(Methodinvocation invocation) throws Throwae
if ( ! isModified) {
if ((invocation.getMethod().getName(). startsWith( "set"))
&& (invocation.getArguments() .length == 1)) {
Method getter = getGetter(invocation.getMethod());
if (getter != null) {
Object newVal = invocation.getArguments() [];
Object oldVal = getter.invoke(invocation.getThis(), null);
if((newVal == null) && (oldVal == null)) {
isModified = false;
else if((newVal == null) && (oldVal != null))
isModified = true;
else if((newVal 1= null) && (oldVal == null))
isModified = true;
else {
isModified = (!newVal.equals(oldVal) );

return super.invoke(invocation);
5. - Spring 261
private Method getGetter(Method setter) {
Method getter = null;
getter = (Method) methodCache.get(setter);
if (getter != null)
return getter;

String getterName = setter.getName().replaceFirst("set", "get");


try {
getter = setter.getDeclaringClass().getMethod(getterName, null);
synchronized (methodCache)
methodCache.put(setter, getter);

return getter;
catch (NoSuchMethodException )
return null;

, ,
IsModified, isModified
isModified (). ,
, -
, .

, ,
-
.
invoke ()
,
. ,
; 0 ,
, , . ,
, ,
. , /
. , ,
, , , ,
.
null isModified. ,
Delegatingintroductioninterceptor
invoke () super. invoke (),
Delegatingintroductioninterceptor
- , , .
,
, .
262 5. - Spring


Advisor,
. ,
, .
IsModifiedAdvisor 5.51.
5.51.
package com.apress.prospring4.ch5;
import org.springframework.aop.support.DefaultintroductionAdvisor;
puic class IsModifiedAdvisor extends DefaultintroductionAdvisor {
pulic IsModifiedAdvisor() {
super(new IsModifiedixin());

, IsModifiedAdvisor
Defaul tintroductionAdvisor.
.

, Advisor,
. 5.52 ,
IsModifiedMixin.
5.52. Targetean
package com.apress.prospring4.ch5;
pulic class TargetBean {
private String name;
puic void setName(String name)
this.name = name;

pulic String getName()


return name;

name,
. 5.53 ,
.
5.53. IsModifiedixin
package com.apress.prospring4.ch5;
import org.springframework.aop.IntroductionAdvisor;
import org.springframework.aop.framework.ProxyFactory;
puic class IntroductionExample {
5. - Sprig 263
pulic static void main(String(] args) {
TargetBean target = new TargetBean();
target.setName("Chris Schaefer");
IntroductionAdvisor advisor = new IsModifiedAdvisor();
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
pf.setOptimize(true);
TargetBean proxy = (TargetBean) pf.getProxy();
IsModified proxyinterface = (IsModified)proxy;
System.out.println("Is TargetBean?: " + (proxy instanceof TargetBean));
System.out.println("Is IsModified?: " + (proxy instanceof IsModified));
System.out.println("Has been modified?: " +
proxyinterface.isModified());
proxy.setName ( "Chris Schaefer");
System.out.println("Has been modified?: " +
proxyinterface.isModified() );
proxy.setName("Chris Schaefer");
System.out.println("Has been modified?: " +
proxyinterface.isModified());

,
true, CGLr. ,
JDK,
( TargetBean);
, . CGLI
.
,
TargetBean, - IsModified.
true, CGLI, JDK true
IsModified. , ,
name , -
, isModified.
:
Is TargetBean?: true
Is IsModified?: true
Has been modified?: false
Has been modified?: false
Has been modified?: true
, instanceof true.
, isModified (), ,
false. , name
, false. isModified (),
, name , true,
, .
264 5. - Spring

Spring;
,
.
- ,
. ,
, ,
. IsModifiedMixin,
, , ,
,
, _ .
, ,
.
, .. .
, ,
( ), ,
,
, ,
,
.

,
,
.
, ,
,
. , Spring
,

.

.
,
.
, , ,
.


Spring .
ProxyFactoryBean. ,
Spring, ProxyFactoryBean
ApplicationContext (, ,
BeanFactory)
Spring.
5. - Spring 265
Spring.
Spring 2.0 (
ProxyFactoryBean) DI
Sring- . , " "
ProxyFactoryBean.
@AspectJ. ,
XML,
@AspectJ.
AspectJ _ AspectJ,
Spring - (..
- ) ApplicationContext.
ProxyFactoryBean
ProxyFactoryBean - FactoryBean,
,
. ProxyFactoryBean
,
, .
ProxyFactoryBean (org. springframework.
. framework.Advised) ProxyFactory (
org. springframework. . framework. AdvisedSupport,
Advised),
, frozen, optimize exposeProxy.
ProxyFactory,
.
ProxyFactoryBean
ProxyFactoryBean . ,
, ProxyFactoryBean ,
,
. ,
.
, . (
)
, .
5.54 5.55 , .
5.54. yDependency
package com.apress.prospring4.ch5;
pulic class MyDependency {
pulic void foo() {
System.out.println("foo()");

pulic void bar () {


System.out.println("bar()");
266 5. n- Spring
5.55. n
package com.apress.prospring4.ch5;
pulic class MyBean {
private MyDependency dep;
puic void execute()
dep.foo();
dep.bar();

puic void setDep(MyDependency dep)


this.dep = dep;


MyDependency, ,
5.56.

5.56. yAdvice
package com.apress.prospring4.ch5;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
puic class MyAdvice implements MethodBeforeAdvice
@Override
pulic void before(Method method, Object[J args, Object target)
throws Throwae {
System.out.println("Executing: " + method);

;
, .
AspectJExpressionPointcut Defaul tPointcutAdvisor ,
foo () MyDependency. ,
MyBean,
. execute ()
, ,
, . 5.57
(app-context-xml. xml).

5.57.
<?xml version="l.O" encoding= "UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
5. - Sprig 267
<bean id="myBeanl" class="com.apress.prospring4.ch5.MyBean">
<property name= "dep">
<ref bean="myDependencyl "/>
</property>
</bean>
<bean id="myBean2" class="com.apress.prospring4.ch5.MyBean">
<property name="dep">
<ref bean="myDependency2"/>
</property>
</bean>
<bean id="myDependencyTarget"
class="com.apress.prospring4.ch5.MyDependency"/>
<bean id="myDependencyl"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref bean="myDependencyTarget"/>
</property>
<property name="interceptorNames">
<list>
<value>advice</value>
</list>
</property>
</bean>
<bean id="myDependency2"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref bean="myDependencyTarget"/>
</property>
<property name="interceptorNames">
<list>
<value>advisor</value>
</list>
</property>
</bean>
<bean id="advice" class="com.apress.prospring4.ch5.MyAdvice"/>
<bean id="advisor"
class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice">
<ref bean="advice"/>
</property>
<property name="pointcut">
<bean class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
<property name="expression">
<value>execution(* foo*( .. ))</value>
</property>
</bean>
</property>
</bean>
</beans>
268 5. - Sprig

,
DI Spring.
ProxyFactoryBean.
,
, ,
,
. ProxyFactoryBean, ,
ProxyFactoryBean ,
.
, ,
,
, , .
, ,
, .
5.58 ,
MyBean ApplicationContext
execute ().
5.58. ProxyFactoryBeanExample
package com.apress.prospring4.ch5;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class ProxyFactoryBeanExample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx =
new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
MyBean beanl = (MyBean)ctx.getBean("myBeanl");
MyBean bean2 = (MyBean)ctx.getBean("myBean2");
System.out.println("Bean 1");
beanl.execute();
System.out.println("\nBean 2");
bean2.execute();

5.58 :
Bean 1
Executing: puic void com.apress.prospring4.ch5.MyDependency.foo()
foo()
Executing: pulic void com.apress.prospring4.ch5.MyDependency.bar()
bar()
Bean 2
Executing: puic void com.apress.prospring4.ch5.MyDependency.foo()
foo()
bar()
5. - Spring 269
, foo () bar ()
, .. .
foo (),
.
ProxyFactoryBean
ProxyFactoryBean
;
. ,
IntroductionAdvisor;
. ProxyFactoryBean
. ProxyFactoryBean,
, Advisor .
5.59 IsModifiedMixin,
(app-context-xml. xml).
5.59. ProxyFactoryBean
<?xml version= "l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id= "bean"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<bean class= "com.apress.prospring4.ch5.TargetBean">
<property name="name">
<value>Chris Schaefer</value>
</property>
</bean>
</property>
<property name= "interceptorNames">
<list>
<value>advisor</value>
</list>
</property>
<property name ="proxyTargetClass">
<value>true</value>
</property>
</bean>
<bean id="advisor" class= "com.apress.prospring4.ch5.IsModifiec!Advisor"/>
</beans>

, IsModifiedAdvisor
ProxyFactoryBean,
,
. 5.60 ,
ApplicationContext.
270 5. - Spring
5.60. IntroductionConfigExample
package com.apress.prospring4.ch5;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class IntroductionConfigExample {
puic static void main(String[J args) {
GenericXmlApplicationContext ctx =
new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
TargetBean bean = (TargetBean) ctx.getBean("bean");
IsModified mod = (IsModified) bean;
System.out.println("Is TargetBean?: " + (bean instanceof TargetBean));
System.out.println("Is IsModified?: " + (bean instanceof IsModified));
System.out.println("Has been modified?: " + mod.isModified());
bean.setName("Chris Schaefer");
System.out.println("Has been modified?: " + mod.isModified());
bean.setName("Chris Schaefer");
System.out.println("Has been modified?: " + mod.isModified());

,
, ApplicationContext
- .

ProxyFactoryBean
ProxyFactoryBean
,
.
, ,
,
.
Spring,

, Spring 2.0 JDK 5


.



Spring.
, ProxyFactoryBean,
.
5.61 5.62 MyDependency
MyBean.
5. - Spring 271
5.61. yDependency
package com.apress.prospring4.ch5;
pulic class MyDependency {
puic void foo(int intValue) {
System.out.println("foo(int): " + intValue);

puic void bar() {


System.out.println("bar()");

5.62. n
package com.apress.prospring4.ch5;
puic class MyBean {
private MyDependency dep;
pulic void execute ()
dep.foo(lOO);
dep.foo(lOl);
dep.bar();

puic void setDep(MyDependency dep)


this.dep = dep;

foo () MyDependency
. ,
MyBean foo () .
, . 5.63
MyAdvice.
5.63. yAdvice
package com.apress.prospring4.ch5;
import org.aspectj.lang.JoinPoint;
puic class MyAdvice {
puic void simpleBeforeAdvice(JoinPoint joinPoint) {
System.out.println("Executing: " +
joinPoint.getSignature().getDeclaringTypeName() + " "
+ joinPoint.getSignature().getName());

,
MethodBeforeAdvice. , ""
JoinPoint, , .
, -
272 5. - Spring

r. ,
(
), r . r ,
Spring .
5.64 L- Spring
(app-context-xml. xml).
5.64. Spring
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:config>
<aop:pointcut id="fooExecution"
expression="execution(* com.apress.prospring4.ch5..foo*(int))"/>
<aop:aspect ref="advice">
<aop:before pointcut-ref="fooExecution"
method="simpleBeforeAdvice"/>
</aop:aspect>
</aop:config>
<bean id="advice" class="com.apress.prospring4.ch5.MyAdvice"/>
<bean id="myDependency"
class="com.apress.prospring4.ch5.MyDependency"/>
<bean id="myBean" class="com.apress.prospring4.ch5.MyBean">
<property name="dep" ref="myDependency"/>
</bean>
</beans>

-, <beans>.
-, r Spring <: config>.
, , ..,
Spring .
nm fooExecution.
"execution (* . apress. prospring4. ch5 .. foo* (int))"
, foo ,
com. apress. prospring4. ch5 ( n).
, foo () .
<: aspect>
Spring advice,
MyAdvice. pointcut-ref
fooExecution, "" (
<aop:before>) simpleBeforeAdvice ()
.
5. - Spring 273
5.65 .
5.65. AopNamespaceExample
package com.apress.prospring4.ch5;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class AopNamespaceExample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
MyBean myBean = (MyBean) ctx.getBean("myBean");
myBean.execute();

ApplicationContext,
execute ().
:
Executing: com.apress.prospring4.ch5.MyDependency foo
foo(int): 100
Executing: com.apress.prospring4.ch5.MyDependency foo
foo(int): 101
bar()
, foo () ,
bar () - . , ,
,
ProxyFactoryBean.

. ,
Spring , myDependency,
, 100.
100,
. MyAdvice 5.66.
5.66. yAdvice ( )
package com.apress.prospring4.ch5;
import org.aspectj.lang.JoinPoint;
pulic class MyAdvice {
puic void simpleBeforeAdvice(JoinPoint joinPoint, int intValue) {
if (intValue != 100) {
System.out.println("Executing: " +
joinPoint.getSignature().getDeclaringTypeName() + " "
+ joinPoint.getSignature() .getName()
+ " argument: " + intValue);
274 5. - Spring
. -, ""
intValue. -,
, 100.

L-. .
:
<aop:pointcut id="fooExecution" expression= "execution(* foo*(int))
and args(intValue) and bean(myDependency*)"/>
.
, args (intValue), Spring
intValue "". , bean (myDependency*),
Spring ,
myDependency. ;
Spring,
. , bean (*DAO*) ,
, bean (*Service*)
, ,
.
(AopNamespaceExample) -
:
foo(int): 100
Executing: com.apress.prospring4.ch5.MyDependency foo argument: 101
foo(int): 101
bar()
, foo ()
, 100.

"".
Methodinterceptor MyAdvice.
MyAdvice simpleAroundAdvice ()
5.67.
5.67. yAdvice ( )
simpleAroundAdvice ()
package com.apress.prospring4.ch5;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
puic class MyAdvice {
puic void simpleBeforeAdvice(JoinPoint joinPoint, int intValue) {
if (intValue != 100) {
// , intValue 100
System.out.println("Executing: " +
joinPoint.getSignature().getDeclaringTypeName() + " "
+ joinPoint.getSignature() .getName()
+ " argument: " + intValue);
5. - Spring 275
puic Object simpleAroundAdvice(ProceedingJoinPoint pjp, int intValue)
throws Throwae {
//
System.out.println("Before execution: " +
pjp.getSignature().getDeclaringTypeName() + " "
+ pjp.getSignature().getName()
+ " argument: " + intValue);
Object retVal = pjp.proceed();
//
System.out.println("After execution: " +
pjp.getSignature().getDeclaringTypeName() +
+ pjp.getSignature().getName() + " argument: " + intValue);
return retVal;

simpleAroundAdvice () ,
, ProceedingJoinPoint,
. ,
intValue .
5.68 L-.

5.68. Spring
( "")
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:config>
<aop:pointcut id="fooExecution"
expression="execution(* com.apress.prospring4.ch5..foo*(int))"/>
<aop:aspect ref="advice">
<aop:before pointcut-ref= "fooExecution"
method="simpleBeforeAdvice"/>
<aop:around pointcut-ref="fooExecution"
method="simpleAroundAdvice"/>
</aop:aspect>
</aop:config>
<bean id= "advice" class="com.apress.prospring4.ch5.MyAdvice"/>
<bean id="myDependency"
class= "com.apress.prospring4.ch5.MyDependency"/>
<bean id="myBean" class="com.apress.prospring4.ch5.MyBean">
<property name="dep" ref="myDependency"/>
</bean>
</beans
276 5. - Spring

<: around>
"" .
:
Before execution: com.apress.prospring4.ch5.MyDependency foo argument: 100
foo (int): 100
After execution: com.apress.prospring4.ch5.MyDependency foo argument: 100
Executing: com.apress.prospring4.ch5.MyDependency foo argument: 101
Before execution: com.apress.prospring4.ch5.MyDependency foo argument: 101
foo(int): 101
After execution: com.apress.prospring4.ch5.MyDependency foo argument: 101
bar()
. -, "
" foo (),
. -, foo () 101
, "" "",
"" .

! @AspectJ
"". " " ( <aop:after
returning>) , .
, "" ( <:after>),
, , , -
. ,
,
"".

@AspectJ
Spring JDK 5
@AspectJ. ,
, Spring -
,
AspectJ.
, ,
,
@AspectJ.
Spring.
5.69 5.70 MyDependency MyBean
DI Spring.
5.69. yDependency
package com.apress.prospring4.ch5;
import org.springframework.stereotype.Component;
@Component("myDependency")
pulic class MyDependency {
puic void foo(int intValue)
System.out.println("foo(int): " + intValue);
5. - Spring 277
puic void bar() {
System.out.println("bar()");

5.70. n
package com.apress.prospring4.ch5;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("myBean")
pulic class MyBean {
private MyDependency myDependency;
pulic void execute() {
myDependency.foo(lOO);
myDependency.foo(lOl);
myDependency.bar();

@Autowired
pulic void setDep(MyDependency myDependency)
this.myDependency = myDependency;

@Component
. MyBean myDependency
@Autowired
Spring.
, MyAdvice
@AspectJ. , "" "".
MyAdvice 5.71.
5.71. yAdvice
package com.apress.prospring4.ch5;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
puic class MyAdvice {
@Pointcut("execution(* com.apress.prospring4.ch5..foo*(int)) &&
args(intValue)")
pulic void fooExecution(int intValue) {
}
278 5. - Sprig
@Pointcut("bean(myDependency*)")
puic void inyDependency() {
}
@Before("fooExecution(intValue) && inMyDependency()")
puic void simpleBeforeAdvice(JoinPoint joinPoint, int intValue) {
if (intValue != 100) {
// , intValue 100
System.out.println("Executing: " +
joinPoint.getSignature().getDeclaringTypeName() +
+ joinPoint.getSignature().getName() + " argument: " + intValue);

@Around("fooExecution(intValue) && inMyDependency()")


pulic Object simpleAroundAdvice(ProceedingJoinPoint pjp, int intValue)
throws Throwae {
//
System.out. println("Before execution: " +
pjp.getSignature().getDeclaringTypeName() + " "
+ pjp.getSignature().getName()
+ " argument: " + intValue) ;
Object retVal = pjp.proceed();
// m
System.out.println("After execution: " +
pjp.getSignature().getDeclaringTypeName() + " "
+ pjp.getSignature().getName()
+ " argument: " + intValue) ;
return retVal;

, ,
, .
, .
yAd.vice @Component
@Aspect. @Aspect .
Spring , L-r
<context: component-scan>,
@Component.
, void
; @Pointcut.
.
( fooExecution (int intValue))
foo* ()
com. apress .prospring4. chS,
(intValue) . (
inMyDependency ()) ,
Spring,
myDependency. , ""
&&,
and.
5. - Spring 279
"" @Bef ore,
"" - @Around.
, , .
"fooExecution (intValue) && inMyDependency ()" ,
,
, CornposalePointcut.
"" ""
.
L-r
. 5.72 (app
config-annotation. xrnl).
5.72. Spring @AspectJ
<?xml version="l. " encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<aop:aspectj-autoproxy/>
<context:component-scan base-package="com.apress.prospring4.ch5"/>
</beans>

. <: aspect-autorpoxy>
Spring ,
@AspectJ, <context: cornponent-scan> -
Spring Spring , .
@Cornponent,
, Spring.
<: aspectj-autoproxy> proxy-target-class.
false, , Spring
, ,
JDK. proxy-target-class true
Spring CGLI ,
. 5.73
AspectJAnnotationExarnple.
5. 73. AspectJ
package com.apress.prospring4.ch5;
import org.springframework.context.support.GenericXmlApplicationContext;
280 5. - Spring
puic class AspectJAnnotationExample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
MyBean myBean = (MyBean) ctx.getBean("myBean");
myBean.execute();

, -
:
Before execution: com.apress.prospring4.ch5.MyDependency foo argument: 100
foo(int): 100
After execution: com.apress.prospring4.ch5.MyDependency foo argument: 100
Before execution: com.apress.prospring4.ch5.MyDependency foo argument: 101
Executing: com.apress.prospring4.ch5.MyDependency foo argument: 101
foo(int): 101
After execution: com.apress.prospring4.ch5.MyDependency foo argument: 101
bar()


Spring

Spring, ProxyFactoryBean,
@AspectJ. , ,
, ProxyFactoryBean. ,
: -
@AspectJ?
Spring L-r,
,
DI. ,
,
@AspectJ. ,
,
.
,
@AspectJ.
(,
, and
, && @AspectJ).

.
""
. ,
@AspectJ
5. - Spring 281
(.. fooExecution (intValue) && inMyDependency ()) ""
"".
, ,
.

AspectJ
,
- .
Spring ,
,
.
, Spring.
Spring ,
. ,
/ ,
..

. AspectJ,
AspectJ Spring, AspectJ
Spring.

AspectJ
AspectJ - ,
( , )
. AspectJ Jv
r ,
Java.
AspectJ, .
AspectJ ,
Spring. AspectJ AspectJ in
Action: Enterprise with Spring Applications, 2- (Manning, 2009 r.).

! , AspectJ
. AspectJ
aspectj-aspects 5.


AspectJ
, . ,
Spring AspectJ, ,
,
AspectJ. org. aspectj.
lang .Aspects. aspectOf (),
. aspectOf ()
Spring, Spring.
282 5. - Spring
,
, AspectJ,
01 Spring. ,
;
ApplicationContext , Spring,
AspectJ .
5.74 MessageWri ter,
AspectJ.
5.74. MessageWriter
package com.apress.prospring4.ch5;
pulic class MessageWriter {
pulic void writeMessage() {
System.out.println("foobar!");

pulic void foo() {


System.out.println("foo");

AspectJ
wri teMessage () .
Spring.
5.75 MessageWrapper (
MessageWrapper. aj, .. AspectJ, Jv-).
5. 75. MessageWrapper
package com.apress.prospring4.ch5;
puic aspect MessageWrapper
private String prefix;
private String suffix;
pulic void setPrefix(String prefix)
this.prefix = prefix;

pulic String getPrefix()


return this.prefix;

puic void setSuffix(String suffix)


this.suffix = suffix;

pulic String getSuffix()


return this.suffix;

pointcut doWriting() :
execution(*
com.apress.prospring4.ch5.MessageWriter.writeMessage());
before(): doWriting() {
System.out.println(prefix);
5. - Spring 283
after () : doWriting ()
System.out.println(suffix);

MessageWrapper ,
Jv-, , suffix prefix,
writeMessage ().
doWriting () ,
- writeMessage (). AspectJ
,
. , :
doWri ting (), - .
5.76 , Spring (app-config-xml. xml).
5. 76. AspectJ
<?xml version ="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="aspect" class="com.apress.prospring4.ch5.MessageWrapper"
factory-method="aspectOf">
<property name="prefix">
<value>The Prefix</value>
</property>
<property name="suffix">
<value>The Suffix</value>
</property>
</bean>
</beans>

,
.
factory-method <bean>. ,
"" (Factory),
Spring. , Foo
getinstance (), factory-method
Spring. aspectOf () ,
AspectJ, ,
Spring . 5.77
.
5.77. AspectJ
package com.apress.prospring4.ch5;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class AspectJExample {
284 5. - Spring
puic static void main (String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load(new String[J {"classpath:META-INF/spring/app-context-xml.xml"));
ctx.refresh();
MessageWriter writer = new MessageWriter();
writer.writeMessage();
writer. foo();

, ApplicationContext,
Spring .
MessageWri ter wri teMessage () foo ().
:
The Prefix
foobar !
T he Suffix
foo
, MessageWrapper
writeMessage (), prefix suffix,
ApplicationContext,
.

,
Spring.
, ( ) Spring,
AspectJ ,
Spring.
, Spring,
. , ,
. ,
, Spring.
, , .

JDK CGLIB.
, ,
, . Spring
Framework ,
.
Spring AspectJ,
AspectJ, Spring.
, .
-
JDBC, Spring,
JDBC.
6

JDBC Spring
, ,
Spring.
- ().
, : ,
?
,
- .

.

() MySQL (www. mysql. ) PostgreSQL
(www. postgresql. org). , MySQL
-, Linux. ,
PostgreSQL Oracle,
PL/pgSQL PL/SQL Oracle.

,
. , ,
,
,
.
, Sprig
, JDBC.
, , Spring,
, Sprig.
: Spring
SQL-,
, . ,
.
JDBC JDBC Spring.
, Spring JDBC ,
. ,
286 6. JDBC Spring

Spring l- JDBC
l- JdcTemplate.
.
,
Connection DataSource. ,
, Spring (DataSource),
.
Jv-. ,
Jv
. , Spring JDBC
- (object-relational
mapping - ORM).
, . , ,
,
Spring .

-
Java 8
-. -
,
JDBC Spring. -
Java 8 .
Java 8 General Availability,
, Java 8.
, ,
. - Spring API,
,
JDBC. - ,
Java,
-.
http: //docs. oracle. corn/javase/tutorial/
java/javaOO/larndaexpressions.html.


, , ,
,
(
,
).
.
, CONTACT, , ,
CONTACT_TEL_DETAIL, .
; ,
CONTACT CONTACT_TEL_DETAIL " -
6. JDBC Spring 287
". u , ,
. . 6.1 "
-" (entity-relationship - ER) .

CONTACT CONTACT_TEL_DEAIL
lliI lliI
FIRS_NAME VARCHAR(60) t- CONTACT _ID=ID CONTACT_ID INT
lAST_NAME VARCHAR(40) TEL_1YPE VARCHAR(20)
BIRTH_DATE DATE TEL_NUMBER VARCHAR(20)

. 6.1.

, u u ID,
.
u CONTACT _TEL_DETAIL u
CONTACT, u CONTACT_ID
u CONTACT (.. u ID).

!
MySQL.
MySQL. MySQL.
,
. , ,
, MySQL.

6.1 u (
MySQL).
6.1. (schema. sql)
CREATE L CONTACT (
ID INT NOT NOLL INCREMENT
, FIRST_N VARCAR( 60) NOT NOLL
, LAST_NAE VARCHAR(40) NOT NOLL
, BIRTH_DATE DATE
, ONIQOE OQ_CONTACT_l (FIRST_NAE, LAST_NAE)
, PRIARY (ID)
) ;

CREATE L CONTACT TEL_DETAIL (


ID INT NOT NOLL INCREMENT
, CONTACT_ID INT NOT NOLL
, TEL_TYPE VARCAR(20) NOT NOLL
, TEL_NOBER VARCAR(20) NOT NOLL
, ONIQOE OQ_CONTACT_TEL_DETAIL_l (CONTACT_ID, TEL_TYPE)
, PRIARY (ID)
, CONSTRAINT FK_CONTACT_TEL_DETAIL_l FOREIGN (CONTACT_ID)
REFERENCES CONTACT (ID)
) ;
288 6. JDBC Spring

6.2 r1 CONTACT CONTACT_


TEL DETAIL .
6.2. (test-data. sql)
insert into contact (first_name, last_name, birth_date) values
('Chris', 'Schaefer', '1981-05-03');
insert into contact (first_name, last_name, birth_date) values
('Scott', 'Tiger', '1990-11-02');
insert into contact (first_name, last_name, birth_date) values
('John', 'Smith', '1964-02-28');
insert into contact_tel_detail (contact_id, tel_type, tel numer) values
(1, 'Moile', '1234567890');
insert into contact tel detail (contact_id, tel type, tel_numer) values
(1, 'Home', '1234567890');
insert into contact tel detail (contact_id, tel_type, tel_numer) values
(2, 'Home', '1234567890');


JDBC
Jv- (.. POJO). 6.3 6.4
Contact ContactTelDetail.
6.3. Contact
package com.apress.prospring4.ch6;
import java.io.Serializale;
import java.sql.Date;
import java.util.List;
puic class Contact implements Serializae {
private Long id;
private String firstName;
private String lastName;
private Date irthDate;
private List<ContactTelDetail> contactTelDetails;
puic void setid(Long id)
this.id = id;

puic Long getid()


return this.id;

puic void setFirstName(String firstName) {


this.firstName = firstName;

puic String getFirstName()


return this.firstName;

puic void setLastName(String lastName) {


this.lastName = lastName;
6. JDBC Spring 289
puic String getLastName ()
return this.lastName;

puic void setContactTelDetails(List<ContactTelDetail> contactTelDetails)


{
this.contactTelDetails = contactTelDetails;

pulic List<ContactTelDetail> getContactTelDetails()


return contactTelDetails;

pulic void setBirthDate(Date birthDate)


this.birthDate = birthDate;

pulic Date getBirthDate()


return birthDate;

puic String toString()


return "Contact - Id: " + id + ", First name: " + firstName
+ ", Last name: " + lastNarne + ", Birthday: " + irthDate;

6.4. ContactTelDetail
package com.apress.prospring4.ch6;
import java.io.Serializae; }
puic class ContactTelDetail implements Serializae {
private Long id;
private Long contactld;
private String telType;
private String telNumer;
pulic void setld(Long id)
this.id = id;

pulic Long getld()


return this.id;

puic void setContactld(Long contactld)


this.contactld = contactld;

puic Long getContactld()


return this.contactld;

pulic void setTelType(String telType)


this.telType = telType;

puic String getTelType()


return this.telType;
290 6. JDBC Spring
pulic void setTelNumer(String telNumer)
this.telNumber = telNumer;

pulic String getTelNumer() {}


return this.telNumer;

@Override
puic String toString()
return "Contact Tel Detail - Id: " + id + ", Contact id: " + contactid
+ ", : " + tel + ", Numer: " + telNumer;

ContactDao,
.
6.5.
6.5. ContactDao
package com.apress.prospring4.ch6;
import java.util.List;
pulic interface ContactDao
List<Contact> findAll();
List<Contact> findByFirstName(String firstName);
String findLastNameByid(Long id);
String findFirstNameByid(Long id);
void insert(Contact contact);
void update(Contact contact);
void delete(Long contactid);

ContactDao ,
, , CRUD
(create, read, update, delete - , , ).
, , log4j,
DEBUG .
DEBUG JDBC Spring SQL-,
, , ;
SQL
oepaopax. 6.6 log4j .properties (
src/main/resources 8)
DEBUG.
6.6. log4j .properties
log4j.rootCategory=DEBUG, stdout
log4j.appender.stdout= org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern= %d{ASOLUTE} %5 %40.40c:%4L - %m%n
6. JDBC Spring 291

JDBC
JDBC Jv-
, . JDBC ,
; Jv-
.
j ava. sql.
DriverManager.
. getConnection ()
DriverManager java.sql.Connection,
. SQL- .
JDBC ; ,
.
.
,
.
.
, , ,
.
, Spring ,
, ,
JDBC.
ContactDao
JDBC. ,
,
( )
.
Java ,
.
, .
6.7 , JDBC,
MySQL.
6. 7. JDBC
package com.apress.prospring4.ch6;
puic class PlainContactDao implements ContactDao
static {
try {
Class. forName (". mysql. j d. Driver");
catch (ClassNotFoundException ) {
ex.printStackTrace();

private Connection getConnection() throws SQLException


return DriverManager.getConnection(
"jdbc:mysql://localhost:3306/prospring4_ch6",
"prospring4", "prospring4");
292 6. JDBC Spring
private void closeConnection(Connection connection) {
if (connection == null) {
return;

try {
connection.close();
catch (SQLException )
ex.printStackTrace();

, ,
JDBC.
,
.
( "
" ), 6.8
findAll (), insert () delete () ContactDao
JDBC.
6.8. DAO JDBC
package com.apress.prospring4.ch6;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
puic class PlainContactDao implements ContactDao {
static {
try {
Class. forName( "com.mysql.jdc.Driver");
catch (ClassNotFoundException ) {
ex.printStackTrace();

private Connection getConnection() throws SQLException


return DriverManager.getConnection(
"jdbc:mysql://localhost:3306/prospring4_ch6",
"prospring4", "prospring4");

private void closeConnection(Connection connection)


if (connection == null) {
return;
6. JDBC Spring 293
try {
connection.close();
catch (SQLException )
ex.printStackTrace();

@Override
puic List<Contact> findAll{) {
List<Contact> result = new ArrayList<Contact>();
Connection connection = null;
try {
connection = getConnection();
PreparedStatement statement =
connection.prepareStatement("select * from contact");
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) (
Contact contact = new Contact();
contact.setid(resultSet.getLong("id"));
contact.setFirstName(resultSet.getString("first name"));
contact.setLastName(resultSet.getString("last_name"));
contact.setBirthDate(resultSet.getDate("irth_date"));
result.add(contact);

catch (SQLException )
ex.printStackTrace();
finally {
closeConnection(connection);

return result;

@Override
pulic void insert(Contact contact)
Connection connection = null;
try {
connection = getConnection();
PreparedStatement statement = connection.prepareStatement(
"insert into Contact (first_name, last_name, irth_date) values (?, ?, ?)"
, Statement.RETURN_GENERATED_KEYS);
statement.setString(l, contact.getFirstName());
statement.setString(2, contact.getLastName());
statement.setDate(, contact.getBirthDate());
statement.execute();
ResultSet generatedKeys = statement.getGeneratedKeys();
if (generatedKeys.next()) {
contact.setid(generatedKeys.getLong(l));

catch (SQLException )
ex.printStackTrace();
finally (
closeConnection(connection);
294 6. JDBC Spring
@Override
puic void delete(Long contactid}
Connection connection = null;
try {
connection = getConnection(};
PreparedStatement statement =
connection.prepareStatement("delete from contact where id=?"};
statement.setLong(l, contactid};
statement.execute(};
catch (SQLException }
ex.printStackTrace(};
finally {
closeConnection(connection};

@Override
puic List<Contact> findByFirstName(String firstName} {
return null;

@Override
pulic String findFirstNameByid(Long id} {
return null;

@Override
puic String findLastNameByid(Long id} {
return null;

@Override
puic void update(Contact contact} {
}

6.9 ,
DAO .

6.9. , JDBC
package com.apress.prospring4.ch6;
import java.sql.Date;
import java.util.GregorianCalendar;
import java.util.List;
puic class PlainJdbcSample {
private static ContactDao contactDao = new PlainContactDao(};
pulic static void main(String [] args} {
//
System.out.println("Listing initial contact data:");
listAllContacts(};
System.out.println(};
//
System.out.println("Insert new contact"};
6. JDBC Spring 295
Contact contact = new Contact();
contact.setFirstName("Jacky");
contact.setLastName("Chan");
contact.setBirthDate(new Date(
(new GregorianCalendar(2001, 10, 1)).getTime().getTime()));
contactDao.insert(contact);
//
System.out.println("Listing contact data after new contact created:");
listAllContacts();
System.out.println();
//
System.out.println("Deleting the previous created contact");
contactDao.delete(contact.getid());.
//
System.out.println("Listing contact data after new contact deleted:");
listAllContacts();

private static void listAllContacts()


List<Contact> contacts = contactDao.findAll();
for (Contact contact: contacts) {
System.out.println(contact);

, 11 MySQL Java (. 6.1 ).

6. 1. MySQL




mysql mysql-connector-java 5.1.29 Jv- MySQL

6.9 (,
MySQL prospring4_h,
, prospring4;

schema. sql test-data. sql 11
):
Listing initial contact data:
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday: 1981-05-03
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
Insert new contact
Listing contact data after new contact created:
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday: 1981-05-03
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
Contact - Id: 4, First name: Jacky, Last name: Chan, Birthday: 2001-11-01
296 6. JDBC Spring
Deleting the previous created contact
Listing contact data after new contact deleted:
Contact - Id: 1, First : Chris, Last name: Schaefer, Birthday: 1981-05-03
Contact - Id: 2, First narne: Scott, Last narne: Tiger, Birthday: 1990-11-02
Contact - Id: 3, First narne: John, Last narne: Srnith, Birthday: 1964-02-28
.
, .
.
6.8,
, , .
JOBC -
.
, ,
: , .
,
.
Spring.
, - ,
, . ,
JOBC Spring .

JDBC Spring
, , ,
, ,
. , Spring
.

JDBC Spring
JOBC Spring ,
. 6.2; JOBC.
6.2. JDBC Spring

org.springfrarnework.jc!c.core JDBC Spring.
JDBC Jc!cTernplate,

JDBC.

JDBC
(, Jc!cTernplate,
),

org. springfr arnewor k. j d. datasource
DataSource,
JDBC JEE.

,

6. JDBC Spring 297
. 6.2

org.springframework.jdc.object ,
, ,
.
Jv-, ,

org.springframework.jdc.support
SQLException.
Spring ,
,

org.springframework.jdc.config ,
JDBC ApplicationContext.
,
jdc (,
<jdc:emedded-database>)

JDBC Spring
. ,
SQL- - .



Spring, , j avax. sql. DataSource.
DataSource Connection , DataSource
Connection.
DataSource DriverManagerDataSource
( org.springframework.jdbc.datasource). ,
, DriverManager
. , DriverManagerDataSource
,
. Dri verManagerDataSource ,
6.10; , URL
, (datasource-drivermanager. xml).
6.1 . da taSource Dri veranagerDa taSource, Spring
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
298 6. JDBC Spring
<bean id="dataSource"
class="org.springframework.jdc.datasource.DriverManagerDataSource"
p:driverClassName="${jdc.driverClassName}"
p:url="${jdbc. url}"
p:username="${jdc.username}"
p:password="${jdbc.password}"/>
<context:property-placeholder
location="classpath:META-INF/config/jdbc.properties"/>
</beans>

.
, JDBC
Connection.

. 6.11 jdbc.properties,
Spring .
6. 11. j d . properties
jdbc.driverClassName=com.mysql.jdc.Driver
jdbc.url =jdbc:mysql://localhost:3306/prospring4 h
jdbc.username=prospring4
jdc.password=prospring4

Apache
Commons BasicDataSource (http: //counons. apache.org/dbcp/)
t1 , JEE (,
JBoss, WebSphere, Weogic GlassFish),
.
JDBC ;

- . , Spring
dataSource
ApplicationContext ( 6.12
datasource-dcp. xml).
6.12. & da taSource, Spring
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
6. JDBC Spring 299
p:driverClassName="${jdc.driverClassName}"
p:url="${jdc.url}"
p:username="${jdbc.username}"
p:password="${jdc.password}"/>
<context:property-placeholder
location="classpath:META-INF/config/jdc.properties"/>
</beans>

! BasicDataSource Apache Commons



, (www.mchange.com/projects/c3p0/index.html) BoneCP
(http://jolbox.com/).

, Spring, org. apache.


commons. dbcp. BasicDataSource. ,
dataSource j avax. sql. DataSource,
.
dataSource
JNDI.
JEE, ,
. l , JNDI,
dataSource, 6.13 (datasource
jndi. xml).
6.1 . d.ataSource, JNDI Spring
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation ="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean").
p:jndiName="java:comp/env/jdbc/prospring4ch6"/>
</beans>

JndiObjectFactoryBean Spring
JNDI. 2.5,
Spring jee,
. 6.14
JNDI, jee (datasource-jee. xrnl).
6.14. d.ataSource, JNDI Spring
( jee)
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
300 6. JDBC Spring
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee.xsd">
<jee:jndi-lookup jndi-name= "java:comp/env/jdc/prospring4ch6"/>
</beans>

j
<beans> <j: jndi-lookup>
.
JNDI,
(resource-ref) ( 6.15).

6.15.
<root-node>
<resource-ref>
<res-ref-name>jdbc/prospring4ch6</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</root-node>

<root-node> ;
, . , <web-app>
- (WEB-INF/web. xrnl),
-. , resource-ref
, .
, resource-ref jdc/prospring4ch6,
jndiName dataSource java: comp/env/jdbc/
prospring4ch6.
, Spring
,
.
, , ,
.
dataSource, ,
,
JEE.


3.0, Sprig
,
. 6.16
(app-context-xml. xml).
6. JDBC Spring 301
6. 16. Spring
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdc
http://www.springframework.org/schema/jdbc/spring-jdc.xsd">
<jdbc:emedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:META-INF/sql/schema.sql"/>
<jdbc:script location="classpath:META-INF/sql/test-data.sql"/>
</jdc:emedded-database>
</beans>

jdbc
<beans>. <jdbc: embedded
database>
dataSource. Spring
,
. ,
: DDL (Data
Definition Language - )
, - DML (Data Manipulation Language -
). type
. Spring 4.0 HSQL (), 2
DERBY.

.
,
- .

JDBC, ,
- , MySQL, Orac\e ..
type emedded-database initialize-database,
,
.

DAO
ContactDao,
6.17.
6.17. Con tactDao
package com.apress.prospring4.ch;
puic interface ContactDao {
String findLastNameByid(Long id);
302 6. JDBC Spring

dataS ource
JdcC ontactDao. , dataSource
, , :
, .
, , ,
.
, .
JdcContactDao 6.18.

6.18. JdcUserDao dataSource


package com.apress.prospring4.ch6;
import javax.sql.DataSource;
puic class JdcContactDao implements ContactDao {
private DataSource dataSource;
puic void setDataSource(DataSource dataSource)
this.dataSource = dataSource;

Spring
contactDao JdcContactDao
dataSource ( app-context-xml. xml 6.19).

6.19. Spring dataSource contactDao


<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:jdc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdc
http://www.springframework.org/schema/jdc/spring-jdc.xsd">
<jdbc:emedded-database id= "dataSource" type="H2">
<jdc:script location="classpath:META-INF/sql/schema.sql"/>
<jdc:script location= "classpath:META-INF/sql/test-data.sql"/>
</jdc:emedded-database>
<bean id= "contactDao" class="com.apress.prospring4.ch6.JdcContactDao"
p:dataSource-ref="dataSource"/>
</beans>

2
(. 6.3).
6. JDBC Spring 303
6.3. 2



com.h2database h2 1.3.172 Jv- 2

Spring contactDao
JdbcContactDao dataSource,
dataSource.

. , InitializingBean
afterPropertiesSet () ( 6.20).
, JdbcContactDao
.
4.
6.20. JdcContactDao InitializingBean
package com.apress.prospring4.ch6;
import javax.sql.DataSource;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
puic class JdcContactDao implements ContactDao, InitializingBean
private DataSource dataSource;
pulic void setDataSource(DataSource dataSource)
this.dataSource = dataSource;

@Override
pulic void afterPropertiesSet() throws Exception {
if (dataSource == null) {
// dataSource ContactDao
throw new BeanCreationException ( "Must set dataSource on ContactDao") ;

, ,
Spring, ContactDao
JDBC. dataSource JdbcContactDao
ApplicationContext. ,
DAO.


Spring
, ,
SQLException Spring JDBC.
304 6. JDBC Spring

, SQL Spring,
, ,
.
,
throws ; , ,
, , .
Spring
SQLExceptionTranslator,
SQL Spring JDBC.
,
Spring SQLExceptionTranslator
JdcTemplate, 6.21.

6.21. SQLExceptionTranslator
package com.apress.prospring4.ch6;
import java.sql.SQLException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DeadlockLoserDataAccessException;
import org.springframework.jdc.support.SQLErrorCodeSQLExceptionTranslator;
puic class MySQLErrorCodesTranslator extends
SQLErrorCodeSQLExceptionTranslator
@Override
protected DataAccessException customTranslate(String task,
String sql, SQLException sqlex) {
if (sqlex.getErrorCode() == -12345) {
return new DeadlockLoserDataAccessException(task, sqlex);

return null;

spring-jdbc
(. 6.4).

6.4. spring-jdc



org.springframework spring-jdc 4.0.2.RELEASE Spring JDBC

,
JdbcTemplate DAO. 6.22
JdcContactDao. setDataSource ()
.
6. JDBC Spring 305
6.22. J1 SQLExceptionTranslator
Spring JDBC
pulic void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
JdbcTemplate jdcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
MySQLErrorCodesTranslator errorTranslator =
new MySQLErrorCodesTranslator();
errorTranslator.setDataSource(dataSource);
jdbcTemplate.setExceptionTranslator(errorTranslator);
this.jdbcTemplate = jdbcTemplate;

Spring
SQL SQL SQL-
, , -12345.
Spring .
, SQLExceptionTranslator
Spring JdbcTemplate .
, JdbcTemplate;
.

Jd.cTemplate
JOBC Spring.
SQL-. ,
.
(,
, ..).

. ,
.
, .
JdbcTemplate SQL-oepaop
.
JOBC
Spring JdcTemplate.

JdcTempla te DAO
JdcTemplate ,
JdbcTemplate .
; ,
( Spring
). 6.23 ,
JdbcTemplate.
306 6. JDBC Spring
6.23. JdcTemplate
private Jd.cTemplate jd.cTemplate;
private DataSource dataSource;
puic void setDataSource(DataSource dataSource)
this.dataSource = dataSource;
this.jd.cTemplate = new JdbcTemplate(dataSource);

u JdbcTemplate
, ,
Sprig, JdbcTemplate .
JdbcTemplate
. ,
JdbcTemplate L- Spring
.

! Srig- Jdbc JdbcDaoSupport.


JdbcTemplate
JdbcDaoSupport. DAO
Jd.cTemplate .


JdcTempla te
, . ,
.
JdbcTemplate . 6.24
findFirstNameByid () JdbcContactDao.
.
6.24. JdcTemplate
package com.apress.prospring4.ch6;
import javax.sql.DataSource;
import java.util.List;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jd.c.core.JdbcTemplate;
puic class JdbcContactDao implements ContactDao, InitializingBean
private DataSource dataSource;
private Jd.cTemplate jd.cTemplate;
@Override
puic String findFirstNameByid(Long id)
return jd.cTemplate.queryForObject(
. '
"select first name from contact where id = ?"
new Object[J {id}, String.class);
6. JDBC Spring 307
puic void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
JdbcTemplate jdcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
MySQLErrorCodesTranslator errorTranslator =
new MySQLErrorCodesTranslator();

errorTranslator.setDataSource(dataSource);
jdbcTemplate.setExceptionTranslator(errorTranslator);
this.jdcTemplate = jdcTemplate;

@Override
puic void afterPropertiesSet() throws Exception {
if (dataSource == null) {
throw new BeanCreationException("Must set dataSource on ContactDao");

if (jdcTemplate == null) {
throw new BeanCreationException ( "Null JdbcTemplate on ContactDao");


queryForObj ect () JdbcTemplate. - SQL
, - , SQL-oepaopy ,
. ,
String. Obj ect
, Long Integer.
. 6.25 .

6.25. JdcTemplate
package com.apress.prospring4.ch6;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class JdcContactDaoSarnple {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
ContactDao contactDao = ctx. getBean("contactDao", ContactDao.class);
System.out.println("First name for contact id 1 is: " +
contactDao.findFirstNarneByld(ll));

, :
First name for contact id 1 is: Chris
308 6. JDBC Spring


NamedParameterJd.cTemplate
( ?)

Obj ect. , ,
,
.

, .
Spring JdbcTemplate
NamedParameterJdbcTemplate ( org. springframework. j dbc. core.
namedparam).
NamedPa r ame t rJdbcTemp 1 t
JdbcTempla te,
NamedPar ame terJdbcTempla te
setDataSource (), 6.26.
6.26. NamedParameterJdcTemplate

package com.apress.prospring4.ch6;
import javax.sql.DataSource;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdc.core.namedparam.NamedParameterJdcTemplate;
pulic class JdbcContactDao implements ContactDao, InitializingBean
private DataSource dataSource;
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Override
puic String findLastNameByld(Long id) {
String sql = "select last_name from contact where id = :contactld";
Map<String, Object> namedParameters = new HashMap<String, Object>();
namedParameters.put( "contactld", id);

return namedParameterJdbcTemplate.queryForObject(sql,
namedParameters, String.class);

puic void setDataSource(DataSource dataSource)


this.dataSource = dataSource;
NamedParameterJdcTemplate namedParameterJdcTemplate =
new NamedParameterJdbcTemplate(dataSource);
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
6. JDBC Spring 309
@Override
pulic void afterPropertiesSet() throws Exception {
if (dataSource == null) {
throw new BeanCreationException ( "Must set dataSource on ContactDao");

if (namedParameterJdbcTemplate == null) {
throw new BeanCreationException("Null NamedParameterJdbcTemplate on
ContactDao");
}

, ? (
). 6.27
.

6.27. JdcContactDaoSample,

package com.apress.prospring4.ch6;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class JdbcContactDaoSample {
pulic static void main(String[] args) {
GenericXrnlApplicationContext ctx = new GenericXrnlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xml.xml");
ctx.refresh();
ContactDao contactDao = ctx. getBean("contactDao", ContactDao. class);
System. out. println ("Last name for contact id 1 is: " +
contactDao.findLastNameByid(ll));

, ,
:
Last name for contact id 1 is: Schaefer


Rowapper<T>


. RowMapper<T> Spring (
org. springframework. jdbc. core)
J DBC POJO.
, findAll () ContactDao
RowMapper<T>. findAll ()
6.28.
310 6. JDBC Spring

6.28. Rowapper<T>
package com.apress.prospring4.ch6;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
puic class JdcContactDao implements ContactDao, InitializingBean
private DataSource dataSource;
private NamedParameterJdcTemplate namedParameterJdcTemplate;
@Override
puic String findLastNam_eByid(Long id) (
String sql = "select last_name from contact where id = : contactid";
Map<String, Object> namedParameters = new HashMap<String, Object>();
namedParameters.put("contactid", id);

return namedParameterJdcTemplate.queryForObject(sql,
namedParameters, String.class);

@Override
puic List<Contact> findAll() {
String sql = "select id, first_name, last_name, irth_date from contact";
return namedParameterJdcTemplate.query(sql, new ContactMapper());

pulic void setDataSource(DataSource dataSource) {


this.dataSource = dataSource;
NamedParameterJdcTemplate namedParameterJdbcTemplate
new NamedParameterJdcTemplate(dataSource);
this.namedParameterJdcTemplate = namedParameterJdcTemplate;

@Override
puic void afterPropertiesSet() throws Exception {>
if (dataSource == null) {
throw new BeanCreationException("Must set dataSource on ContactDao");

if (namedParameterJdbcTemplate == null) {
throw new BeanCreationException("Null NamedParameterJdcTemplate
on ContactDao");
}

private static final class ContactMapper implements RowMapper<Contact> {


@Override
6. JDBC Spring 311
puic Contact mapRow(ResultSet rs, int rowNum) throws SQLException {
Contact contact = new Contact();
contact.setid(rs.getLong("id"));
contact.setFirstName(rs.getString("first_name"));
contact.setLastName(rs.getString("last_name"));
contact.setBirthDate(rs.getDate("irth_date"));
return contact;


ContactMapper, RowMapper<T>.
mapRow (),
.

RowMapper<T> .

-
Java 8 ContactMapper, ,
-:
@Override
puic List<Contact> findAll()
String sql = "select id, first_name, last_name, irth date from contact";
return namedParameterJdbcTemplate.query(sql, (rs, rowNum) -> {
Contact contact = new Contact();
contact.setid(rs.getLong("id"));
contact.setFirstName(rs.getString("first_name"));
contact.setLastName(rs.getString("last_name"));
contact.setBirthDate(rs.getDate("irth_date"));
return contact; >
});

find.All () ,
. ,
, query () ,
.
JdbcContactDaoSample
( 6.29).

6.29.
package com.apress.prospring4.ch6;
import java.util.List;
import org.springframework.context.support.GenericXrnlApplicationContext;
312 6. JDBC Spring
puic class JdcContactDaoSample
pulic static void main (String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:ETA-INF/spring/app-context-xml.xml");
ctx.refresh();>
ContactDao contactDao = ctx.getBean("contactDao", ContactDao.class) ;
List<Contact> contacts = contactDao.findAll();
for (Contact contact: contacts) {
System.out.println(contact);
if (contact.getContactTelDetails() != null)
for (ContactTelDetail contactTelDetail:
contact.getContactTelDetails()) {
System.out.println("---" + contactTelDetail);

System.out.println();

:
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday: 1981-05-03
Contact - Id: 2, First name: Scott, Last narne: Tiger, Birthday: 1990-11-02
Contact - Id: , First name: John, Last name: Srnith, Birthday: 1964-02-28


Resul tSetExtractor
,
(CONTACT) (CONTACT_TEL_DETAIL)
,
(ContactTelDetail Contact).
RowMapper<T>
.
Resul tSetExtractor.
, ContactDao
findAllWithDetail ().
.
6.30 findAllWi thDetail ()
ResultSetExtractor.
6.30. Resul tSetExtractor

package com.apress.prospring4.ch6;
import java.util.List;
puic interface ContactDao {
String findLastNarneByid(Long id);
List<Contact> findAllWithDetail();
6. JDBC Spring 313
package com.apress.prospring4.ch6;
import javax.sql.DataSource;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdc.core.namedparam.NamedParameterJdcTemplate;
pulic class JdbcContactDao implements ContactDao, InitializingBean
private DataSource dataSource;
private NamedParameterJdbcTemplate namedParameterJdcTemplate;
@Override
puic String findLastNameByid(Long id) {
String sql = "select last_name from contact where id = :contactid";
Map<String, Object> namedParameters = new HashMap<String, Object>();
namedParameters.put("contactid", id);

return namedParameterJdcTemplate.queryForObject(sql,
namedParameters, String.class);

@Override
puic List<Contact> findAllWithDetail() {
String sql = "select c.id, c.first_name, c.last_name, c.irth date" +
", t.id as contact_tel_id, t.tel_type, t.tel_numer from contact " +
"left join contact_tel_detail t on c.id = t.contact_id";
return namedParameterJdcTemplate.query(sql, new ContactWithDetailExtractor());

puic void setDataSource(DataSource dataSource) {


this.dataSource = dataSource;
NamedParameterJdcTemplate namedParameterJdcTemplate
new NamedParameterJdcTemplate(dataSource);
this.namedParameterJdcTemplate = namedParameterJdcTemplate;

@Override
pulic void afterPropertiesSet() throws Exception {
if (dataSource == null) {
throw new BeanCreationException("Must set dataSource on ContactDao") ;

if (namedParameterJdcTemplate == null)
throw new BeanCreationException("Null NamedParameterJdbcTemplate
on ContactDao");
}
314 6. JDBC Spring
private static final class ContactWithDetailExtractor implements
ResultSetExtractor<List<Contact>>
@Override
puic List<Contact> extractData(ResultSet rs) throws SQLException,
DataAccessException {
Map<Long, Contact> map = new HashMap<Long, Contact>();
Contact contact = null;
while (rs.next()) {
Long id = rs.getLong("id");
contact = map.get(id);
if (contact == null) {
contact = new Contact();
contact.setid(id);
contact.setFirstName(rs.getString("first_name") );
contact.setLastName(rs.getString("last_name"));
contact.setBirthDate(rs.getDate("birth_date"));
contact.setContactTelDetails(new ArrayList<ContactTelDetail>());
rnap.put(id, contact);

Long contactTelDetailid = rs.getLong("contact_ tel _ id");


if (contactTelDetailid > ) {
ContactTelDetail contactTelDetail = new ContactTelDetail();
contactTelDetail.setid(contactTelDetailid);
contactTelDetail.setContactid(id);
contactTelDetail.setTelType(rs.getString("tel type"));
contactTelDetail.setTelNurner(rs.getString("tel_numer"));
contact.getContactTelDetails() .add(contactTelDetail);

return new ArrayList<Contact> (rnap.values());

R owMapper,
, Resul tSetExtractor. ex
tractData ()
Contact. findAllWithDetail ()
, .
. ,
JdbcTemplate. query (),
ResultSetExtractor.

r -
Java 8 ContactWi thDetailExtractor,
, -:
@Override
puic List<Contact> findAllWithDetail() {
6. JDBC Spring 315
String sql = "select c.id, c.first_name, c.last_name, c.irth_date" +
", t.id as contact_tel_id, t.tel_type, t.tel_numer from contact " +
"left join contact_tel_detail t on c.id = t.contact_id";
return namedParameterJdbcTemplate.query(sql, (ResultSet rs) -> (
Map<Long, Contact> map = new HashMap<Long, Contact>();
Contact contact = null;
while (rs.next()) (
Long id = rs.getLong("id");
contact = map.get(id);
if (contact == null) (
contact = new Contact();
contact.setid(id);
contact.setFirstName(rs.getString("first_name"));
contact.setLastName(rs.getString("last_name"));
contact.setBirthDate(rs.getDate("irth_date"));
contact.setContactTelDetails(new ArrayList<ContactTelDetail>());
map.put(id, contact);
}
Long contactTelDetailid = rs.getLong("contact_tel id");
if (contactTelDetailid > ) {
ContactTelDetail contactTelDetail = new ContactTelDetail();
contactTelDetail.setid(contactTelDetailid);
contactTelDetail.setContactid(id);
contactTelDetail.setTelType(rs.getString("tel type"));
contactTelDetail.setTelNumer(rs.getString("tel_numer"));
contact.getContactTelDetails().add(contactTelDetail);

return new ArrayList<Contact> (map.values());


}) ;

6.31 JdbcContactDaoSample,
.

6.31. Resul tSetExtractor


package com.apress.prospring4.ch6;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class JdbcContactDaoSample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-xrnl.xml");
ctx.refresh();
ContactDao contactDao = ctx.getBean("contactDao", ContactDao.class);
List<Contact> contactsWithDetail = contactDao.findAllWithDetail();
for (Contact contact: contactsWithDetail)
System.out.println(contact);
316 6. JDBC Spring
if (contact.getContactTelDetails() != null) {
for (ContactTelDetail contactTelDetail: contact.getContactTelDetails())
System.out.println("---" + contactTelDetail);

System.out.println();

, :
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
---Contact Tel Detail - Id: 3, Contact id: 2, : , Numer: 1234567890
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday: 1981-05-03
---Contact Tel Detail - Id: 2, Contact id: 1, : , Numer: 1234567890
---Contact Tel Detail - Id: 1, Contact id: 1, : Mobile, Numer: 1234567890
,
. 6.2.
, JdbcTemplate
. JdbcTempla te (
NamedParameterJdbcTemplate)
update (), , ,
, .. update ()
, . ,
,
SglUpdate, Spring.

Spring, JDBC
, JdbcTemplate

JDBC.
JdbcTemplate Spring ,
JDBC

- . ,
.
MappingSqlQuery<T>. MappingSglQuery<T>
mapRow () .
SqlUpdate. SglUpdate SQL
oepaop .
SQL-,
..
BatchSqlUpdate. BatchSglUpdate
. , Jv-
6. JDBC Spring 317
List BatchSqlUpdate ,
.
.
SqlFunction<T>. SqlFunction<T>
r .
, StoredProcedure, .

D- JDBC
, DAO,
. ContactDao
, .
6.32 ContactDao
.
6.32. ContactDao
package com.apress.prospring4.ch6;
import java.util.List;
puic interface ContactDao {
List<Contact> finc!All();
List<Contact> findByFirstName(String firstName);
String findFirstNameByid(Long id);
List<Contact> finc:IAllWithDetail();
void insert(Contact contact);
void insertWithDetail(Contact contact);
void update(Contact contact);

6.33
JSR-250.
6.33. JdcContactDao
package com.apress.prospring4.ch6;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Repository;
@Repository ( "contactDao")
pulic class JdcContactDao implements ContactDao {
private Log log = LogFactory.getLog(JdcContactDao.class);

private DataSource dataSource;


@Resource(name="dataSource")
puic void setDataSource(DataSource dataSource)
this.dataSource = dataSource;
318 6. JDBC Spring
pulic DataSource getDataSource()
return dataSource;

@Repository
Spring contactDao,
, @Repository Spring
SQL, ,
DataAccessException, .
log commons-logging Apache
. ,
@Resource JSR-250,
Spring dataSource.
6.34 L- Spring,
(app-context-annotation. xml).
6.34. Lr Spring,
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdc
http://www.springframework.org/schema/jdc/spring-jdc.xsd">
<context:component-scan base-package="com.apress.prospring4.ch6"/>
<jdbc:emedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:META-INF/sql/schema.sql"/>
<jdbc:script location="classpath:META-INF/sql/test-data.sql"/>
</jdc:emedded-database>
</beans>

2
<context: component-scan>
Spring. ,
JDBC.

appingSqlQuery<T>
Spring
MappingSqlQuery<T>. , MappingSqlQuery<T>,
. mapRow ()

.
6. JDBC Spring 319
SelectAllContacts (
r1 ),
MappingSqlQuery<T>. SelectAllContacts 6.35.
6.35. SelectAllContacts
package com.apress.prospring4.ch6;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.jdbc.object.MappingSqlQuery;
puic class SelectAllContacts extends MappingSqlQuery<Contact>
private static final String SQL_SELECT_ALL_CONTACT =
"select id, first_name, last_name, irth_date from contact";
puic SelectAllContacts(DataSource dataSource)
super(dataSource, SQL_SELECT_ALL_CONTACT);

protected Contact mapRow(ResultSet rs, int rowNum) throws SQLException {


Contact contact = new Contact();
contact.setid(rs.getLong("id"));
contact.setFirstName(rs.getString("first_name"));
contact.setLastName(rs.getString("last_name"));
contact.setBirthDate(rs.getDate("irth_date"));
return contact;

SelectAllContacts SQL-oepaop r1
. super () r1
, SQL-onepaop. ,
MappingSqlQuery<T>. mapRow (), r1
Contact.
SelectAllContacts, findAll ()
JdbcContactDao, 6.36.
6.36. findAll ()
package com.apress.prospring4.ch6;
import java.util.List;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Repository;
@Repository("contactDao")
puic class JdcContactDao implements ContactDao {
private static final Log LOG = LogFactory.getLog(JdcContactDao.class);
320 6. JDBC Spring
private DataSource dataSource;
private SelectAllContacts selectAllContacts;
@Override
puic List<Contact> findAll() {
return selectAllContacts.execute();

@Override
puic List<Contact> findByFirstName(String firstName) {
return null;

@Override
puic String findFirstNameByid(Long id) {.
return null;

@Override
puic void insert(Contact contact) {
}
@Override
pulic void update(Contact contact)
}
@Resource(name= "dataSource")
puic void setDataSource(DataSource dataSource)
this.dataSource = dataSource;
this.selectAllContacts = new SelectAllContacts(dataSource);

puic DataSource getDataSource()


return dataSource;

setDataSource ()
SelectAllContacts. findAll ()
SelectAllContacts. execute (),
SqlQuery<T>. , . 6.37
.

6.37. appingSqlQuery
package com.apress.prospring4.ch;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class AnnotationJdcDaoSample {
puic static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
ContactDao contactDao = ctx.getBean("contactDao", ContactDao.class);
List<Contact> contacts = contactDao.findAll();
listContacts(contacts);
6. JDBC Spring 321
private static void listContacts(List<Contact> contacts) {
for (Contact contact: contacts) {
System.out.println(contact);
if (contact.getContactTelDetails() != null) {
for (ContactTelDetail contactTelDetail: contact.getContactTelDetails())
System.out.println("---" + contactTelDetail);

System.out.println();

:
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday: 1981-05-03
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
- , DEBUG,
, Spring:
JdcTemplate: 663 - Executing prepared SQL query
JdbcTemplate: 597 - Executing prepared SQL statement [select id,
first_name, last_name, birth_date from contact]
findByFirstName (),
. ,
SelectContactByFirstName, 6.38.
6.38. SelectContactyFirstName
package com.apress.prospring4.ch6;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql. Types;
import javax.sql.DataSource;
import org.springframework.jdbc.object.MappingSqlQuery;
import org.springframework.jdbc.core.SqlParameter;
pulic class SelectContactByFirstName extends MappingSqlQuery<Contact>
private static final String SQL_FIND_BY_FIRST_NAE =
"select id, first_name, last_name, irth_date from contact where
first-name = : first-name";
pulic SelectContactByFirstName(DataSource dataSource) {
super(dataSource, SQL_FIND_BY_FIRST_NAE);
super.declareParameter(new SqlParameter("first_name", Types.VARCAR));

protected Contact mapRow(ResultSet rs, int rowNum) throws SQLException {


Contact contact = new Contact();
contact.setld(rs.getLong("id"));
contact.setFirstName(rs.getString("first_name"));
contact.setLastName(rs.getString("last_name"));
contact.setBirthDate(rs.getDate("irth_date"));
return contact;
322 6. JDBC Spring

SelectContactByFirstName SelectAllContacts.
SQL-onepaop first name.
declareParameter () (
org. springframework. jdbc. object.
RdbmsOperation). findByFirstName ()
JdcContactDao. 6.39.
6.39. findyFirstName ()
package com.apress.prospring4.ch;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Repository;
@Repository ( "contactDao")
pulic class JdbcContactDao implements ContactDao {
private static final Log LOG = LogFactory.getLog(JdbcContactDao.class);
private DataSource dataSource;
private SelectAllContacts selectAllContacts;
private SelectContactByFirstName selectContactByFirstName;
@Override
pulic List<Contact> findAll() {
return selectAllContacts.execute();
@Override
puic List<Contact> findByFirstName(String firstName) {
Map<String, Object> paramap = new HashMap<String, Object>();
paramap.put("first_name", firstName);
return selectContactByFirstName.executeByNamedParam(paramap);
@Override
pulic String findFirstNameByid(Long id)
return null;

@Override
puic void insert(Contact contact) {
}
@Override
pulic void update(Contact contact) {.
}
@Resource(name="dataSource")
puic void setDataSource(DataSource dataSource)
this.dataSource = dataSource;
this.selectAllContacts = new SelectAllContacts(dataSource);
this.selectContactByFirstName = new SelectContactByFirstName(dataSource);

puic DataSource getDataSource()


return dataSource;
6. JDBC Spring 323
SelectContactByFirstName.
findByFir stName () Ha shMap
.
, executeByNamedParam () (
SqlQuery<T> ).
, 6.40.

6.40. findyFirstName ()
package com.apress.prospring4.ch6;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class AnnotationJdcDaoSample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
ContactDao contactDao = ctx.getBean("contactDao", ContactDao.class);
List<Contact> contacts = contactDao.findByFirstName("Chris");
listContacts(contacts);

private static void listContacts(List<Contact> contacts)


for (Contact contact: contacts) {
System.out.println(contact);
if (contact.getContactTelDetails() != null) {
for (ContactTelDetail contactTelDetail:
contact.getContactTelDetails()) {
System.out.println("---" + contactTelDetail);

System.out.println();

findByFirstName ():
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday: 1981-05-03
: Map p ingSqlQuery<T> )])]
.
- JdbcTemp late ResultSetExtractor,
finc:IAllWithDetail (),
JdcTemplate.

SqlUpda te
Spring SqlUpdate. 6.41
UpdateContact, SqlUpdate
.
324 6. JDBC Spring
6.41. UpdateContact
package com.apress.prospring4.ch6;
import java.sql.Types;
import javax.sql.DataSource;
import org.springframework.jdc.core.SqlParameter;
import org.springframework.jdc.object.SqlUpdate;
puic class UpdateContact extends SqlUpdate {
private static final String SQL_UPDATE_CONTACT =
"update contact set first_name=:first_name,
last_name=:last_name, rth_date=:irth date where id=:id";
pulic UpdateContact(DataSource dataSource) {
super(dataSource, SQL_UPDATE_CONTACT);
super.declareParameter(new SqlParameter("first_name", Types.VARCAR));
super.declareParameter(new SqlParameter("last_name", Types.VARCHAR));
super.declareParameter(new SqlParameter("irth_date", Types.DATE));
super.declareParameter(new SqlParameter("id", Types.INTEGER));

.
SqlUpdate , .
6.42 update (} JdcContactDao.
6.42. SqlUpdate
package com.apress.prospring4.ch6;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Repository;
@Repository( "contactDao")
puic class JdbcContactDao implements ContactDao {
private static final Log LOG = LogFactory.getLog(JdcContactDao.class);

private DataSource dataSource;


private SelectAllContacts selectAllContacts;
private SelectContactByFirstName selectContactByFirstName;
private UpdateContact updateContact;
@Override
puic List<Contact> findAll() {
return selectAllContacts.execute();

@Override
6. JDBC Spring 325
puic List<Contact> findByFirstName(String firstName} {
Map<String, Object> paramap = new HashMap<String, Object>(};
paramap.put("first_name", firstName};
return selectContactByFirstName.executeByNamedParam(paramap};

@Override
puic String findFirstNameByid(Long id) {
return null;

@Override
puic void insert(Contact contact) {
)
@Override
puic void update(Contact contact} {
Map<String, Object> paramap = new HashMap<String, Object>(};
paramap.put("first_name", contact.getFirstName(}};
paramap.put("last_name", contact.getLastName(}};
paramap. put("irth_date", contact.getBirthDate(}};
paramap.put("id", contact.getid(}};
updateContact.updateByNamedParam(paramap};

LOG.info( "Existing contact updated with id: " + contact.getid(}};

@Resource(name="dataSource"}
puic void setDataSource(DataSource dataSource}
this.dataSource = dataSource;
this.selectAllContacts = new SelectAllContacts(dataSource};
this.selectContactByFirstName = new SelectContactByFirstName(dataSource};
this.updateContact = new UpdateContact(dataSource};

puic DataSource getDataSource(}


return dataSource;


UpdateContact. update () Contact
HashMap , up
da teByNamedParam () .
, AnnotationJdbcDaoSample,
6.43.

6.43. upda te ()
package com.apress.prospring4.ch6;
import java.util.List;
import java.util.GregorianCalendar;
import java.sql.Date;
import org.springframework.context.support.GenericXmlApplicationContext;
326 6. JDBC Spring
puic class AnnotationJdcDaoSarnple
puic static void main(String [] args)
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
ContactDao contactDao = ctx.getBean( "contactDao", ContactDao.class);
Contact contact = new Contact();
contact.setid(ll);
contact.setFirstName("Chris");
contact.setLastNarne("John");
contact.setBirthDate(new Date(
(new GregorianCalendar(1977, 10, 1)).getTime().getTime()));

contactDao.update(contact);
listContacts(contactDao.findAll());

private static void listContacts(List<Contact> contacts)


for (Contact contact: contacts) {
System.out.println(contact);
if (contact.getContactTelDetails() != null)
for (ContactTelDetail contactTelDetail:
contact.getContactTelDetails()) {
System.out.println("---" + contactTelDetail);

System.out.println();

Contact update ().


listContacts ():
INFO com.apress.prospring4.ch6.JdbcContactDao: 60 - Existing contact
updated with id: 1
Contact - Id: 1, First name: Chris, Last name: John, Birthday: 1977-11-01
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
, 1
.


SqlUpdate.
, (
).
, ,
. r AUTO_ INCREMENT -
6. JDBC Spring 327
,
. Orac\e, , ,
Orac\e
.
JDBC - . ,
MySQL SQL-onepaop select last insert id (),
Microsoft SQL Server - select @@IDENTITY.
, JDBC 3.0,
,
. 6.45 insert (),
.
( );
, JDBC, JDBC 3.0
.
InsertContact ,
SqlUpdate. InsertContact 6.44.
6.44. InsertContact
package com.apress.prospring4.ch6;
import java.sql.Types;
import javax.sql.DataSource;
import org.springframework.jdc.core.SqlParameter;
import org.springframework.jdc.object.SqlUpdate;
pulic class InsertContact extends SqlUpdate {
private static final String SQL_INSERT_CONTACT =
"insert into contact (first_name, last_name, irth date) values
(: first_name, :last_name, :irth_date)";
pulic InsertContact(DataSource dataSource) {
super(dataSource, SQL_INSERT_CONTACT);
super.declareParameter(new SqlParameter("first_name", Types.VARCAR));
super .declareParameter(new SqlParameter("last_name", Types.VARCHAR));
super.declareParameter(new SqlParameter("irth_date", Types.DATE));
super.setGeneratedKeysColumnNames(new String[] {"id"});
super.setReturnGeneratedKeys(true);

InsertContact UpdateContact;
.
InsertContact
SqlUpdate. setGeneratedKeysColumnNames ()
. SqlUpdate. setReturnGeneratedKeys ()
JDBC .
6.45 i n s e r t ()
JdbcContactDao.
328 6. JDBC Spring

6.45. SqlUpdate
package com.apress.prospring4.ch6;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Repository;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdc.support.KeyHolder;
@Repository("contactDao")
pulic class JdcContactDao implements ContactDao {
private static final Log LOG = LogFactory.getLog(JdbcContactDao.class);

private DataSource dataSource;


private SelectAllContacts selectAllContacts;
private SelectContactByFirstName selectContactByFirstName;
private UpdateContact updateContact;
private InsertContact insertContact;
@Override
puic List<Contact> findAll() {
return selectAllContacts.execute();

@Override
pulic List<Contact> findByFirstName(String firstName) {
Map<String, Object> paramap = new HashMap<String, Object>();
paramap.put("first_name", firstName);
return selectContactByFirstName.executeByNamedParam(paramap);

@Override
puic String findFirstNameByid(Long id) {
return null;

@Override
puic void insert(Contact contact)
Map<String, Object> paramap = new HashMap<String, Object>();
paramap.put("first_name", contact.getFirstName());
paramap.put("last_name", contact.getLastName());
paramap.put("birth_date", contact.getBirthDate());
KeyHolder keyHolder = new GeneratedKeyHolder();
insertContact.updateByNamedParam(paramap, keyHolder);
contact.setid(keyHolder.getKey().longValue());
LOG.info("New contact inserted with id: " + contact.getid());

@Override
6. JDBC Spring 329
pulic void update(Contact contact) {
Map<String, Object> paramap = new HashMap<String, Object>();
paramap.put("first_name", contact.getFirstName());
paramap.put("last_name", contact.getLastName());
paramap.put("irth_date", contact.getBirthDate());
paramap.put("id", contact.getid());
updateContact.updateByNamedParam(paramap);

LOG.info("Existing contact updated with id: " + contact.getid());

@Resource(name="dataSource")
pulic void setDataSource(DataSource dataSource)
this.dataSource = dataSource;
this.selectAllContacts = new SelectAllContacts(dataSource);
this.selectContactByFirstName = new SelectContactByFirstName(dataSource);
this.updateContact = new UpdateContact(dataSource);
this.insertContact = new InsertContact(dataSource);

puic DataSource getDataSource()


return dataSource;

InsertContact. r
insert () SqlUpdate. updateByNamedParam ().
, KeyHolder,
.
KeyHolder.
6.46 An notationJdbc
DaoSample.
6.46. insert ()
package com.apress.prospring4.ch;
import java.util.List;
import java.util.GregorianCalendar;
import java.sql.Date;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class AnnotationJdbcDaoSample {
pulic static void main(String [] args) {
GenericXmlApplicationContext ctx = new
GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
ContactDao contactDao = ctx.getBean("contactDao", ContactDao.class);
Contact contact = new Contact();
contact.setFirstName("Rod");
contact.setLastName("Johnson");
contact.setBirthDate(new Date((new GregorianCalendar(2001, 10, 1))
.getTime().getTime()));
330 6. JDBC Spring
contactDao.insert(contact);
listContacts(contactDao.find.All());

private static void listContacts(List<Contact> contacts)


for (Contact contact: contacts) {
System.out.println(contact);
if (contact.getContactTelDetails() != null)
for (ContactTelDetail contactTelDetail:
contact.getContactTelDetails()) {
System.out.println("---" + contactTelDetail);

System.out.println();

-
listContacts ():
INFO com.apress.prospring4.ch6.JdbcContactDao: 62 - New contact
inserted with id: 4
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday: 1981-05-03
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
Contact - Id: 4, First name: Rod, Last name: Johnson, Birthday: 2001-11-01
, 4 -
.

tchSqlUpda te
BatchSqlUpdate.
insertWi thDetail ()
.
,
InsertContactTelDetail, 6.47.
6.47. InsertContactTelDetail
package com.apress.prospring4.ch6;
import java.sql.Types;
import javax.sql.DataSource;
import org.springframework.jdc.core.SqlParameter;
import org.springframework.jdc.object.BatchSqlUpdate;
puic class InsertContactTelDetail extends BatchSqlUpdate
private static final String SQL_INSERT_CONTACT_TEL =
"insert into contact_tel_detail (contact_id, tel_type, tel_numer)
values (:contact_id, :tel_type, :tel_numer)";
6. JDBC Spring 331
private static final int BATCH_SIZE = 10;
pulic InsertContactTelDetail(DataSource dataSource)
super(dataSource, SQL_INSERT_CONTACT_TEL);
declareParameter(new SqlParameter("contact_id", Types. INEGER));
declareParameter(new SqlParameter("tel_type", Types.VARCAR));
declareParameter(new SqlParameter("tel_numer", Types.VARCHAR));
setBatchSize(BATCH_SIZE);

,
BatchSqlUpdate. setBatchSize ()
J D .
6.48 insertWithDetail ()
JdbcContactDao.
6.48. SQL-
package com.apress.prospring4.ch6;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Repository;
import org.springframework.jdc.core.JdcTemplate;
import org.springframework.jdc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.jdc.core.ResultSetExtractor;
import org.springframework.dao.DataAccessException;
@Repository("contactDao")
pulic class JdcContactDao implements ContactDao {
private static final Log LOG = LogFactory.getLog(JdcContactDao.class);

private DataSource dataSource;


private SelectAllContacts selectAllContacts;
private SelectContactByFirstName selectContactByFirstName;
private UpdateContact updateContact;
private InsertContact insertContact;
private InsertContactTelDetail insertContactTelDetail;
@Override
puic List<Contact> findAll()
return selectAllContacts.execute();
332 6. JDBC Spring
@Override
puic List<Contact> findByFirstName(String firstName) {
Map<String, Object> paramap = new HashMap<String, Object>();
paramap.put("first_name", firstName);
return selectContactByFirstName.executeByNamedParam(paramap);

@Override
puic String findFirstNameByid(Long id) {
return null;

@Override
puic void insert(Contact contact) {
Map<String, Object> paramap = new HashMap<String, Object>();
paramap.put("first_name", contact.getFirstName());
paramap.put("last_name", contact.getLastName());
paramap.put("birth_date", contact.getBirthDate());
KeyHolder keyHolder = new GeneratedKeyHolder();
insertContact.updateByNamedParam(paramap, keyHolder);
contact.setid(keyHolder.getKey().longValue());
LOG.info("New contact inserted with id: " + contact.getid());

@Override
puic void insertWithDetail(Contact contact) {
insertContactTelDetail = new InsertContactTelDetail(dataSource);
Map<String, Object> paramap = new HashMap<String, Object>();
paramap.put("first_name", contact.getFirstName());
paramap.put("last_name", contact.getLastName());
paramap.put("birth_date", contact.getBirthDate());
KeyHolder keyHolder = new GeneratedKeyHolder();
insertContact.updateByNamedParam(paramap, keyHolder);
contact.setid(keyHolder.getKey().longValue());
LOG.info("New contact inserted with id: " + contact.getid());
List<ContactTelDetail> contactTelDetails
contact.getContactTelDetails();
if (contactTelDetails != null) {
for (ContactTelDetail contactTelDetail: contactTelDetails)
paramap = new HashMap<String, Object>();
paramap.put("contact_id", contact.getid());
paramap.put("tel_type", contactTelDetail.getTelType());
paramap.put("tel_numer", contactTelDetail.getTelNumer());
insertContactTelDetail.updateByNamedParam(paramap);

insertContactTelDetail.flush();

@Override
6. JDBC Spring 333
puic List<Contact> findAllWithDetail()
JdcTemplate jdcTemplate = new JdcTemplate(getDataSource());
String sql = "select c.id, c.first_name, c.last_name, c.irth_date" +
t.id as contact_tel_id, t.tel_type, t.tel_nurner from contact " +
"left join contact_tel_detail t on c.id = t.contact_id";
return jdbcTemplate.query(sql, new ContactWithDetailExtractor());

@Override
puic void update(Contact contact) {
Map<String, Object> paramap = new HashMap<String, Object>();
paramap.put("first_name", contact.getFirstName());
paramap.put("last_name", contact.getLastName());
paramap.put("irth_date", contact.getBirthDate());
paramap.put("id", contact.getid());
updateContact.updateByNamedParam(paramap);

LOG.info("Existing contact updated with id: " + contact.getid());

@Resource(name="dataSource")
puic void setDataSource(DataSource dataSource)
this.dataSource = dataSource;
this.selectAllContacts = new SelectAllContacts(dataSource);
this.selectContactByFirstName = new SelectContactByFirstName(dataSource);
this.updateContact = new UpdateContact(dataSource);
this.insertContact = new InsertContact(dataSource);

puic DataSource getDataSource()


return dataSource;

private static final class ContactWithDetailExtractor


implements ResultSetExtractor<List<Contact>> {
@Override
puic List<Contact> extractData(ResultSet rs) throws
SQLException, DataAccessException {
Map<Long, Contact> map = new HashMap<Long, Contact>();
Contact contact = null;
while (rs.next()) {
Long id = rs.getLong("id");
contact = map.get(id);

if (contact == null) {
contact = new Contact();
contact.setid(id);
contact.setFirstName(rs.getString("first_name"));
contact.setLastName(rs.getString("last_name"));
contact.setBirthDate(rs.getDate("irth_date"));
contact.setContactTelDetails(new ArrayList<ContactTelDetail>());
map.put(id, contact);
334 6. JDBC Spring
Long contactTelDetailid = rs.getLong("contact_tel_id");
if (contactTelDetailid > ) {
ContactTelDetail contactTelDetail = new ContactTelDetail();
contactTelDetail.setid(contactTelDetailid);
contactTelDetail.setContactid(id);
contactTelDetail.setTelType(rs.getString("tel_type"));
contactTelDetail.setTelNumer(rs.getString("tel_numer"));
contact.getContactTelDetails() .add(contactTelDetail);

return new ArrayList<Contact> (map.values());

insertWithDetail ()
InsertContactTelDetail, .. BatchSqlUpdate
. SqlUpdate.
, BatchSqlUpdate
. ,
, Spring
. ,
BatchSqlUpdate. flush (), Spring
(.. , ,
). ,
ContactTelDetail Contact
BatchSqlUpdate. updateByNamedParam ().
findAllWithDetail ().

r -
Java 8 ContactWithDetailExtractor,
, -:
@Override
puic List<Contact> findAllWithDetail() {
JdcTemplate jdcTemplate = new JdcTemplate(getDataSource());
String sql = "select c.id, c.first_name, c.last_name, c.rth_date" +
t.id as contact_tel_id, t.tel_type, t.tel_numer from contact " +
"left join contact_tel_detail t on c.id = t.contact_id";
return jdbcTemplate.query(sql, (ResultSet rs) -> {
Map<Long, Contact> map = new HashMap<Long, Contact>();
Contact contact = null;
while (rs.next()) {
Long id = rs.getLong( "id");
contact = map.get(id);
if (contact == null) {
contact = new Contact();
contact.setld(id);
6. JDBC Spring 335
contact.setFirstName(rs.getString("first_name"));
contact.setLastName(rs.getString("last_name"));
contact.setBirthDate(rs.getDate("birth_date"));
contact.setContactTelDetails(new ArrayList<ContactTelDetail>());
map.put(id, contact);

Long contactTelDetailid = rs.getLong("contact_tel_id");


if (contactTelDetailid > ) {
ContactTelDetail contactTelDetail = new ContactTelDetail();
contactTelDetail.setld(contactTelDetailid);
contactTelDetail.setContactid(id);
contactTelDetail.setTelType(rs.getString("tel_type"));
contactTelDetail.setTelNumer(rs.getString("tel_numer"));
contact.getContactTelDetails().add(contactTelDetail);

return new ArrayList<Contact> (map.values());


}} ;

6.49 AnnotationJdbc
DaoSample, .

6.49. insertWi thDetail ()


package com.apress.prospring4.ch6;
import java.util.List;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.sql.Date;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class AnnotationJdbcDaoSample {
pulic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
ContactDao contactDao = ctx.getBean("contactDao", ContactDao.class);
Contact contact = new Contact();
contact.setFirstName("Michael");
contact.setLastName("Jackson");
contact.setBirthDate(new Date((new GregorianCalendar(1964, 10, 1))
.getTime().getTime()) );
List<ContactTelDetail> contactTelDetails = new ArrayList<ContactTelDetail>();
ContactTelDetail contactTelDetail = new ContactTelDetail();
contactTelDetail.setTelType("Home");
contactTelDetail.setTelNumer("11111111");
contactTelDetails.add(contactTelDetail);

contactTelDetail = new ContactTelDetail();


336 6. JDBC Spring
contactTelDetail.setTelType("Moile");
contactTelDetail.setTelNurner("22222222");

contactTelDetails.add(contactTelDetail);
contact.setContactTelDetails(contactTelDetails);
contactDao.insertWithDetail(contact);
listContacts(contactDao.findAllWithDetail());

private static void listContacts(List<Contact> contacts)


for (Contact contact: contacts) {
System.out.println(contact);
if (contact.getContactTelDetails() != null)
for (ContactTelDetail contactTelDetail:
contact.getContactTelDetails()) {
System.out.println("---" + contactTelDetail);

System.out.println();


listContacts () :
Contact - Id: l, First name: Chris, Last name: Schaefer, Birthday: 1981-05-03
---Contact Tel Detail - Id: 2, Contact id: 1, : Home, Nurner: 1234567890
---Contact Tel Detail - Id: l, Contact id: 1, : Moile, Nurner: 1234567890
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
---Contact Tel Detail - Id: 3, Contact id: 2, : , Nurner: 1234567890
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
Contact - Id: 4, First name: Michael, Last : Jackson, Birthday: 1964-11-01
---Contact Tel Detail - Id: 4, Contact id: 4, : Home, Numer: 11111111
---Contact Tel Detail - Id: 5, Contact id: 4, : Moile, Nurner: 22222222
,
.

SqlFunction
Spring ,
/ JDBC. ,
SqlFunction.
MySQL,
SqlFunction<T>.
, MySQL prospring4 _h,
, prospring4 (
, "
JDBC"). getFirstNameByid (),
.
6. JDBC Spring 337
6.50
MySQL (stored-function .sql).
MySQL.

.50. MySQL
DELIMITER //
CREATE FUNCTION getFirstNameByld(in_id INT)
RETURNS VARCAR(60)
BEGIN
RETURN (SELECT first name FROM contact WHERE id = in_id);
END //
DELIMITER ;


.
StoredFunctionFirstNameByid,
,
SqlFunction<T>. 6.51.

.51. Stored.FunctionFirstNameByid
package com.apress.prospring4.ch;
import java.sql.Types;
import javax.sql.DataSource;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.SqlFunction;
pulic class StoredFunctionFirstNameByid extends SqlFunction<String>
private static final String SQL = "select getfirstnamebyid(?) ";
pulic StoredFunctionFirstNameByid (DataSource dataSource)
super(dataSource, SQL);
declareParameter(new SqlParameter(Types.INTEGER));
compile ();

SqlFunction<T> String,
. SQL
MySQL.
. .
6.52 JdcContactDao,
.
.52. JdcContactDao,
package com.apress.prospring4.ch6;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
338 6. JDBC Spring
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Repository;
import org.springframework.jdc.core.JdcTemplate;
import org.springframework.jdc.support.GeneratedKeyHolder;
import org.springframework.jdc.support.KeyHolder;
import org.springframework.jdc.core.ResultSetExtractor;
import org.springframework.dao.DataAccessException;
@Repository("contactDao")
puic class JdbcContactDao implements ContactDao {
private static final Log LOG = LogFactory.getLog(JdcContactDao.class);

private DataSource dataSource;


private SelectAllContacts selectAllContacts;
private SelectContactByFirstName selectContactByFirstName;
private UpdateContact updateContact;
private InsertContact insertContact;
private InsertContactTelDetail insertContactTelDetail;
private StoredFunctionFirstNameByid storedFunctionFirstNameByid;
@Override
puic List<Contact> findAll() {
return selectAllContacts.execute();

@Override
puic List<Contact> findByFirstName(String firstName) {
Map<String, Object> paramap = new HashMap<String, Object>();
paramap.put("first_name", firstName);
return selectContactByFirstName.executeByNamedParam(paramap);

@Override
puic String findFirstNameByid(Long id) {
List<String> result = storedFunctionFirstNameByid.execute(id);
return result.get(O);

@Override
puic void insert(Contact contact) {
Map<String, Object> paramap = new HashMap<String, Object>();
paramap.put("first_name", contact.getFirstName());
paramap.put("last_name", contact.getLastName());
paramap.put("irth_date", contact.getBirthDate());
KeyHolder keyHolder = new GeneratedKeyHolder();
insertContact.updateByNamedParam(paramap, keyHolder);
contact.setid(keyHolder.getKey() .longValue());
LOG.info("New contact inserted with id: " + contact.getid());
6. JDBC Spring 339
@Override
puic void insertWithDetail(Contact contact) {
insertContactTelDetail = new InsertContactTelDetail(dataSource);
Map<String, Object> paramap = new HashMap<String, Object>();
paramap.put("first_name", contact.getFirstName());
paramap.put("last_name", contact.getLastName());
paramap.put("irth_date", contact.getBirthDate());
KeyHolder keyHolder = new GeneratedKeyHolder();
insertContact.updateByNamedParam(paramap, keyHolder);
contact.setid(keyHolder.getKey().longValue());
LOG.info("New contact inserted with id: " + contact.getid());
List<ContactTelDetail> contactTelDetails
contact.getContactTelDetails();
if (contactTelDetails != null) {
for (ContactTelDetail contactTelDetail: contactTelDetails)
paramap = new HashMap<String, Object>();
paramap.put("contact_id", contact.get!d());
paramap.put("tel_type", contactTelDetail.getTelType());
paramap.put("tel_numer", contactTelDetail.getTelNumer());
insertContactTelDetail.updateByNamedParam(paramap);

insertContactTelDetail.flush();

@Override
puic List<Contact> findAllWithDetail() [
JdbcTemplate jdcTemplate = new JdcTemplate(getDataSource());
String sql = "select c.id, c.first_name, c.last_name, c.irth_date" +
t.id as contact_tel_id, t.tel_type, t.tel_numer from contact " +
"left join contact_tel_detail t on c.id = t.contact_id";
return jdcTemplate.query(sql, new ContactWithDetailExtractor());

@Override
puic void update(Contact contact) {
Map<String, Object> paramap = new HashMap<String, Object>();
paramap.put("first_name", contact.getFirstName());
paramap.put("last_name", contact.getLastName());
paramap.put("irth_date", contact.getBirthDate());
paramap.put("id", contact.getid());
updateContact.updateByNamedParam(paramap);

LOG.info("Existing contact updated with id: " + contact.get!d());

@Resource(name="dataSource")
puic void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.selectAllContacts = new SelectAllContacts(dataSource);
this.selectContactByFirstName = new SelectContactByFirstName(dataSource);
340 6. JDBC Spring
this.updateContact = new UpdateContact(dataSource);
this.insertContact = new InsertContact(dataSource);
this.storedFunctionFirstNameByid = new StoredFunctionFirstNameByid(dataSource);

puic DataSource getDataSource()


return dataSource;

private static final class ContactWithDetailExtractor


implements ResultSetExtractor<List<Contact>> {
@Override
pulic List<Contact> extractData(ResultSet rs) throws
SQLException, DataAccessException {
Map<Long, Contact> map = new HashMap<Long, Contact>();
Contact contact = null;
while (rs.next()) {
Long id = rs.getLong("id");
contact = map.get(id);

if (contact == null) {
contact = new Contact();
contact.setid(id);
contact.setFirstName(rs.getString("first name") );
contact.setLastName(rs.getString("last_name"));
contact.setBirthDate(rs.getDate("birth_date"));
contact.setContactTelDetails(new ArrayList<ContactTelDetail>());

map.put(id, contact);
}
Long contactTelDetailid = rs.getLong("contact_tel_id");
if (contactTelDetailid > ) {
ContactTelDetail contactTelDetail = new ContactTelDetail();
contactTelDetail.setid(contactTelDetailid);
contactTelDetail.setContactid(id);
contactTelDetail.setTelType(rs.getString("tel type"));
contactTelDetail.setTelNumber(rs.getString("tel_numer"));
contact.getContactTelDetails().add(contactTelDetail);

return new ArrayList<Contact> (map.values());

StoredFunctionFirst
NameByid. findFirstNameByid ()
execute (), .
Str ing, ,
.
6. JDBC Spring 341

-
Java 8 ContactWithDetailExtractor,
, -:
@Override
pulic List<Contact> findAllWithDetail() {
JdcTemplate jdbcTemplate = new JdbcTemplate(getDataSource());
String sql = "select c.id, c.first_name, c.last_name, c.birth_date" +
t.id as contact_tel_id, t.tel_type, t.tel_numer from contact " +
"left join contact_tel_detail t c.id = t.contact_id";
return jdbcTemplate.query(sql, (ResultSet rs) -> {
Map<Long, Contact> map = new HashMap<Long, Contact>();
Contact contact = null;
while (rs.next()) {
Long id = rs.getLong("id");
contact = map.get(id);
if (contact == null) {
contact = new Contact();
contact.setid(id);
contact.setFirstName(rs.getString("first_name"));
contact.setLastName(rs.getString("last_name"));
contact.setBirthDate(rs.getDate("irth_date"));
contact.setContactTelDetails(new ArrayList<ContactTelDetail>());
map.put(id, contact);

Long contactTelDetailid = rs.getLong("contact_tel_id");


if (contactTelDetailid > ) {
ContactTelDetail contactTelDetail = new ContactTelDetail();
contactTelDetail.setid(contactTelDetailid);
contactTelDetail.setContactid(id);
contactTelDetail.setTelType(rs.getString("tel_type"));
contactTelDetail.setTelNumer(rs.getString("tel_numer"));
contact.getContactTelDetails().add(contactTelDetail);

return new ArrayList<Contact> (map.values());


));

6.53 Spring
MySQL (app-context-annotation. xml).

6.53. Spring MySQL


<?xml version= "l. " encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
342 6. JDBC Spring
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<import resource= "classpath:ETA-INF/spring/datasource-dcp.xml"/>
<context:component-scan base-package= "com.apress.prospring4.ch6"/>
</beans>

datasource-dbcp.xml,
MySQL.
commons-dbcp, . 6.5.

6.5. commons-dcp


commons-dcp commons-dcp 1.4
commons-dcp Apache

6.54 .

6.54. MySQL
package com.apress.prospring4.ch6;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class AnnotationJdcDaoSample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:ETA-INF/spring/app-context-annotation.xml");
ctx.refresh() ;
ContactDao contactDao = ctx.getBean("contactDao", ContactDao.class);
System.out.println(contactDao.findFirstNameByid(ll));

, 1.
Chris , MySQL
test-data. sql. :
JdcTemplate: 663 - Executing prepared SQL query
JdcTemplate: 597 - Executing prepared SQL statement [select getfirstnamebyid(?)]
DataSourceUtils: 110 - Fetching JDBC Connection from DataSource
DataSourceUtils: 327 - Returning JDBC Connection to DataSource
Chris
, u .
Spring JDBC.
Spring (, StoredProcedure),
,
.
JDBC, Spring.
6. JDBC Spring 343

Spring Data: S1 JDBC



, ,

. ,
, Spring Data
(www.springsource.org/spring-data). -
_ Spring
, .
Spring Data .
- JDBC Extensions (www. spr ingsource. org /spr ing-da ta /
jdbc-extensions). ,

JDBC Spring.
JDBC Extensions.
QueryDSL. QueryDSL (www. querydsl. ) -
,
, . JDBC
Extensions Spring Data QueryDslJdcTemplate,
JDBC QueryDSL
SQL-onepaopo.
Oracle Database. JDBC Extensions
Oracle
Database.
, Oracle,
(Fast Connection Failover) Oracle RAC.
, ,
Oracle (Oracle Advanced Queueing).
L- Oracle, STRUCT
ARRAY ..
JDBC, Spring Oracle
Database, JDBC Extensions.

S1 S1 JDBC
, Spring
,
JDBC. -
,
.
JDBC ,
-
Java. , iBAIS
, SQL-.
iatis u-
344 6. JDBC Spring

L- . Spring, iS
,
SQL-,
DAO.
-
, , .
Hibernate, EclipseLink (
TopLink) OpenJPA. JPA
J.
-
,
, JDBC.
,
, ( ,
Orac\e), Spring JDBC -
. Spring
,
. , Hibernate
- , JDBC -
;
- .
Spring .

, Spring
JDBC.
, , ,
. Spring JDBC
JdbcTemplate. , Spring,
JdbcTemplate,
JDBC.
-, Java 8.
Spring
- .
7

Hibernate Spring
, JDBC Sring
. , Spring
II JDBC, - .
-
(object-relational mapping - ORM), Hiernate.

EJB ( EJB 3.0),
.
,
, ,
Jv-.
Spring POJO

EJ , , ,
POJO
. ,
R. R -

Java,

, .
ORM, , Hibemate
. ,
POJO,
,
Java.
Hibemate JCP,
Jv- (Java Data Object - JDO)
ORM Java . EJB 3.0,
EJB Java Persistence API (JPA),
ORM,
Hibernate, TopLink JDO.
346 7. Hibernate Spring

Hibernate J . ,
Hibernate, JBoss, JCP
JPA. 3.2, ibernate
JPA. ,
Hibernate
I- Hibemate JPA Hibemate.
Hibemate ,
Spring ibernate . Hibemate
ORM,
; Hibernate
.
ibernate Spring. , .
Hibernate. Hibernate
Session, SessionFactory.
, Hiernate Sring
.
-
Hibernate. ,
Hibernate POJO
.
, " " " ".
.
(, , , ) Hibemate
Spring. Hibernate
Session.

! - Hibernate
.
L-, Jv-
( ORM JPA Java,
, (entity
class)).
- .
JPA (, javax.persistence),
Hibernate,
JPA.


, , . 7.1.
, CONTACT
DETAIL ( ), " "
CONTACT . , CONTACT CONTACT_
TEL_DETAIL VERSION,
, .
7. Hibernate Spring 347

CONTACT CONTACT_TEL_DEAIL
jQ INT jQ INT
FIRST_NAME VARCHAR(O) f-tt-- CONTACT_ID=ID -- CONTACT_ID INT
LAST _NAME VARCHAR(40) L_ VARCHAR(20)
BIRTH_DATE DATE TEL_NUMBER VARCHAR(20)
VERSION INT VERSION INT

CONTACT_ID=ID

(
J
CONTACT_HOBBY_DEAIL
CONTACT ID INT
-
HOBY_ID=HOBY_ID --.ll-t- H-OBB_ __ ID_ _
- Y _ _ _ _ _ _ - --,
V. ARCHAR(20)
HOBY_ID VARCHAR(20)

. 7. 1. Hibernate
2,
.
7.1 7.2
.
7.1. ( schema. sql)
CREATE TABLE CONTACT (
ID INT NOT NULL INCREMENT
, FIRST_NAE VARCHAR(O) NOT NULL
, LAST_NAE VARCHAR(40) NOT NULL
, BIRTH_DATE DATE
, VERSION INT NOT NULL DEFAULT
, UNIQUE UQ_CONTACT_l (FIRST_NAE, LAST_NAE)
, PRIARY (ID)
);
CREATE L (
HOBBY_ID VARCAR(20) NOT NULL
, PRIARY (HOBBY_ID)
);
CREATE TABLE CONTACT TEL DETAIL
ID INT NOT NOLL INCREENT
, CONTACT_ID INT NOT NULL
, TEL_ VARCHAR(2 ) NOT NULL
, TEL_NUMBER VARCAR(2 ) NOT NULL
, VERSION INT NOT NULL DEFAULT O
, UNIQUE UQ_CONTACT_TEL_DETAIL_l (CONTACT_ID, TEL_TYPE)
, PRIARY (ID)
, CONSTRAINT FK_CONTACT_TEL_DETAIL_l FOREIGN (CONTACT_ID)
REFERENCES CONTACT (ID)
);
348 7. Hibernate Spring
CREATE TABLE CONTACT_HOBBY_DETAIL (
CONTACT ID INT NOT NULL
, HOBBY_ID VARCAR(20) NOT NULL
, PRIARY (CONTACT_ID, HOBBY_ID)
, CONSTRAINT FK CONTACT DETAIL 1 FOREIGN (CONTACT_ID)
REFERENCES CONTACT (ID) ON DELETE CASCADE
, CONSTRAINT FK CONTACT_HOBBY DETAIL 2 FOREIGN (HOBBY_ID)
RE FERENCES (_ID)
) ;

7.2. (test-data. sql)


insert into contact (first_name, last_name, birth_date)
values ('Chris', 'Schaefer', '1981-05-03');
insert into contact (first_name, last_name, birth_date)
values ('Scott', 'Tiger', '1990-11-02');
insert into contact (first_name, last_name, birth_date)
values ('John', 'Smith', '1964-02-28');
insert into contact_tel_detail (contact_id, tel_type, tel_numer)
values (1, 'Moile', '1234567890');
insert into contact tel_detail (contact_id, tel_type, tel_number)
values (1, 'Home', '1234567890');
insert into contact_tel_detail (contact_id, tel_type, tel_numer)
values (2, 'Home', '1234567890');
insert into hobby (hobby_id) values ( 'Swimming' );
insert into hobby (hobby_id) values ('Jogging');
insert into hobby (hobby_id) values ('Programming');
insert into hobby (hobby_id) values ('Movies');
insert into hobby (hobby_id) values ('Reading');
insert into contact hobby detail(contact id, hobby_id) values (1, 'Swimming');
insert into contact_hobby_detail(contact_id, hobby_id) values (1, 'Movies');
insert into contact_hobby_detail(contact_id, hobby_id) values (2, 'Swimming');

Hibernate
, Hibemate
Session, SessionFactory. Spring
Hibernate Spring
. Hibernate,
ibernate, . 7 .1.
7. 1. Hibernate



org.hibernate hibernate 4.2.3.Final Hibernate 4
entitymanager
7. Hibernate Spring 349
7.3 L-
(app-context-annotation.xml).

7.3. Spring Hibernate


<?xml version="l. " encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:jdc= "http://www.springframework.org/schema/jdc"
xmlns:util= "http://www.springframework.org/schema/util"
xsi:schemaLocation= "
http://www.springframework.org/schema/jdc
http://www.springframework.org/schema/jdc/spring-jdbc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<jdbc:emedded-database id="dataSource" type="H2">
<jdc:script location="classpath:META-INF/sql/schema.sql"/>
<jdc:script location= "classpath:META-INF/sql/test-data.sql"/>
</jdc:emedded-database>

<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory"/>
<tx:annotation-driven/>
<context:component-scan base-package="com.apress.prospring4.ch7"/>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
p:dataSource-ref="dataSource"
p:packagesToScan= "com.apress.prospring4.ch7"
p:hibernateProperties-ref= "hibernateProperties"/>
<util:properties id="hibernateProperties">
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
<prop key="hibernate.max fetch depth"></prop>
<prop key="hibernate.jdc.fetch_size">50</prop>
<prop key="hibernate.jdc.batch_size">lO</prop>
<prop key="hibernate.show_sql">true</prop>
</util:properties>
</beans>


Hibernate.
350 7. Hibernate Spring

r.
dataSource.
2.
transactionanager. Hibernate
r .
Spring , Hibernate 4
(org. springframework.orm. hibernate4. HibernateTransactionManager).
transactionManager.
, , Spring
ApplicationContext transactionManager.
9.
<tx: annotation-driven>
, .
<context: component-scan>.
. Spring
com. apress. prospring4. ch7.
sessionFactory. .
. -,
. -, Hibemate
com.apress.
prospring4. ch7. -, hibernateProperties
Hibemate. r
, ,
. . 7.2
r Hibemate.
7.2.

hibernate. dialect ,
Hibernate. Hibernate
SQL .
org. hibernate. dialect.
Dialect . H2Dialect,
OraclelOgDialect, PostgreSQLDialect,MySQLDialect,
SQLServerDialect ..
hibernate. max_fetch_depth "" ,

.
Hibernate
.
3
hibernate. jdc. fetch_size
JDBC, Hibernate

. ,
500 .
50,
Hibernate 1
7. Hiberate Spring 351
. 7.2

hibernate. jdc. batch_size Hibernate ,
.
Hibernate.
, ,
, ,
Hibernate ,

hibernate. show_sql , Hibernate SQL
anpoc .
,

, Hibernate,
Hibernate (http://d ocs.jboss.org/
hibernate/core/ 4. 3/manual/en-US/html/chO.html).

-
Hibernate
,
Jv- POJO
.
.
,
. , r
hibernate. hbm2ddl. auto, Hiemate
DDL- .
, , POJO
. ,
,
.
- , . 7.2.

Contact
ContactelDetail
- id: Long
- version : int - contactelDetail - id: Long
'
- firstName : String - version : int
'
/
/

- contact '
- lastName : String - telType : String
- irthDate : Date - telNumber : String
I\
'
- contacts
[

. ' - hobbles
1
1 - hobbyld : String 1

. 7 .2.
352 7. Hiberate Sprig
, " "
Contact ContactTelDetail, " "
Contact .


. 7.4
Contact .
7.4. Contact
package com.apress.prospring4.ch7;
import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializae;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.Tale;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
import javax.persistence.Version;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity
@Tale(name = "contact")
puic class Contact implements Serializae {
private Long id;
private int version;
private String firstName;
private String lastName;
private Date birthDate;
@Id
@GeneratedValue(strategy = IDENTITY)
@Column (name = "ID")
puic Long getid () {
return this.id;

puic void setid (Long id) {


this.id = id;

@Version
@Column (name = "VERSION")
puic int getVersion () {
return this.version;

puic void setVersion ( int version)


this.version = version;
7. Hibernate Spring 353
@Column(name = "FIRST_NAE")
puic String getFirstName()
return this.firstName;

puic void setFirstName(String firstNarne) {


this.firstName = firstName;

@Column(name = "LAST_NAE")
puic String getLastName()
return this.lastName;

puic void setLastName(String lastName)


this.lastName = lastName;

@Temporal(TemporalType.DATE)
@Column(name = "BIRTH_DATE")
puic Date getBirthDate() {
return this.birthDate;

puic void setBirthDate (Date birthDate)


this.birthDate = birthDate;

puic String toString() {


return "Contact - Id: " + id + ", First name: " + firstName
+ ", Last name: " + lastName + ", Birthday: " + birthDate;

@Entity, ,
. @
, .
@Column .
, @
@Column .
.
@ Temporal
Temporalype.DAE. , Java
(java. util. Date) SQL (java. sql. Date).
irthDate Contact, java. util. Date,
.
id @Id ,
. Hibemate

. , @GeneratedValue Hibemate,
id. IDENTITY
, .
354 7. Hibernate Spring
version @Version. Hibernate
, ,
version. ,
Hibernate ,
. , ,
, Hibernate
. , , -
, Hibernate StaleObj ectStateException,
Spring HibernateOptimisticLockingFailure
Exception.
. , Hibernate
. ,
, .. Hibernate
I .
, Hibernate
.
,

.
7.5 - ContactTelDetail.
7.5. ContactTelDetail
package com.apress.prospring4.ch7;
import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializae;
import javax.persistence.Entity;
import javax.persistence.Tale;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
import javax.persistence.Version;
@Entity
@Tale(name = "contact_tel_detail")
pulic class ContactTelDetail implements Serializae {
private Long id;
private int version;
private String telType;
private String telNumer;
puic ContactTelDetail()
}
puic ContactTelDetail(String telType, String telNumer) {
this.telType = telType;
this.telNumber = telNumber;
}
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "ID")
puic Long getid() {
return this.id;
7. Hibernate Spring 35S
puic void setid(Long id) {
this.id = id;

@Version
@Column(name = "VERSION")
puic int getVersion() {
return this.version;

puic void setVersion(int version)


this.version = version;

@Column(name = "TEL_TYPE")
puic String getTelType()
return this.te!Type;

puic void setTelType(String telType) {


this.telType = telType;

@Column(name = "TEL_NUBER")
puic String getTelNumer()
return this.telNumer;

puic void setTelNumer(String telNumer)


this.telNumer = telNumer;

7.6 .
7 .6.
package com.apress.prospring4.ch7;
import java.io.Serializale;
import javax.persistence.Entity;
import javax.persistence.Tale;
import javax.persistence.Column;
import javax.persistence.Id;
@Entity
@ (name = "hobby")
puic class implements Serializae {
private String hobbyid;
@Id
@Column(name = "HOBBY_ID")
puic String getHobbyid()
return this.hobbyid;

puic void setHobbyid(String hobbyid) {


this.hobbyid = hobbyid;

puic String toString() {


return " : " + getHobbyid();
356 7. Hibernate Spring

" "
Hibernate
. " "
" ".
, " " ( ORM
" " "
" " " ). 7.7
Contact ContactTelDetail.

7. 7. " "
package com.apress.prospring4.ch7;
import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializale;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.Tale;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
import javax.persistence.Version;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.CascadeType;
import javax.persistence.OneToMany;
@Entity
@Tale(name = "contact")
puic class Contact implements Serializale {
private Long id;
private int version;
private String firstName;
private String lastName;
private Date birthDate;
private Set<ContactTelDetail> contactTelDetails new
HashSet<ContactTelDetail>();
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "ID")
puic Long getld() {
return this.id;

puic void setld(Long id)


this.id = id;

@Version
@Column (name = "VERSION")
7. Hibernate Spring 357
pulic int getVersion()
return this.version;

pulic void setVersion(int version)


this.version = version;

@Column(name = "FIRST_NAE")
puic String getFirstName(}
return this.firstName;

puic void setFirstName(String firstName} {


this.firstName = firstName;

@Column(name = "LAST_NAE"}
pulic String getLastName(}
return this.lastName;

pulic void setLastName(String lastName} {


this.lastName = lastName;

@Temporal(TemporalType.DATE}
@Column(name = "BIRTH_DATE"}
pulic Date getBirthDate(} {
return this.birthDate;

pulic void setBirthDate(Date birthDate}


this.birthDate = birthDate;

@OneToMany(mappedBy = "contact", cascade=CascadeType.ALL,


orphanRemoval=true}
puic Set<ContactTelDetail> getContactTelDetails(}
return this.contactTelDetails;

pulic void setContactTelDetails(Set<ContactTelDetail> contactTelDetails}


{
this.contactTelDetails = contactTelDetails;
}
puic void addContactTelDetail(ContactTelDetail contactTelDetail}
contactTelDetail.setContact(this};
getContactTelDetails(}.add(contactTelDetail};

pulic void removeContactTelDetail(ContactTelDetail contactTelDetail}


getContactTelDetails(}.remove(contactTelDetail};

puic String toString(} {


return "Contact - Id: " + id + ", First name: " + firstName
+ ", Last name: " + lastName + ", Birthday: " + irthDate;
358 7. Hibernate Spring
contactTelDetails
@OneToMany, " "
ContactTelDetail. .
mappedBy ContactTelDetail,
(..
CONTACT_TEL_DETAIL). cascade ,
. orphanRemoval ,
, , ,
, .
7.8 ContactTelDetail
.
7.8. " " ContactTelDetail
package corn.apress.prospring4.ch7;
irnport static javax.persistence.GenerationType.IDENTITY;
irnport java.io.Serializale;
irnport javax.persistence.Entity;
irnport javax.persistence.Tae;
irnport javax.persistence.Id;
irnport javax.persistence.GeneratedValue;
irnport javax.persistence.Colurnn;
irnport javax.persistence.Version;
irnport javax.persistence.ManyToOne;
irnport javax.persistence.JoinColurnn;
@Entity
@Tale(narne = "contact_tel_detail")
pulic class ContactTelDetail irnplernents Serializae {
private Long id;
private int version;
private String telType;
private String telNurner;
private Contact contact;
pulic ContactTelDetail()
}
puic ContactTelDetail(String telType, String telNurner) {
this.telType = telType;
this.telNurner = telNurner;

@Id
@GeneratedValue(strategy = IDENTITY)
@Colurnn(narne = "ID")
pulic Long getid() {
return this.id;

puic void setid(Long id) {


this.id = id;
7. Hibernate Spring 359

@Version
@Colnn(name = "VERSION")
puic int getVersion()
return this.version;

puic void setVersion(int version)


this.version = version;

@Colnn(name = "TEL_TYPE")
puic String getTelType ()
return this.telType;

puic void setTelType(String telType)


this.telType = telType;

@Column(name = "TEL_NOMBER")
puic String getTelNumer()
return this.telNumer;

puic void setTelNumer(String telNumer) {


this.telNumer = telNumer;

@ManyToOne
@JoinColumn(name = "CONTACT ID")
puic Contact getContact()
return this.contact;

puic void setContact(Contact contact) {


this.contact = contact;

puic String toString() {


return "Contact Tel Detail - Id: " + id + ", Contact id: "
+ getContact () . getid() + ", : "
+ telType + ", Number: " + telNumer;

contact @ManyToOne,
Contact.
@JoinColumn . ,
toString () .

" "
,
, .. "
". ,
CONTACT _HOBBY_DETAIL, . 7.2. 7.9
Contact, .
360 7. Hibernate Spring

7.9. " "


package com.apress.prospring4.ch7;
import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializale;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.Tale;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
import javax.persistence.Version;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.OneToMany;
import javax.persistence.ManyToMany;
import javax.persistence.JoinTae;
import javax.persistence.JoinColumn;
import javax.persistence.CascadeType;
@Entity
@Tale(name = "contact")
puic class Contact implements Serializale {
private Long id;
private int version;
private String firstName;
private String lastName;
private Date birthDate;
private Set<ContactTelDetail> contactTelDetails = new
HashSet<ContactTelDetail>();
private Set<Hobby> hobbies = new HashSet<Hobby>();
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "ID")
puic Long getid() {
return this. id;

puic void setid(Long id) {


this.id = id;

@Version
@Column (name = "VERSION")
puic int getVersion() {
return this.version;

pulic void setVersion(int version)


this.version = version;

@Column(name = "FIRST_NAE")
7. Hibernate Spring 361
puic String getFirstNarne()
return this.firstNarne;

puic void setFirstName(String firstNarne) {


this.firstNarne = firstNarne;

@Colurnn(name = "LAST_NAE")
puic String getLastName()
return this.lastName;

pulic void setLastName(String lastName) {


this.lastName = lastName;

@Temporal(Tempora!Type.DATE)
@Colurnn(name = "BIRTH_DATE")
pulic Date getBirthDate() {
return this.birthDate;

puic void setBirthDate(Date birthDate}


this.birthDate = birthDate;

@OneToMany(mappedBy = "contact", cascade=CascadeType.ALL,


orphanRemoval=true}
puic Set<ContactTelDetail> getContactTelDetails(}
return this.contactTelDetails;

pulic void setContactTelDetails(Set<ContactTelDetail> contactTelDetails}


this.contactTelDetails = contactTelDetails;
}
pulic void addContactTelDetail(ContactTelDetail contactTelDetail}
contactTelDetail.setContact(this};
getContactTelDetails(}.add(contactTelDetail};

puic void removeContactTelDetail(ContactTelDetail contactTelDetail}


getContactTelDetails() .rernove(contactTelDetail};

@ManyToMany
@JoinTale(name = "contact hobby detail",
joinColurnns = @JoinColurnn(narne = "CONTACT_ID"},
inverseJoinColurnns = @JoinColurnn(narne = "HOBBY_ID"}}
puic Set<Hobby> getHobbies(} {
return this.hobbies;

pulic void setHobbies(Set<Hobby> hobbies}


this.hobbies = hobbies;

puic String toString(} {


return "Contact - Id: " + id + ", First name: " + firstNarne
+ ", Last name: " + lastNarne + ", Birthday: " + irthDate;
362 7. Hibernate Spring

hobies Contact
@ManyToMany. @JoinTae
, Hibemate.
r name , j oinColumns
, CONTACT, inverseJoinColumns
,
(. . ). 7.10
.
7 .1 . " "
package com.apress.prospring4.ch7;
import java.io.Serializale;
import javax.persistence.Entity;
import javax.persistence.Tale;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.JoinTale;
import javax.persistence.JoinColumn;
import java.util.Set;
import java.util.HashSet;
@Entity
@ (name = "hobby")
pulic class implements Serializae {
private String hobbyid;
private Set<Contact> contacts = new HashSet<Contact>();
@Id
@Column(name = "HOBBY_ID")
pulic String getHobbyid()
return this.hobbyid;

puic void setHobbyid(String hobbyid)


this.hobbyid = hobbyid;

@ManyToMany
@JoinTae(name = "contact_hobby_detail",
joinColumns = @JoinColumn(name = "HOBBY_ID"),
inverseJoinColumns = @JoinColumn(name = "CONTACT ID"))
pulic Set<Contact> getContacts() {
return this.contacts;

pulic void setContacts(Set<Contact> contacts)


this.contacts = contacts;

@Override
puic String toString() {
return " : " + getHobbyid();
7. Hibernate Spring 363
7.9,
joinColumns inverseJoinColumns , .

Session Hibernate
Hibemate
Session, .
7.11 ContactDaoimpl,

SessionFactory.
7.11. SessionFactory
package com.apress.prospring4.ch7;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Repository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;
import javax.annotation.Resource;
@Transactional
@Repository("contactDao")
pulic class ContactDaoimpl implements ContactDao {
private static final Log LOG = LogFactory.getLog(ContactDaoimpl.class);
private SessionFactory sessionFactory;
pulic SessionFactory getSessionFactory()
return sessionFactory;

@Resource(name="sessionFactory")
puic void setSessionFactory(SessionFactory sessionFactory)
this.sessionFactory = sessionFactory;

, DAO Spring
@Repository. @Transactional ,
9. sessionFactory
@Resource.


Hibernate
7.12 ContactDao,
, .
364 7. Hibernate Spring
7.12. ContactDao
package com.apress.prospring4.ch7;
import java.util.List;
puic interface ContactDao
List<Contact> finc!All();
List<Contact> finc!AllWithDetail();
Contact findByid(Long id);
Contact save(Contact contact);
void delete(Contact contact);

; ,
. save ()
.

Hibernate
ibernate, ORM J DO J ,
. ,
SQL-
. Hibernate
Hibernate (Hibernate Query Language - HQL).
Hibernate QL- SQL-.
HQL SQL. ,
, .
.

findAll (),
. 7.13
.
7 .13. findAll ()
package com.apress.prospring4.ch7;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Repository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;
import javax.annotation.Resource;
import java.util.List;
@Transactional
@Repository("contactDao")
puic class ContactDaoimpl implements ContactDao {
private static final Log LOG = LogFactory.getLog(ContactDaoimpl.class);
private SessionFactory sessionFactory;
@Override
7. Hibernate Spring 365
@Transactional(readOnly=true)
puic List<Contact> findAll()
return sessionFactory.getCurrentSession()
.createQuery("from Contact ") .list();

@Override
puic List<Contact> findAllWithDetail() {
return null;

@Override
puic Contact findByid(Long id) {
return null;

@Override
pulic Contact save(Contact contact) {
return null;

@Override
pulic void delete(Contact contact) {

pulic SessionFactory getSessionFactory()


return sessionFactory;

@Resource(name="sessionFactory")
puic void setSessionFactory(SessionFactory sessionFactory)
this.sessionFactory = sessionFactory;

SessionFactory. getCurrentSession ()
Session ibernate. Session.createQuery(),
HQL. from Contact
.
select from Contact . @Transactional (readOnly=true)
,
. , ,
.
7.14 ContactDaoimpl.
7.14. ContactDaoimpl
package com.apress.prospring4.ch7;
import java.util.List;
import org.springframework.context.support.GenericXrnlApplicationContext;
pulic class SpringHibernateSample {
puic static void main(String [] args) {
GenericXrnlApplicationContext ctx = new GenericXrnlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
366 7. Hiberate Sprig
ContactDao contactDao = ctx.getBean( "contactDao", ContactDao.class);
listContacts(contactDao.finc!All());

private static void listContacts(List<Contact> contacts) {


System.out.println("");
System.out.println("Listing contacts without details:");
for (Contact contact: contacts) {
System.out.println(contact);
System.out.println();

:
Listing contacts without details:
Contact - Id: 1, First : Chris, Last : Schaefer, Birthday: 1981-05-03
Contact - Id: 2, First : Scott, Last : Tiger, Birthday: 1990-11-02
Contact - Id: 3, First name: John, Last : Smith, Birthday: 1964-02-28
, , -
?
. 7.15 .

7.15. ContactDaoimpl,

package com.apress.prospring4.ch7;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class SpringHibernateSample {
puic static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
ContactDao contactDao = ctx.getBean ("contactDao", ContactDao.class);
listContactsWithDetail(contactDao.finc!All());

private static void listContactsWithDetail(List<Contact> contacts) {


System.out.println("");
System.out.println ("Listing contacts with details:");
for (Contact contact: contacts) {
System.out.println(contact);
if (contact.getContactTelDetails() 1= null) {
for (ContactTelDetail contactTelDetail:
contact.getContactTelDetails()) {
System.out.println(contactTelDetail);
7. Hibernate Spring 367
if (contact.getHobbies() != null) {
for ( hobby: contact.getHobbies())
System.out.println(hobby);

System.out.println();

:
Listing contacts with details:
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday: 1981-05-03
Exception in thread "main" org.hibernate.LazyinitializationException:
"main" org.hibernate.LazyinitializationException:

Hibernate
LazyinitializationException. , Hibernate
("") , ,
(.. CONTACT _ TEL_DETAIL)
.
, , ,
,
.


ll Hibernate ,
.
EAGER, : @ManyToMany ( fetch=FetchType. EAGER).
Hibernate
. , ,
.

. Criteria,
Criteria. setFetchMode () Hibernate
. NarnedQuery
Hibernate
fetch.
findAllWithDetail (),
.
(NarnedQuery).
L-
. 7.16
Contact , .
368 7. Hibernate Spring

7 .16. NamedQuery
package com.apress.prospring4.ch7;
import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializale;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.Tale;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
import javax.persistence.Version;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.OneToMany;
import javax.persistence.ManyToMany;
import javax.persistence.JoinTale;
import javax.persistence.JoinColumn;
import javax.persistence.CascadeType;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
@Entity
@(name = "contact")
@NamedQueries({
@NamedQuery(name="Contact.findAllWithDetail",
query="select distinct from Contact left join fetch c.contactTelDetails t
left join fetch c.hobbies h")
})
puic class Contact implements Serializae {
private Long id;
private int version;
private String firstName;
private String lastName;
private Date birthDate;
private Set<ContactTelDetail> contactTelDetails =
new HashSet<ContactTelDetail>();
private Set<Hobby> hobbies = new HashSet<Hobby>();
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "ID")
puic Long getid() {
return this.id;

pulic void setid(Long id) {


this.id = id;

@Version
@Column(name "VERSION")
7. Hibernate Spring 369
pulic int getVersion()
return this.version;

puic void setVersion(int version)


this.version = version;

@Column(name = "FIRST_NAE")
puic String getFirstName()
return this.firstName;

pulic void setFirstName(String firstName) {


this.firstName = firstName;

@Column(name = "LAST_NAE")
puic String getLastName()
return this.lastName;

puic void setLastName(String lastName)


this.lastName = lastName;

@Temporal(TemporalType.DATE)
@Column(name = "BIRTH_DATE")
puic Date getBirthDate() {
return this.rthDate;

puic void setBirthDate(Date rthDate)


this.rthDate = rthDate;

@OneToMany(mappedBy = "contact", cascade=CascadeType.ALL,


orphanRemoval=true)
puic Set<ContactTelDetail> getContactTelDetails()
return this.contactTelDetails;

puic void setContactTelDetails(Set<ContactTelDetail> contactTelDetails)


{
this.contactTelDetails = contactTelDetails;

puic void addContactTelDetail(ContactTelDetail contactTelDetail)


contactTelDetail.setContact(this);
getContactTelDetails().add(contactTelDetail);

puic void removeContactTelDetail(ContactTelDetail contactTelDetail)


getContactTelDetails().remove(contactTelDetail);

@ManyToMany
@JoinTae(name = "contact_hobby_detail",
joinColurnns = @JoinColurnn(name = "CONTACT_ID"),
inverseJoinColurnns = @JoinColumn(name = "HOBBY_ID"))
370 7. Hibernate Spring
puic Set<Hobby> getHobbies()
return this.hobbies;

puic void setHobbies(Set<Hobby> hobbies) {


this.hobbies = hobbies;

@Override
puic String toString() {
return "Contact - Id: " + id + ", First name: " + firstName
+ ", Last name: " + lastName + ", Birthday: " + birthDate;

Contact. findAllWi th
Detail. HQL.
left j oin fetch, Hibernate
.
select distinct, Hibernate
(, - ,
Contact).
7.17 findAllWithDetail ().
7.17. find.AllWithDetail ()
package com.apress.prospring4.ch7;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Repository;
import org.apache.counons.logging.Log;
import org.apache.counons.logging.LogFactory;
import org.hibernate.SessionFactory;
import javax.annotation.Resource;
import java.util.List;
@Transactional
@Repository("contactDao")
puic class ContactDaoimpl implements ContactDao {
private static final Log LOG = LogFactory.getLog(ContactDaoimpl.class);
private SessionFactory sessionFactory;
@Override
@Transactional(readOnly=true)
puic List<Contact> findAll()
return sessionFactory.getCurrentSession()
.createQuery("from Contact ").list();

@Override
@Transactional(readOnly=true)
puic List<Contact> findAllWithDetail()
return sessionFactory.getCurrentSession().
getNamedQuery("Contact.findAllWithDetail").list();
7. Hibernate Spring 371
@Override
puic Contact findByid(Long id) {
return null;

@Override
puic Contact save(Contact contact) {
return null;

@Override
puic void delete(Contact contact) {

puic SessionFactory getSessionFactory()


return sessionFactory;

@Resource(name="sessionFactory")
puic void setSessionFactory(SessionFactory sessionFactory)
this.sessionFactory = sessionFactory;

Session. getNamedQuery (),


NamedQuery. (SpringHibernateSample)
ContactDao. find.AllWithDetail ()
:
Listing contacts with details:
Contact - Id: 1, First name: Chris, Last : Schaefer, Birthday: 1981-05-03
Contact Tel Detail - Id: 1, Contact id: 1, : Mobile, Numer: 1234567890
Contact Tel Detail - Id: 2, Contact id: 1, : Home, Numer: 1234567890
:Movies
:Swimrning
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
Contact Tel Detail - Id: 3, Contact id: 2, : Home, Numer: 1234567890
:Swimrning
.
, .
findByid (),
. 7.18 Contact
.

7. 18.
package com.apress.prospring4.ch7;
import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializae;
import java.util.Date;
import java.util.HashSet;
372 7. Hibernate Spring
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.Tale;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
import javax.persistence.Version;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.OneToMany;
import javax.persistence.ManyToMany;
import javax.persistence.JoinTale;
import javax.persistence.JoinColumn;
import javax.persistence.CascadeType;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
@Entity
@Tale(name = "contact")
@NamedQueries({
@NamedQuery(name="Contact.findByid",
query="select distinct from Contact left join fetch c.contactTelDetails
t left join fetch c.hobbies h where c.id = :id"),
@NamedQuery(name="Contact.findAllWithDetail",
query="select distinct from Contact left join fetch c.contactTelDetails
t left join fetch c.hobbies h")
})
puic class Contact implements Serializae {
private Long id;
private int version;
private String firstName;
private String lastName;
private Date birthDate;
private Set<ContactTelDetail> contactTelDetails =
new HashSet<ContactTelDetail>();
private Set<Hobby> hobbies = new HashSet<Hobby>();
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "ID")
puic Long getid() {
return this.id;

puic void setid(Long id) {


this.id = id;

@Version
@Column(name = "VERSION")
puic int getVersion() {
return this.version;

pulic void setVersion(int version) {


this.version = version;
7. Hiberate Sprig 373
@Column(name = "FIRST_NAE")
puic String getFirstName()
return this.firstName;

puic void setFirstName(String firstName) {


this.firstName = firstName;

@Column(name = "LAST_NAE")
puic String getLastName()
return this.lastName;

puic void setLastName(String lastName) {


this.lastName = lastName;

@Temporal(TemporalType.DATE)
@Column(name = "BIRTH_DATE")
pulic Date getBirthDate() {
return this.birthDate;

pulic void setBirthDate(Date birthDate)


this.birthDate = birthDate;

@OneToMany(mappedBy = "contact", cascade=CascadeType.ALL,


orphanRemoval=true)
puic Set<ContactTelDetail> getContactTelDetails()
return this.contactTelDetails;

puic void setContactTelDetails(Set<ContactTelDetail> contactTelDetails)


{
this.contactTelDetails = contactTelDetails;

puic void addContactTelDetail(ContactTelDetail contactTelDetail)


contactTelDetail.setContact(this);
getContactTelDetails().add(contactTelDetail);

puic void removeContactTelDetail(ContactTelDetail contactTelDetail)


getContactTelDetails().remove(contactTelDetail);

@ManyToMany
@JoinTale(name = "contact hobby detail",
joinColumns = @JoinColumn(name = "CONTACT_ID"),
inverseJoinColumns = @JoinColumn(name = "HOBBY_ID"))
pulic Set<Hobby> getHobies() {
return this.hobies;

puic void setHobies(Set<Hobby> hobies) {


this.hobies = hobies;

@Override
puic String toString() {
return "Contact - Id: " + id + ", First name: " + firstName
+ ", Last name: " + lastName + ", Birthday: " + irthDate;
374 7. Hibernate Spring

Contact. findByid
: id. 7.19 findByid ()
ContactDaoimpl.
7.19. findyid()
package com.apress.prospring4.ch7;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Repository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;
import javax.annotation.Resource;
import java.util.List;
@Transactional
@Repository("contactDao")
pulic class ContactDaoimpl implements ContactDao {
private static final Log LOG = LogFactory.getLog(ContactDaoimpl.class);
private SessionFactory sessionFactory;
@Override
@Transactional(readOnly=true)
pulic List<Contact> find.All()
return sessionFactory.getCurrentSession()
.createQuery("from Contact ").list();

@Override
@Transactional(readOnly=true)
pulic List<Contact> find.AllWithDetail()
return sessionFactory.getCurrentSession().
getNamedQuery("Contact.find.AllWithDetail").list();

@Override
@Transactional(readOnly=true)
pulic Contact findByid(Long id)
return (Contact) sessionFactory.getCurrentSession().
getNamedQuery("Contact.findByid").
setParameter("id", id).uniqueResult();

@Override
pulic Contact save(Contact contact) {
return null;

@Override
puic void delete(Contact contact)

puic SessionFactory getSessionFactory()


return sessionFactory;

@Resource(name="sessionFactory")
pulic void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
7. Hibernate Spring 375
Session. getNameQuery().
, setParameter(),
.
setParameterList() setPararneters() Query.
,
,
JPA.
fi ndByid( ),
SpringHibernateSample, 7.20.
7.20. findyid ()
package com.apress.prospring4.ch7;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class SpringHibernateSample {
pulic static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
ContactDao contactDao = ctx.getBean("contactDao", ContactDao.class);
Contact contact = contactDao.findByid(ll);
System.out.println("");
System.out.println("Contact with id 1:" + contact);
System.out.println("");

:
Contact with id l:Contact - Id: 1, First name: Chris,
Last name: Schaefer, Birthday: 1981-05-03


Hibernate .
,
. , JDBC ,
, KeyHolder
. Hibernate
. Hibernate
. save()
7.21.
7.21. save ()

package com.apress.prospring4.ch7;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Repository;
import org.apache.commons.logging.Log;
376 7. Hibernate Spring
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;
import javax.annotation.Resource;
import java.util.List;
@Transactional
@Repository("contactDao")
puic class ContactDaoimpl implements ContactDao {
private static final Log LOG = LogFactory.getLog(ContactDaoimpl.class);
private SessionFactory sessionFactory;
@Override
@Transactional(readOnly=true)
puic List<Contact> findAll()
return sessionFactory.getCurrentSession()
.createQuery("from Contact ").list();

@Override
@Transactional(readOnly=true)
puic List<Contact> findAllWithDetail()
return sessionFactory.getCurrentSession().
getNamedQuery("Contact.findAllWithDetail").list();

@Override
@Transactional(readOnly=true)
pulic Contact findByid(Long id)
return (Contact) sessionFactory.getCurrentSession().
getNamedQuery("Contact.findByid").
setParameter("id", id).uniqueResult();

@Override
puic Contact save(Contact contact) {
sessionFactory.getCurrentSession() .saveOrUpdate(contact);
LOG.info("Contact saved with id: " + contact.getid());
return contact;

@Override
puic void delete(Contact contact)

puic SessionFactory getSessionFactory()


return sessionFactory;

@Resource(name="sessionFactory")
puic void setSessionFactory(SessionFactory sessionFactory)
this.sessionFactory = sessionFactory;

Session. saveOrUpdate (),


.
,
7. Hibernate Spring 377

Hibemate . 7.22
SpringHibernateSample.

7.22.
package com.apress.prospring4.ch7;
import java.util.List;
import java.util.Date;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class SpringHibernateSample {
puic static void main (String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:ETA-INF/spring/app-context-annotation.xml");
ctx.refresh();
ContactDao contactDao = ctx.getBean("contactDao", ContactDao.class);
Contact contact = new Contact();
contact.setFirstName("Michael");
contact.setLastName("Jackson");
contact.setBirthDate(new Date());
ContactTelDetail contactTelDetail =
new ContactTelDetail("Home", "1111111111");
contact.addContactTelDetail(contactTelDetail);
contactTelDetail = new ContactTelDetail("Mobile", "2222222222");
contact.addContactTelDetail(contactTelDetail);
contactDao.save(contact);
listContactsWithDetail(contactDao.findAllWithDetail());

private static void listContactsWithDetail(List<Contact> contacts)


System.out.println("");
System.out.println("Listing contacts with details:");
for (Contact contact: contacts) {
System.out.println(contact);
if (contact.getContactTelDetails() != null) {
for (ContactTelDetail contactTelDetail:
contact.getContactTelDetails()) {
System.out.println(contactTelDetail);

if (contact.getHobbies() != null) {
for ( hobby: contact.getHobbies())
System.out.println(hobby);

System.out.println();
378 7. Hiberate Sprig
7.22 ,
. .
:
Hibernate: insert into contact_tel_detail (ID, CONTACT_ID, TEL_NUMBER,
TEL_TYPE, VERSION) values (null, ?, ?, ?, ?)
18:04:00,240 INFO com.apress.prospring4.ch7.ContactDaoimpl:
38 - Contact saved with id: 4
Listing contacts with details:
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday: 1981-05-03
Contact Tel Detail - Id: 1, Contact id: 1, : Mobile, Numer: 1234567890
Contact Tel Detail - Id: 2, Contact id: 1, : Home, Number: 1234567890
:Movies
:Swimming
Contact - Id: 4, First name: Michael, Last name: Jackson, Birthday: 2013-07-25
Contact Tel Detail - Id: 4, Contact id: 4, : Mobile, Numer: 2222222222
Contact Tel Detail - Id: 5, Contact id: 4, : Home, Numer: 1111111111
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
Contact Tel Detail - Id: 3, Contact id: 2, : Home, Number: 1234567890
:Swimming
INFO ,
. Hibernate SQL-,
, ,
" ".


, .
, I
.
, SpringHibernateSample ,
7.23.
7.23.
package com.apress.prospring4.ch7;
import java.util.List;
import java.util.Date;
import java.util.Set;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class SpringHibernateSample {
puic static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx. refresh () ;
ContactDao contactDao = ctx.getBean("contactDao", ContactDao.class);
Contact contact = contactDao.findByid(ll);
contact.setFirstName("Kim Fung");
7. Hiberate Spring 379
Set<ContactTelDetail> contactTels = contact.getContactTelDetails();
ContactTelDetail toDeleteContactTel = null;
for (ContactTelDetail contactTel: contactTels) {
if (contactTel.getTelType().equals("Home")) {
toDeleteContactTel = contactTel;

contact.removeContactTelDetail(toDeleteContactTel);
contactDao.save(contact);

listContactsWithDetail(contactDao.findAllWithDetail());

private static void listContactsWithDetail(List<Contact> contacts)


System.out.println("");
System.out.println("Listing contacts with details:");
for (Contact contact: contacts) {
System.out.println(contact);
if (contact.getContactTelDetails() != null) {
for (ContactTelDetail contactTelDetail:
contact.getContactTelDetails()) {
System.out.println(contactTelDetail);

if (contact.getHobies() != null) {
for ( hobby: contact.getHobies())
System.out.println(hobby);

System.out.println();

, '-l
1, .
, "Horne"
. , ContactDao. save ().
:
Listing contacts with details:
Contact - Id: 1, First name: Kirn Fung, Last name: Schaefer, Birthday: 1981-05-03
Contact Tel Detail - Id: 1, Contact id: 1, : Moile, Nurner: 1234567890
:Movies
:Swimming
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
Contact - Id: 2, First name: Scott, Last narne: Tiger, Birthday: 1990-11 -02
Contact Tel Detail - Id: 3, Contact id: 2, : Home, Nurner: 1234567890
:Swimming
380 7. Hibernate Spring

, ,
. ,
" " orphanRernoval=true, Hibemate
, (.. )
.


.
Session. delete () . 7.24
.

7 .24. delete ()
package com.apress.prospring4.ch7;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Repository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;
import javax.annotation.Resource;
import java.util.List;
@Transactional
@Repository("contactDao")
puic class ContactDaoimpl implements ContactDao {
private static final Log LOG = LogFactory.getLog(ContactDaoimpl.class);
private SessionFactory sessionFactory;
@Override
@Transactional(readOnly=true)
puic List<Contact> finc!All()
return sessionFactory.getCurrentSession()
.createQuery("from Contact ") .list();

@Override
@Transactional(readOnly=true)
puic List<Contact> finc!AllWithDetail()
return sessionFactory.getCurrentSession().
getNamedQuery("Contact.finc!AllWithDetail").list();

@Override
@Transactional(readOnly=true)
puic Contact findByld(Long id)
return (Contact) sessionFactory.getCurrentSession().
getNamedQuery("Contact.findByid").
setParameter("id", id).uniqueResult();

@Override
pulic Contact save(Contact contact) {
sessionFactory.getCurrentSession().saveOrUpdate(contact);
LOG.info("Contact saved with id: " + contact.getld());
return contact;
7. Hibernate Spring 381
@Override
pulic void delete(Contact contact)
sessionFactory.getCurrentSession().delete(contact);
LOG.info("Contact deleted with id: " + contact.getid());

puic SessionFactory getSessionFactory()


return sessionFactory;

@Resource(name="sessionFactory")
puic void setSessionFactory(SessionFactory sessionFactory)
this.sessionFactory = sessionFactory;

,
, , ..
cascade = CascadeType. ALL. 7.25
SpringHibernateSample.

7.25.
package com.apress.prospring4.ch7;
import java.util.List;
import java.util.Date;
import java.util.Set;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class SpringHibernateSample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
ContactDao contactDao = ctx.getBean("contactDao", ContactDao.class);
Contact contact = contactDao.findByid(ll);
contactDao.delete(contact);
listContactsWithDetail(contactDao.findAllWithDetail());

private static void listContactsWithDetail(List<Contact> contacts)


System.out.println("");
System.out.println("Listing contacts with details: ");
for (Contact contact: contacts) {
System.out.println(contact);
if (contact.getContactTelDetails() != null) {
for (ContactTelDetail contactTelDetail:
contact.getContactTelDetails()) {
System.out.println(contactTelDetail);
382 7. Hibernate Spring
if (contact.getHobies() != null)
for ( hobby: contact.getHobes())
System.out.println(hobby);

System.out.println();

I
delete () .
:
Listing contacts with details:
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
Contact Tel Detail - Id: 3, Contact id: 2, : Home, Number: 1234567890
:Swimming
, I .

Hibernate
,
- ,
Hibemate ,
, SQL
. Hibemate
Jv-
.
, .
SQL-,
,
. SQL-,
Hibemate, .
, Hibernate
, , .
Hibemate
.
, Hibemate , -
.
, ,
.
, Hibemate
( , ..).

.
7. Hibernate Spring 383
, Hibernate JPA,
,
Jv-, -
.

Hibernate ,
Spring.
ORM,
HibernateTemplate
.

Hibernate.
Hibernate, Hibemate
Spring. , , , ,
Beginning Hibernate, 3- . (Apress, 2014 r.) Pro JPA 2 (Apress, 2013 r.).
JPA Spring.
Hibernate JPA,
Hibernate
. JPA
Hibernate. ,
, Hibernate
JPA.
8

Spring

JPA2
, Hiberate Spring
ORM.
Hibemate
Spring , Session
.
Hiernate. ibernate Spring
Hibemate ,
l- Java (Java Persistence API - JPA).
POJO Hibernate HQL
,
Java. Hibemate JCP
JDO (Java Data Objects - Java) JPA.
J 2.1
, PersistenceContext,
EntityManager JPQL (Java Persistence Query Language -
Java).
JPA, Hibemate, EclipseLink,
l TopLink Apache OpenJPA. J-
JPA .
Spring JPA. ,
EntityManagerFactoryBean
JPA JPA.
Spring Data Spring Data JPA,
JPA Sing-.
Spring Data JPA
Repository Specification, ,
(Query Domain Specific Language - QueryDSL).
386 8. Spring JPA 2
JPA 2.1 Spring, Hibemate
. ,

Enti tyManager JPA JPQL. , Spring Data
JPA JPA. ,
, ORM,
.
, .
JPA. JPA.
r JPA. EntityManager
Factory, Spring,
- LocalContainerEnti tyManagerFactoryBean -
L- Spring.
. ,
JPA, ,
Hibemate.
.
JPA l-
.
Spring Data JPA. Spring Data JPA ,

.
.

, , . ,
,
, . , Spring Data JPA
Hibemate Envers (Hibemate Entity rsioning System -
Hibemate) .

! Hibernate, JPA XML,


Jv-.
, , XML.

JPA 2.1
Java (Java Specit1cation Request - JSR),
JPA 2.1 (JSR-338)
ORM JSE JEE. ,
, , JPA
. JPA

, J-
, JEE.
8. Spring JPA 2 387
JPA EntityManager,
Enti tyManagerFactory. Enti tyManager
,
, . EntityManager
,
. Hibemate,
, Sessio n , EntityManagerFactory -
, SessionFactory. Hibernate
, imt-
SessionFactory Session. JPA
.
Enti tyManager.
JPQL HQL, HQL,
JPQL . , JPA 2
l- ,
. , r
, .
JPA 2
Pro JPA 2 (Apress, 2013 .).
JPA,
, ,
ApplicationContext JPA.

,
7.
. ,
, .
- 7, ,
" ";
.
Enti tyanaqerFactory JPA
, JPA Spring
Enti tyManagerFactory, SessionFactory
Hibernate.
Spring E nti tyManagerFactory.
LocalEntityManagerFactoryBean.
,
. ,
, ,
.
JEE 6 ,

JPA . Spring
JNDI. 8.1
JND 1.
388 8. Spring JPA 2
8.1. JNDI
<beans>
<jee:jndi-lookup id="prospring4Emf"
jndi-name="persistence/prospring4PersistenceUnit"/>
</beans>

JPA
META-INF/persisten ce. xml. , Spring 3.1
, ;
, .
,
- LocalCon tain erEn ti tyMan agerFactoryBean.

, . 8.2
L- (app-con text-an n otation . xml).
8.2. Spring LocalContainerEntityanagerFactoryean
<?xml version= "l.0" encoding="UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi=http://www.w.org/2001/XLSchema-instance
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc=http://www.springframework.org/schema/jdc
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<jdc:emedded-database id="dataSource" type= "H2">
<jdbc:script location= "classpath:META-INF/sql/schema.sql"/>
<jdbc:script location="classpath:META-INF/sql/test-data.sql"/>
</jdc:emedded-database>
<bean id ="transactionanager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name= "entityManagerFactory" ref="emf"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name= "dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
/>
</property>
<property name= "packagesToScan" value="com.apress.prospring4.ch8"/>
8. Spring JPA 2 389
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.H2Dialect</prop>
<prop key="hibernate.max_fetch_depth"></prop>
<prop key="hibernate.jdc.fetch_size">SO</prop>
<prop key="hibernate.jdbc.batch_size">lO</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<context:component-scan base-package="com.apress.prospring4.ch8" />
</beans>


r LocalContainerEntityManagerFactoryBean Hiemate
. r.
dataSource.
2. ,
.
transactionanager.
. Spring
JPA (org. springframework.
orm. jpa. JpaTransactionManager).
transactionManager. 9.
<tx: annotation-driven>
.
com.ponent-scan. .
Spring
com.apress.prospring4.ch8.
JPA. emf
. ,
LocalContainerEntityManagerFactoryBean.
. -,
, . -,
jpaVendorAdapter HibernateJpaVendorAdapter, ..
Hibemate. -,
ORM
. apress.prospring4.chB ( <property
name= "packagesToScan">). ,
Spring 3.1,

META-INF /persistence.xrnl. -, jpaProperties
, .. Hibemate.
, r,
7, .
390 8. Spring JPA 2

JPA ORM
Hiemate ,
JPA. JPA
, 7 I
.
7, , j vax.
persistence, JPA.
EntityManagerFactory
, . 8.3
ContactServiceimpl,
I JPA.
8.3.
package com.apress.prospring4.ch8;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@Service("jpaContactService")
@Repository
@Transactional
puic class ContactServiceimpl implements ContactService {
private Log log = LogFactory.getLog(ContactServiceimpl.class);
@PersistenceContext
private EntityManager em;
@Override
puic List<Contact> findAll()
return null;

@Override
puic List<Contact> findAllWithDetail() {
return null;

@Override
puic Contact findByid(Long id)
return null;

@Override
puic Contact save(Contact contact) {
return null;

@Override
puic void delete(Contact contact) {
}
8. Spring JPA 2 391
. @Service
Spring,
- ; Spring jpaContactService.
@Repository ,
Spring , ,
DataAccessException, Spring.
, @Transactional
.
EntityManager @Persistence
Context, JPA
. ,
@PersistenceContext, ,
EntityManager,
.
unitName
, .
.

JPA
, J .
8.4 ContactService,
, .
8.4. ContactService
package com.apress.prospring4.ch8;
import java.util.List;
puic interface ContactService
List<Contact> findAll();
List<Contact> findAllWithDetail();
Contact findByid(Long id);
Contact save(Contact contact);
void delete(Contact contact);

; ,
. save ()
.

JPQL
JPQL HQL HQL,
7,
ContactService. JPA Hibernate
, . 8.1.
392 8. Spring JPA 2

8.1. Hibernate JPA





org.hibernate hibernate 4.2.3.Final
entitymanager Hibernate 4
org.hibernate.javax.persistence hibernate-jpa- 1.0.0.Final JPA
2.1-api

8.5
7.
8.5.
package com.apress.prospring4.ch8;
import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializae;
import java.util.Date;
import java.util.HashSet;
irnport java.util.Set;
irnport javax.persistence.Entity;
irnport javax.persistence.Tale;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
import javax.persistence.Version;
import javax.persistence.Ternporal;
import javax.persistence.TemporalType;
import javax.persistence.OneToMany;
import javax.persistence.ManyToMany;
import javax.persistence.JoinTale;
irnport javax.persistence.JoinColumn;
irnport javax.persistence.CascadeType;
irnport javax.persistence.NamedQueries;
irnport javax.persistence.NamedQuery;
@Entity
@ (name = "contact")
@NarnedQueries({
@NamedQuery(name="Contact.findAll", query="select frorn Contact "),
@NamedQuery(name="Contact.findByid",
query="select distinct from Contact left join fetch
c.contactTelDetails t left join fetch c.hobies h where c.id = :id"),
@NamedQuery(narne="Contact.findAllWithDetail",
query="select distinct from Contact left join fetch
c.contactTelDetails t left join fetch c.hobies h")
})
puic class Contact implements Serializae {
private Long id;
private int version;
private String firstNarne;
private String lastName;
8. Spring JPA 2 393
private Date birthDate;
private Set<ContactTelDetail> contactTelDetails =
new HashSet<ContactTelDetail>();
private Set<Hobby> hobbies = new HashSet<Hobby>();
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "ID")
pulic Long getid() {
return this.id;

pulic void setid(Long id) {


this.id = id;

@Version
@Column{name = "VERSION")
pulic int getVersion{) {
return this.version;

puic void setVersion(int version)


this.version = version;

@Column(name = "FIRST_NAE")
puic String getFirstName()
return this.firstName;

puic void setFirstName(String firstNarne) {


this.firstNarne = firstNarne;

@Colurnn(name = "LAST_NAE")
puic String getLastNarne()
return this.lastName;

puic void setLastNarne(String lastNarne) {


this.lastNarne = lastName;

@Temporal(TernporalType.DATE)
@Column(name = "IRTH_DATE")
puic Date getBirthDate() {
return this.birthDate;

puic void setBirthDate(Date birthDate)


this.birthDate = birthDate;

@OneToMany(rnappedBy = "contact", cascade=CascadeType.ALL,


orphanRernoval=true)
puic Set<ContactTelDetail> getContactTelDetails()
return this.contactTelDetails;
394 8. Spring JPA 2
puic void setContactTelDetails(Set<ContactTelDetail> contactTelDetails)
{
this.contactTelDetails = contactTelDetails;
}
pulic void addContactTelDetail(ContactTelDetail contactTelDetail)
contactTelDetail.setContact(this);
getContactTelDetails().add(contactTelDetail);

pulic void removeContactTelDetail(ContactTelDetail contactTelDetail)


getContactTelDetails().remove(contactTelDetail);

@ManyToMany
@JoinTale(name = "contact_hobby_detail",
joinColumns = @JoinColumn(name = "CONTACT_ID"),
inverseJoinColumns = @JoinColumn(name = "HOBBY_ID"))
pulic Set<Hobby> getHobies() {
return this.hobes;

puic void setHobes(Set<Hobby> hobies)


this.hobies = hobies;

@Override
puic String toString()
return "Contact - Id: " + id + ", First name: " + firstName
+ ", Last name: " + lastName + ", Birthday: " + rthDate;

package com.apress.prospring4.ch8;
import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializae;
import javax.persistence.Entity;
import javax.persistence.Tale;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
import javax.persistence.Version;
import javax.persistence.ManyToOne;
import javax.persistence.JoinColumn;
@Entity
@Tale(name = "contact_tel_detail")
puic class ContactTelDetail implements Serializae {
private Long id;
private int version;
private String telType;
private String telNumer;
private Contact contact;
pulic ContactTelDetail()
}
8. Spring JPA 2 395
puic ContactTelDetail(String telType, String telNumer) {
this.telType = telType;
this.telNumer = telNumer;

@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "ID")
puic Long getld() {
return this.id;

puic void setld(Long id) {


this.id = id;

@Version
@Column(name = "VERSION")
pulic int getVersion() {
return this.version;

puic void setVersion(int version) {


this.version = version;

@Column(name = "TEL_TYPE")
puic String getTelType()
return this.telType;

puic void setTelType(String telType)


this.telType = telType;

@Column(name = "TEL_NUER")
puic String getTelNumer()
return this.telNumer;

pulic void setTelNumer(String telNumer) {


this.telNumer = telNumer;

@ManyToOne
@JoinColumn(name = "CONTACT ID")
puic Contact getContact()
return this.contact;

puic void setContact(Contact contact) {


this.contact = contact;

@Override
puic String toString() {
return "Contact Tel Detail - Id: " + id + ", Contact id: "
+ getContact() . getid() + ", : "
+ tel + ", Numer: " + telNumer;
396 8. Spring JPA 2
package com.apress.prospring4.ch8;
import java.io.Serializae;
import javax.persistence.Entity;
import javax.persistence.Tale;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.JoinTale;
import javax.persistence.JoinColumn;
import java.util.Set;
import java.util.HashSet;
@Entity
@ (name = "hobby")
puic class implements Serializale {
private String hobbyld;
private Set<Contact> contacts = new HashSet<Contact>();
@Id
@Column(name = "HOBBY_ID")
puic String getHobbyld()
return this.hobbyld;

pulic void setHobbyid(String hobbyld)


this.hobbyid = hobbyid;

@ManyToMany
@JoinTae(name = "contact_hobby_detail",
joinColumns = @JoinColumn(name = "HOBBY_ID"),
inverseJoinColumns = @JoinColumn(name "N ID"))
pulic Set<Contact> getContacts() {
return this.contacts;

pulic void setContacts(Set<Contact> contacts) {


this.contacts = contacts;

@Override
puic String toString()
return " :" + getHobbyid();

8.5 ,
7, . ,
Hibernate JPA .
findAll (),
. 8.6 .
8. Spring JPA 2 397
8.6. findAll ()
package com.apress.prospring4.ch8;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@Service("jpaContactService")
@Repository
@Transactional
puic class ContactServiceimpl implements ContactService {
private Log log = LogFactory.getLog(ContactServiceimpl.class);
@PersistenceContext
private EntityManager em;
@Transactional(readOnly=true)
@Override
puic List<Contact> finc:IAll()
List<Contact> contacts = em.createNamedQuery("Contact.finc:IAll",
Contact.class).getResultList();
return contacts;

@Override
puic List<Contact> finc:IAllWithDetail() {
return null;

@Override
puic Contact findByid(Long id)
return null;

@Override
puic Contact save(Contact contact) {
return null;

@Override
puic void delete(Contact contact) {

, EntityManager. createNamed
Query (), .
EntityManager TypedQuery<X>.
TypedQuery. getResul tList () .
398 8. Sprig JPA 2

8.7
ContactServiceimpl.
8.7. ContactServiceimpl
package com.apress.prospring4.ch8;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class SpringJPASample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx =
new GenericXmlApplicationContext();
ctx.load("classpath:META-INF /spring/app-context-annotation.xml");
ctx.refresh();
ContactService contactService = ctx.getBean(
"jpaContactService", ContactService.class);
listContacts(contactService.findAll());

private static void listContacts(List<Contact> contacts)


System.out.println("");
// .
System.out.println("Listing contacts without details:");
for (Contact contact: contacts) {
System.out.println(contact);
System.out.println();

:
Listing contacts without details:
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday: 1981-05-03
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28

! JPA ,
.
JPA, Hibernate, -
.
. Hibernate
JPA.

findAllWithDetail (),
. 8.8
ContactServiceimpl.
8. Spring JPA 2 399
8.8. FindAllWi thDetail ()
package com.apress.prospring4.ch8;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@Service("jpaContactService")
@Repository
@Transactional
pulic class ContactServiceimpl implements ContactService {
private Log log = LogFactory.getLog(ContactServiceimpl.class);
@PersistenceContext
private EntityManager em;
@Transactional(readOnly=true)
@Override
pulic List<Contact> findAll()
List<Contact> contacts = em.createNamedQuery("Contact.findAll",
Contact.class) .getResultList();
return contacts;

@Transactional(readOnly=true)
@Override
puic List<Contact> findAllWithDetail()
List<Contact> contacts = em.createNamedQuery(
"Contact.findAllWithDetail", Contact.class).getResultList();
return contacts;

@Override
puic Contact findByid(Long id) {
return null;

@Override
puic Contact save(Contact contact) {
return null;

@Override
puic void delete(Contact contact)
}

find.AllWi thDetail () find.All (),


left join fetch. 8.9
,
.
400 8. Spring JPA 2

8.9. ContactServiceimpl
package com.apress.prospring4.ch8;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class SpringJPASample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
ContactService contactService = ctx.getBean(
"jpaContactService", ContactService.class);
List<Contact> contacts = contactService.findAllWithDetail();
listContactsWithDetail(contacts);

private static void listContactsWithDetail(List<Contact> contacts) {


System.out.println("");
System.out.println("Listing contacts with details:");
for (Contact contact: contacts) {
System.out.println(contact);
if (contact.getContactTelDetails() != null)
for (ContactTelDetail contactTelDetail:
contact.getContactTelDetails()) {
System.out.println(contactTelDetail);

if (contact.getHobbies() != null) {
for ( hobby: contact.getHobbies())
System.out.println(hobby);

System.out.println();

, :
Listing contacts with details:
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday: 1981-05-03
Contact Tel Detail - Id: 2, Contact id: 1, : Home, Number: 1234567890
Contact Tel Detail - Id: 1, Contact id: 1, : Mobile, Numer: 1234567890
:Movies
:Swimming
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
Contact Tel Detail - Id: 3, Contact id: 2, : Home, Number: 1234567890
:Swimming
findyid (),
JPA. ,
8. Spring JPA 2 401
.
8.1 .
8.1 . findyid ()
package com.apress.prospring4.ch8;
package com.apress.prospring4.ch8;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@Service("jpaContactService")
@Repository
@Transactional
puic class ContactServiceimpl implements ContactService {
private Log log = LogFactory.getLog(ContactServiceimpl.class);
@PersistenceContext
private EntityManager em;
@Transactional(readOnly=true)
@Override
puic List<Contact> findAll()
List<Contact> contacts = em.createNamedQuery ("Contact. findAll",
Contact.class).getResultList();
return contacts;

@Transactional(readOnly=true)
@Override
puic List<Contact> findAllWithDetail()
List<Contact> contacts = em.createNamedQuery(
"Contact.findAllWithDetail", Contact.class).getResultList();
return contacts;

@Transactional(readOnly=true)
@Override
puic Contact findByid(Long id)
TypedQuery<Contact> query = em.createNamedQuery(
"Contact.findByid", Contact.class);
query.setParameter("id", id);
return query.getSingleResult();

@Override
puic Contact save(Contact contact) {
return null;

@Override
puic void delete(Contact contact) {
}
402 8. Spring JPA 2

EntityManager. createNamedQuery ( j ava. lang. String name, java.


lang. Class<T> resultClass)
TypedQuery<T>, ,
Contact. TypedQuery<T>. setParameter ()
,
getSingleResult (), ..
Contact .
.


,
. -,
.
, -,
.
, . , ,
.
.
ContactSummaryUntypeimpl
displayAllContactSummary (). 8.11
.
8.11. displayAllContactSununary ()
ContactSummaryUntypeimpl
package com.apress.prospring4.ch8;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
import java.util.List;
import java.util.Iterator;
@Service("contactSummaryUntype")
@Repository
@Transactional
pulic class ContactSummaryUntypeimpl
@PersistenceContext
private EntityManager em;
@Transactional(readOnly=true}
puic void displayAllContactSummary()
List result = em
.createQuery("select c.firstName, c.lastName, t.telNumer "
+ "from Contact left join . contactTelDetails t "
+ " where t.tel= ' '") .getResultList();
int count = ;
for (Iterator i = result.iterator(); i.hasNext() ;)
Object[J values = (Object[J} i.next(};
8. Spring JPA 2 403
System.out.println(++count + ": " + values[O] +
+ values[l] + ", " + values[2]);

8.11, Entityanager .createQuery ()


, JPQL,
.
JPQL-oepaope JPA
,
.
.
. 8.12
.
8.12. displayAllContactSummary ()
package com.apress.prospring4.ch8;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class SpringJPASample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
ContactSummaryUntypeimpl contactSummaryUntype =
ctx.getBean("contactSummaryUntype",
ContactSummaryUntypeimpl.class);
contactSummaryUntype.displayAllContactSummary();

:
1: Chris, Schaefer, 1234567890
2: Scott, Tiger, 1234567890
JPA , ,
; .


,
, JPA POJO
. , POJO
ContactSummary,
. ContactSummary 8.13.
404 8. Spring JPA 2
6.13. ContactSummary
package com.apress.prospring4.ch8;
import java.io.Serializale;
puic class ContactSummary implements Serializae {
private String firstName;
private String lastName;
private String homeTelNumer;
puic ContactSummary(String firstName, String lastName,
String homeTelNumer) {
this.firstName = firstName;
this.lastName = lastName;
this.homeTelNumer = homeTelNumber;

pulic String getFirstName()


return firstName;

puic String getLastName()


return lastName;

puic String getHomeTelNumer()


return homeTelNumer;

puic String toString()


return "First name: " + firstName + " Last Name: " + lastName
+ " Phone: " + homeTelNumer;

ContactSummary ,
, .
ContactSummary,
,
JPA
ContactSummary. ContactSummary.
8.14.
8.14. ContactSwnmaryService
package com.apress.prospring4.ch8;
import java.util.List;
puic interface ContactSummaryService
List<ContactSummary> findAll();

8.15 ContactSummaryService.
findAll (),
.
8. Spring JPA 2 405
8.15. findAll ()

package com.apress.prospring4.ch8;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
import java.util.List;
@Service("contactSummaryService")
@Repository
@Transactional
puic class ContactSummaryServiceimpl implements ContactSummaryService {
@PersistenceContext
private EntityManager em;
@Transactional(readOnly=true)
@Override
puic List<ContactSummary> finc!All()
List<ContactSummary> result = em.createQuery(
"select new com.apress.prospring4.ch8.ContactSummary("
+ "c.firstName, c.lastName, t.telNumer) "
+ "from Contact left join c.contactTelDetails t "
+ "where t.telType= 'Home'",
ContactSummary.class) .getResultList();

return result;

JPQL new
POJO, ,
ContactSurnmary.
, ContactSurnmary createQuery ()
.
f i ndAl l () ,
SpringJPASample ( 8.16).
8.16. findAll () ,

package com.apress.prospring4.ch8;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class SpringJPASample {
pulic static void main (String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
406 8. Sprig JPA 2

ContactSurnmaryService contactSurnmaryService =
ctx.getBean("contactSurnmaryService",ContactSurnmaryService.class);
List<ContactSurnmary> contacts = contactSurnmaryService.finc!All();
for (ContactSurnmary contactSurnmary: contacts)
System.out.println(contactSurnmary);


ContactSumrnary , :
First name: Chris Last Name: Schaefer Horne Phone: 1234567890
First name: Scott Last Name: Tiger Home Phone: 1234567890
,
POJO .


JPA .
Hibernate, JPA ,
. 8.17
save ().
8.17. save ()
package com.apress.prospring4.ch8;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Repository;
import org.springfrarnework.transaction.annotation.Transactional;
import java.util.List;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
irnport org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@Service("jpaContactService")
@Repository
@Transactional
puic class ContactServiceimpl implements ContactService {
private Log log = LogFactory.getLog(ContactServiceimpl.class);
@PersistenceContext
private EntityManager em;
@Transactional(readOnly=true)
@Override
puic List<Contact> finc!All()
List<Contact> contacts = em.createNamedQuery("Contact.finc!All",
Contact.class).getResultList();
return contacts;
8. Spring JPA 2 407
@Transactional(readOnly=true)
@Override
puic List<Contact> findAllWithDetail()
List<Contact> contacts = em.createNamedQuery(
"Contact.findAllWi thDetail", Contact.class).getResultList();
return contacts;

@Transactional(readOnly=true)
@Override
puic Contact findByid(Long id)
TypedQuery<Contact> query = em.createNamedQuery(
"Contact.findByid", Contact.class);
query.setParameter("id", id);
return query.getSingleResult();

@Override
puic Contact save(Contact contact) {
if (contact.getid() == null) {
log.info("Inserting new contact");
em.persist(contact);
else {
em.merge(contact);
log.info("Updating existing contact");

log.info("Contact saved with id: " + contact.getid());


return contact;

@Override
puic void delete(Contact contact) {

8.17 , save () id ,
. id null (..
), ,
EntityManager. persist (). persist (),
(EntityManager)
. id , ,
, EntityManager .merge ().
merge ()
.
8.18
.
8.18.
package com.apress.prospring4.ch8;
import java.util.List;
import java.util.Date;
408 8. Sprig JPA 2
import org.springframework.context.support.GenericXmlApplicationContext;
puic class SpringJPASample (
pulic static void main(String[] args) (
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:ETA-INF/spring/app-context-annotation.xml");
ctx.refresh();
ContactService contactService = ctx.getBean(
"jpaContactService", ContactService.class);
Contact contact = new Contact();
contact.setFirstName("Michael");
contact.setLastName("Jackson");
contact.setBirthDate(new Date());
ContactTelDetail contactTelDetail
new ContactTelDetail("Home", "1111111111");

contact.addContactTelDetail(contactTelDetail);

contactTelDetail = new ContactTelDetail("Moile", "2222222222");

contact.addContactTelDetail(contactTelDetail);

contactService.save(contact);

listContactsWithDetail(contactService.findAllWithDetail());

private static void listContactsWithDetail(List<Contact> contacts)


System.out.println("");
System.out.println("Listing contacts with details: ");
for (Contact contact: contacts) (
System.out.println(contact);
if (contact.getContactTelDetails() != null)
for (ContactTelDetail contactTelDetail:
contact.getContactTelDetails()) (
System.out.println(contactTelDetail);

if (contact.getHobbies() != null) (
for ( hobby: contact.getHobies())
System.out.println(hobby);

System.out.println();

, ,
. .
:
8. Spring JPA 2 409
INFO apress.prospring4.ch8.ContactServiceimpl: 50 - Inserting new contact
Hibernate: insert into contact (ID, BIRTH_DATE, FIRST_NAE, LAST_NAE,
VERSION) values (null, ?, ?, ?, ?)
Hibernate: insert into contact_tel_detail (ID, CONTACT_ID, TEL_NUMBER,
TEL_TYPE, VERSION) values (null, ?, ?, ?, ?)
Hibernate: insert into contact_tel_detail (ID, CONTACT ID, TEL_NUMBER,
TEL_TYPE, VERSION) values (null, ?, ?, ?, ?)
INFO apress.prospring4.ch8.ContactServiceimpl: 57 - Contact saved with id: 4
Listing contacts with details:
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday: 1981-05-03
Contact Tel Detail - Id: 2, Contact id: 1, : Home, Numer: 1234567890
Contact Tel Detail - Id: 1, Contact id: 1, : Mobile, Numer:
1234567890
:Movies
: Swimming
Contact - Id: 4, First name: Michael, Last name: Jackson, Birthday: 2013-08-12
Contact Tel Detail - Id: 4, Contact id: 4, : Home, Numer: 1111111111
Contact Tel Detail - Id: 5, Contact id: 4, : Mobile, Numer: 2222222222
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
Contact Tel Detail - Id: 3, Contact id: 2, : , Numer: 1234567890
: Swimming
INFO , id
. Hibernate SQL-,
.


, .
. , I
.
, SpringJPASample (
8.19).

8.19.
package com.apress.prospring4.ch8;
import java.util.List;
import java.util.Date;
import java.util.Set;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class SpringJPASample {
pulic static void main (String [] args) (
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
ContactService contactService = ctx.getBean(
"jpaContactService", ContactService.class);
Contact contact = contactService.findByid(ll);
410 8. Sprig JPA 2
System.out.println("");
System.out.println("Contact with id 1:" + contact);
System.out.println("");
contact.setFirstName("Justin");
Set<ContactTelDetail> contactTels = contact.getContactTelDetails();
ContactTelDetail toDeleteContactTel = null;
for (ContactTelDetail contactTel: contactTels) {
if (contactTel.getTelType().equals("Home")) {
toDeleteContactTel = contactTel;

contactTels.remove(toDeleteContactTel);
contactService.save(contact);
listContactsWithDetail(contactService.findAllWithDetail());

private static void listContactsWithDetail(List<Contact> contacts)


System.out.println("");
System.out.println("Listing contacts with details:");
for (Contact contact: contacts) {
System.out.println(contact);
if (contact.getContactTelDetails() != null)
for (ContactTelDetail contactTelDetail:
contact.getContactTelDetails()) {
System.out.println(contactTelDetail);

if (contact.getHobies() != null) {
for ( hobby: contact.getHobes())
System.out.println(hobby);

System.out.println();

I .
, "Home"
. ,
ContactService. save () .
:
Listing contacts with details:
Contact - Id: 1, First name: Justin, Last name: Schaefer, Birthday: 1981-05-03
Contact Tel Detail - Id: 1, Contact id: 1, : l, Numer: 1234567890
:Swimming
:Movies
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
Contact Tel Oetail - Id: 3, Contact id: 2, : Home, Numer: 1234567890
:Swimming
8. Spring JPA 2 411
, , .
" "
orphanRemoval=true, JPA (Hibernate)
, ,
- :
@OneToMany(mappedBy =
"contact", cascade=CascadeType.ALL, orphanRemoval=true)


.
Enti tyManager. remove () . 8.20
;1 .

8.20. delete ()
package com.apress.prospring4.ch8;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@Service("jpaContactService")
@Repository
@Transactional
puic class ContactServiceimpl implements ContactService {
private Log log = LogFactory.getLog(ContactServiceimpl.class);
@PersistenceContext
private EntityManager em;
@Transactional(readOnly=true)
@Override
puic List<Contact> findAll()
List<Contact> contacts = em.createNamedQuery("Contact.findAll",
Contact.class).getResultList();
return contacts;

@Transactional(readOnly=true)
@Override
puic List<Contact> findAllWithDetail()
List<Contact> contacts = em.createNamedQuery(
"Contact.findAllWi thDetail", Contact.class).getResultList();
return contacts;

@Transactional(readOnly=true)
412 8. Spring JPA 2
@Override
puic Contact findByid(Long id) {
TypedQuery<Contact> query = em.createNamedQuery(
"Contact.findByid", Contact.class);
query.setParameter("id", id);
return query.getSingleResult();

@Override
puic Contact save(Contact contact) {
if (contact.getid() == null) {
log.info("Inserting new contact");
em.persist(contact);
else {
em.merge(contact);
log.info("Updating existing contact");

log.info("Contact saved with id: " + contact.getid() );


return contact;

@Override
pulic void delete(Contact contact) {
Contact mergedContact = em.merge(contact);
em.remove(mergedContact);
log.info("Contact with id: " + contact.getid() + " deleted successfully");

EntityManager .merge ()
. merge ()
. EntityManager.
remove () ,
. remove () ,
, ,
cascade= CascadeType .ALL.
SpringJPASample , 8.21.
8.21.
package com.apress.prospring4.ch8;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class SpringJPASample {
pulic static void main(String [] args) {
GenericXmlApplicationContext ctx = new
GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx. refresh();
ContactService contactService = ctx.getBean(
"jpaContactService", ContactService.class);
8. Spring JPA 2 413
Contact contact = contactService.findByid(ll);
contactService.delete(contact);

listContactsWithDetail(contactService.findAllWithDetail());

private static void listContactsWithDetail(List<Contact> contacts)


System.out.println("");
System.out.println("Listing contacts with details:");
for (Contact contact: contacts) {
System.out.println(contact);
if (contact.getContactTelDetails() != null)
for (ContactTelDetail contactTelDetail:
contact.getContactTelDetails()) {
System.out.println(contactTelDetail);

if (contact.getHobies() 1 = null) {
for ( hobby: contact.getHobies())
System.out.println(hobby);

System.out.println();

l,
delete () .
:
Listing contacts with details:
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
Contact Tel Detail - Id: 3, Contact id: 2, : , Numer: 1234567890
:Swimming
, I .


JPA,
.
, .
Oracle.
(native query).
JPA ; Enti tyManager
, ,
.
JPA
ORM.
414 8. Spring JPA 2
,

Contact.

,
. 8.22 ,
ContactService find.AllByNati veQuery ().
8.22. findAllByNativeQuery()
package com.apress.prospring4.ch8;
import java.util.List;
pulic interface ContactService {
List<Contact> findAll();
List<Contact> findAllWithDetail();
Contact findByid(Long id);
Contact save(Contact contact);
void delete(Contact contact);
List<Contact> findAllByNativeQuery();

8.23 find.AllByNati veQuery ().


8.23. findAllByNativeQuery ()
package com.apress.prospring4.ch8;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@Service("jpaContactService")
@Repository
@Transactional
puic class ContactServiceimpl implements ContactService {
final static String ALL_CONTACT_NATIVE_QUERY =
"select id, first_name, last_name, irth_date, version from contact";
private Log log = LogFactory.getLog(ContactServiceimpl.class);
@PersistenceContext
private EntityManager em;
@Transactional(readOnly=true)
@Override
puic List<Contact> findAll()
List<Contact> contacts = em.createNamedQuery("Contact.findAll",
Contact.class) .getResultList();
return contacts;
8. Sprig JPA 2 415
@Transactional(readOnly=true)
@Override
pulic List<Contact> finc:!AllWithDetail()
List<Contact> contacts = em.createNamedQuery(
"Contact.finc:!AllWithDetail", Contact.class).getResultList();
return contacts;

@Transactional(readOnly=true)
@Override
puic Contact findByid(Long id)
TypedQuery<Contact> query = em.createNamedQuery(
1
1 Contact.findByid", Contact.class);
query.setParameter( 1 id", id);
1

return query.getSingleResult();

@Override
puic Contact save(Contact contact) {
if (contact.getid() == null) {
log. info("Inserting new contact 1
1) ;

em.persist(contact);
else {
em.merge(contact);
log.info("Updating existing contact");

log.info("Contact saved with id: 11 + contact.getid()) ;


return contact;

@Override
puic void delete(Contact contact) {
Contact mergedContact = em.merge(contact);
em.remove(mergedContact);
log.info( 11 Contact with id: + contact.getid() +
11 1
1
deleted successfully");

@Transactional(readOnly=true)
@Override
puic List<Contact> finc:!AllByNativeQuery()
return em.createNativeQuery(ALL_CONTACT_NATIVE_QUERY,
Contact.class).getResultList();

, - SQL-oepaop
CONTACT. ,
Enti tyManager. createNati veQuery (),
.
( Contact).
createNativeQuery () Query,
getResul tList () .
JPA
, JPA,
416 8. Spring JPA 2
. ,
finc!All ().
SQL
,
SQL.
SQL
@SqlResul tSetMapping.
SQL .
SQL
Contact ( 8.24).
8.24. SQL
package com.apress.prospring4.ch8;
import static javax.persistence.GenerationType. IDENTITY;
import java.io.Serializale;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.Tale;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
import javax.persistence.Version;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.OneToMany;
import javax.persistence.ManyToMany;
import javax.persistence.JoinTale;
import javax.persistence.JoinColumn;
import javax.persistence.CascadeType;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.EntityResult;
@Entity
@ (name = "contact")
@NamedQueries({
@NamedQuery(name="Contact.findAll", query="select from Contact "),
@NamedQuery(name="Contact.findByid",
query="select distinct from Contact left join fetch
c.contactTelDetails t left join fetch c.hobies h where c.id = :id"),
@NamedQuery(name="Contact.findAllWithDetail",
query="select distinct from Contact left join fetch
.contactTelDetails t left join fetch .hobies h")
})
@SqlResultSetMapping(
name="contactResult",
entities= @EntityResult(entityClass=Contact.class)
8. Spring JPA 2 417
puic class Contact implements Serializae {
private Long id;
private int version;
private String firstName;
private String lastName;
private Date birthDate;
private Set<ContactTelDetail> contactTelDetails =
new HashSet<ContactTelDetail>();
private Set<Hobby> hobbies = new HashSet<Hobby>();
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "ID")
puic Long getid() {
return this.id;

puic void setid (Long id) {


this.id = id;

@Version
@Column(name = "VERSION")
puic int getVersion() {
return this.version;

puic void setVersion(int version)


this.version = version;

@Column(name = "FIRST_NAE")
puic String getFirstName()
return this.firstName;

puic void setFirstName(String firstName) {


this.firstName = firstName;

@Column(name = "LAST_NAE")
pulic String getLastName()
return this.lastName;

puic void setLastName(String lastName)


this.lastName = lastName;

@Temporal(TemporalType.DATE)
@Column(name = "IRTH_DATE")
puic Date getBirthDate() {
return this.birthDate;

puic void setBirthDate(Date birthDate)


this.birthDate = birthDate;

@OneToMany(mappedBy = "contact", cascade =CascadeType.ALL,


orphanRemoval=true)
pulic Set<ContactTelDetail> getContactTelDetails()
return this.contactTelDetails;
418 8. Spring JPA 2
puic void setContactTelDetails(Set<ContactTelDetail> contactTelDetails)
this.contactTelDetails = contactTelDetails;
}
puic void addContactTelDetail(ContactTelDetail contactTelDetail)
contactTelDetail.setContact(this);
getContactTelDetails() .add(contactTelDetail);

puic void removeContactTelDetail(ContactTelDetail contactTelDetail)


getContactTelDetails().remove(contactTelDetail);

@ManyToMany
@JoinTae(name = "contact_hobby_detail",
joinColumns = @JoinColumn (name = "CONTACT_ID"),
inverseJoinColumns = @JoinColumn(name = "HOBBY_ID"))
puic Set<Hobby> getHobbies() {
return this.hobbies;

puic void setHobbies(Set<Hobby> hobbies) {


this.hobbies = hobbies;

@Override
puic String toString() {
return "Contact - Id: " + id + ", First name: " + firstName
+ ", Last name: " + lastName + ", Birthday: " + irthDate;

SQL
contactResul t enti tyClass
Contact. JPA
, .
SQL findAll
ByNativeQuery () .
8.25 ContactServiceimpl.
8.25. findAllyNativeQuery ()
SQL
package com.apress.prospring4.ch8;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@Service ("jpaContactService")
@Repository
@Transactional
8. Spring JPA 2 419
puic class ContactServiceimpl implements ContactService {
final static String ALL_CONTACT_NATIVE_QUERY =
"select id, first_name, last_name, irth_date, version from contact";
private Log log = LogFactory.getLog{ContactServiceimpl.class);
@PersistenceContext
private EntityManager em;
@Transactional(readOnly=true)
@Override
puic List<Contact> findAll()
List<Contact> contacts = em. createNamedQuery ("Contact. findAll",
Contact.class).getResultList();
return contacts;

@Transactional(readOnly=true)
@Override
puic List<Contact> findAllWithDetail()
List<Contact> contacts = em.createNamedQuery(
"Contact.findAllWithDetail", Contact.class).getResultList();
return contacts;

@Transactional(readOnly=true)
@Override
pulic Contact findByid(Long id)
TypedQuery<Contact> query = em.createNamedQuery(
"Contact.findByid", Contact.class);
query.setParameter("id", id);
return query.getSingleResult();

@Override
puic Contact save(Contact contact) {
if (contact.getid() == null) {
log. info( "Inserting new contact");
em.persist(contact);
else {
em.merge(contact);
log.info("Updating existing contact");

log.info("Contact saved with id: " + contact. getid());


return contact;

@Override
puic void delete(Contact contact) {
Contact mergedContact = em.merge(contact);
em.remove(mergedContact);
log.info("Contact with id: " + contact.getid() + " deleted successfully");

@Transactional(readOnly=true)
@Override
puic List<Contact> findAllByNativeQuery()
return em.createNativeQuery(ALL_CONTACT_NATIVE_QUERY,
"contactResult").getResultList();
420 8. Spring JPA 2
, JPA
SQL.

l-
JPA 2

. ,

.
, , .
l-
.
J 2 ,
I- (Criteria !).
Criteria APJ
.
, ,
.
I- JPA
(_).
, Contact Contact_.
Contact 8.26.
8.26. l- JPA 2:
package com.apress.prospring4.ch8;
import java.util.Date;
import javax.persistence.metarnodel.SetAttribute;
import javax.persistence.metarnodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;
@StaticMetamodel(Contact.class)
puic abstract class Contact_ {
puic static volatile SingularAttribute<Contact, Long> id;
puic static volatile SetAttribute<Contact, ContactTelDetail>
contactTelDetails;
puic static volatile SingularAttribute<Contact, String> lastName;
puic static volatile SingularAttribute<Contact, Date> birthDate;
puic static volatile SetAttribute<Contact, > hobbies;
puic static volatile SingularAttribute<Contact, String> firstName;
puic static volatile SingularAttribute<Contact, Integer> version;

@StaticMetamodel
.
.

. , , -
8. Spring JPA 2 421
JPA
. Hibernate ,
Hibernate Metamodel Generator ( Hibernate; http: //
www.hibernate.org/subprojects/jpamodelgen. html).
,
.
"Usage" ("") Hibernate
(http://docs.jboss .org/hibernate/jpamodelgen/1.3/reference/en-US/
html single/#chapter-usage), .

Maven. ,
. 8.2.
8.2.

JR-
hibernate .
jpamodelgen- hibernate-jpamodelgen-1.3.. Final
1.3..Final.jar
, Maven

,
, . 8.27
findByCriteriaQuery ()
ContactService.
8.27. findyCri teriaQuery ()
package com.apress.prospring4.ch8;
import java.util.List;
puic interface ContactService {
List<Contact> findAll();
List<Contact> findAllWithDetail();
Contact findByid(Long id);
Contact save(Contact contact);
void delete(Contact contact);
List<Contact> findAllByNativeQuery();
List<Contact> findByCriteriaQuery(String firstName, String lastName);

8.28 findByCriteriaQuery (),


l- JPA 2.
8.28. findyCri teriaQuery ()
package com.apress.prospring4.ch8;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
422 8. Sprig JPA 2
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@Service("jpaContactService")
@Repository
@Transactional
pulic class ContactServiceimpl implements ContactService {
final static String ALL_CONTACT_NATIVE_QUERY =
"select id, first_name, last_name, irth_date, version from contact";
private Log log = LogFactory.getLog(ContactServiceimpl.class);
@PersistenceContext
private EntityManager em;
@Transactional(readOnly=true)
@Override
puic List<Contact> findAll()
List<Contact> contacts = em.createNamedQuery("Contact.findAll",
Contact.class).getResultList();
return contacts;

@Transactional(readOnly=true)
@Override
pulic List<Contact> findAllWithDetail()
List<Contact> contacts = em.createNamedQuery(
"Contact.findAllWithDetail", Contact.class).getResultList();
return contacts;

@Transactional(readOnly=true)
@Override
puic Contact findByid(Long id)
TypedQuery<Contact> query = em.createNamedQuery(
"Contact.findByid", Contact.class);
query.setParameter("id", id);
return query.getSingleResult();

@Override
puic Contact save(Contact contact) {
if (contact.getid() == null) {
log.info("Inserting new contact");
em.persist(contact);
else {
em.merge(contact);
log.info("Updating existing contact");
8. Spring JPA 2 423
log.info("Contact saved with id: " + contact.getid());
return contact;

@Override
puic void delete(Contact contact) {
Contact mergedContact = em.merge(contact);
em.remove(mergedContact);
log.info("Contact with id: " + contact.getid() + " deleted
successfully");
}
@Transactional(readOnly=true)
@Override
pulic List<Contact> findAllByNativeQuery()
return em.createNativeQuery(ALL_CONTACT_NATIVE_QUERY,
"contactResult") .getResultList();

@Transactional(readOnly=true)
@Override
pulic List<Contact> findByCriteriaQuery(String firstName, String lastName) {
log.info("Finding contact for firstNarne: " + firstName
+ " and lastNarne: " + lastName);
CriteriaBuilder = ern.getCriteriaBuilder();
CriteriaQuery<Contact> criteriaQuery = cb.createQuery(Contact.class);
Root<Contact> contactRoot = criteriaQuery.from(Contact.class);
contactRoot.fetch(Contact_.contactTelDetails, JoinType.LEF);
contactRoot.fetch(Contact_.hobbies, JoinType.LEFT);
criteriaQuery.select(contactRoot).distinct(true);
Predicate criteria = cb.conjunction();
if (firstName ! = null) {
Predicate = cb.equal(contactRoot.get(Contact_.firstName),
firstNarne) ;
criteria = cb.and(criteria, );

if (lastNarne != null) {
Predicate = cb.equal(contactRoot.get(Contact_.lastName),
lastName);
criteria = cb.and(criteria, );

criteriaQuery.where(criteria);
return ern.createQuery(criteriaQuery).getResultList();

, 8.28.
Cri teriaBuilder Enti ty
Manager.getCriteriaBuilder().
Cri teriaBuilder. createQuery (),
Contact ,
.
424 8. Spring JPA 2

CriteriaQuery. from ()
. ( Root<Contact>),
.
.
Ro ot. fetch ()
, .
JoinType.LEFT . Root.fetch ()
JoinType. LEFT
left join fetch JPQL.
Cri teriaQuery.select()
. distinct ()
true , .
CriteriaBuilder.conjunction()
Predicate; ,
. Predicate ,
; - ,
, .
.
null, Predicate
CriteriaBuilder (.. Cri teriaBuilder. and () ). equal ()
;
Root. get ()
, .
(
criteria) CriteriaBuilder.and ().
Predicate ,
where
CriteriaQuery.where().
, CriteriaQuery EntityManager. EntityManager
CriteriaQuery,
.
,
SpringJPASample, 8.29.
8.29. find.yCri teriaQuery ()
package com.apress.prospring4.ch8;
import java.util.List;
import java.util.Date;
import java.util.Set;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class SpringJPASample {
puic static void main{String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
8. Spring JPA 2 425
ctx.refresh();
ContactService contactService = ctx.getBean(
"jpaContactService", ContactService.class);

List<Contact> contacts = contactService. findByCriteriaQuery("John", "Smith");


listContactsWithDetail(contacts);

private static void listContactsWithDetail(List<Contact> contacts)


System.out.println("");
System.out.println( "Listing contacts with details: ");
for (Contact contact: contacts) {
System.out.println(contact);
if (contact.getContactTelDetails() != null)
for (ContactTelDetail contactTelDetail:
contact.getContactTelDetails()) {
System.out.println(contactTelDetail);

if (contact.getHobbies() != null) {
for ( hobby: contact.getHobbies())
System.out.println(hobby);

System.out.println();

(
):
INFO apress.prospring4.ch8.ContactServicelmpl: 91 - Finding contact for
firstName: John and lastName: Smith

Listing contacts with details:


Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28

null .

Spring Data JPA


Spring Data JPA Spring Data.
Spring Data JPA
JPA.
Spring Data JPA .
. - Reposi tory, -
,
.
426 8. Sprig JPA 2

Spring Data JPA


Spring Data JPA
, . 8.3.

8.3. Maven Spring Data JPA



rpynn
org.springframework.data spring-data 1.3.0.RELEASE Spring Data
jpa JPA
com.google.guava guava 14.0.1

..
org.springframework spring-aop 4.0.2.RELEASE Spring


Repository
Spring Data JPA
Spring Data
Repos i tory (),
Spring Data Commons (https: //github. com/spring-proj ects/spring-data
commons). 1.5.2.RELEASE.
Spring Data JPA
J- EntityManager
JPA. Spring Data
org. springframework. data. repository. Repository<T, ID extends
Serializae>, ,
Spring Data Commons. Spring Data
Repository; -
org. springframework. data. repository. CrudRepository (
Spring Data Commons), .
CrudRepository .
8.30 ,
Spring Data Commons.
8.30. CrudReposi tory
package org.springframework.data.repository;
import java.io.Serializale;
@NoRepositoryBean
puic interface CrudRepository<T, ID extends Serializale> extends
Repository<T, ID> {
long count();
void delete( ID id);
8. Spring JPA 2 427
void delete(Iterae<? extends > entities);
void delete(T entity);
void deleteAll();
boolean exists(ID id);
Iterae<T> findAll();
findOne(ID id);
Iterae<T> save(Iterale<? extends > entities);
save(T entity);

, Repos i tory
.
ContactService, , .
ContactService 8.31.
ContactService SpringJpaSample ContactServiceimpl
.
Spring Data JPA.
8.31. ContactService
package com.apress.prospring4.ch8;
import java.util.List;
pulic interface ContactService {
List<Contact> findAll();
List<Contact> findByFirstName(String firstName);
List<Contact> findByFirstNameAndLastName(String firstName, String lastName);

ContactRepository,
CrudRepository. ContactRepository
8.32.
8.32. ContactReposi tory
package com.apress.prospring4.ch8;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
pulic interface ContactRepository extends CrudRepository<Contact, Long> {
List<Contact> findByFirstName(String firstName);
List<Contact> findByFirstNameAndLastName(String firstName, String lastName);

, ..
findAll () CrudRepository. findAll (). 8.32
, ContactRepository CrudRepository,
(Contact) (Long).
Repos i tory Spring Data ,
, findByFirstName
findByFirstNameAndLastName, Spring Data JPA
428 8. Spring JPA 2
. Spring Data JPA ""
.
, findByFirstName ()
select from Contact where . firstName = : firstName
firstName .
Repository,
Spring. 8.33
(app-context-annotation. xml).
8.33. JPA Spring
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdc"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<jdc:emedded-database id="dataSource" type="H2">
<jdc:script location="classpath:META-INF/sql/schema.sql"/>
<jdbc:script location="classpath:META-INF/sql/test-data.sql"/>
</jdbc:emedded-database>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
/>
</property>
<property name="packagesToScan"
value="com.apress.prospring4.ch8"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.H2Dialect
</prop>
8. Spring JPA 2 429
<prop key="hibernate.max_fetch_depth"></prop>
<prop key="hibernate.jdbc.fetch_size">SO</prop>
<prop key="hibernate.jdc.batch_size">lO</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<context:component-scan base-package="com.apress.prospring4.ch8"/>
<jpa:repositories base-package= "com.apress.prospring4.ch8"
entity-manager-factory-ref="emf"
transaction-manager-ref="transactionanager"/>
</beans>


jpa. <jpa: reposi tories>
Repository Spring Data J . Spring
com. apres s. prospr ing4 . ch8
, EntityManagerFactory
.
8.34
ContactService.
8.34. ContactServiceimpl
package com.apress.prospring4.ch8;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.Lists;
@Service("springJpaContactService")
@Repository
@Transactional
puic class ContactServiceimpl implements ContactService
@Autowired
private ContactRepository contactRepository;
@Transactional(readOnly= true)
puic List<Contact> findAll() {
return Lists.newArrayList(contactRepository.findAll());

@Transactional(readOnly=true)
puic List<Contact> findByFirstName(String firstName) {
return contactRepository.findByFirstName(firstName);

@Transactional(readOnly=true)
puic List<Contact> findByFirstNameAndLastName(
String firstName, String lastName) {
return contactRepository.findByFirstNameAndLastName(firstName, lastName);
430 8. Spring JPA 2
, Enti tyManager
ContactRepository, Spring Data JPA
. 8.35
.
8.35. SpringJpaSample
package com.apress.prospring4.ch8;
import java.util.List;
import java.util.Date;
import java.util.Set;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class SpringJPASample {
puic static void main(String [] args) (
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
ctx.refresh();
ContactService contactService = ctx.getBean(
"springJpaContactService 11 ContactService.class);
,

listContacts("Find all: ", contactService.findAll()) ;


listContacts( 11 Find first name: contactService.findByFirstName( Chris 1
11, 11
1
));

listContacts ( "Find first and last name: 1


1 ,

contactService.findByFirstNameAndLastName( 11 Chris", 1 Schaefer 11


1 ));

private static void listContacts(String message, List<Contact> contacts)

System.out.println( 1 1");

System.out.println(message);
for (Contact contact: contacts)
System.out.println(contact);
System.out.println();

, , .
, , Spring Data JPA .
, Enti tyManager .
createQuery () ..
. Repository
,
@Query, Spe cificatio n
( 1.4.4.RELEASE Spring Data JPA) ..
SpringSource:
Spring Data Commons: http: //docs. spring. io/spring-data/data
commons/docs/current/reference/html/
Spring Data JPA: http: //docs. spring. io/spring-data/data-jpa/
docs/current/reference/html/
8. Spring JPA 2 431



-, .
, , ,
, ,
.
Spring Data JPA
JPA,
. ,
org. springframework. data. domain. Audi tae<U,
ID extends Serializae> ( Spring Data Commons)
, . 8.36
Audi t, Spring Data.
8.36. Audi tale
package org.springfrarnework.data.domain;
import java.io.Serializale;
import org.joda.time.DateTime;
puic interface Auditae<U, ID extends Serializae>
extends Persistale<ID> {
U getCreatedBy();
void setCreatedBy(final U createdBy);
DateTime getCreatedDate();
void setCreated(final DateTime creationDate);
U getLastModifiedBy();
void setLastModifiedBy(final U lastModifiedBy);
DateTime getLastModifiedDate();
void setLastModified(final DateTime lastModifiedDate);

, ,
CONTACT_AUDIT, CONTACT,
, . 8.37
(schema. sql).
8.37. CONTACT_AUDIT
CREATE L CONTACT_AUDIT (
ID INT NOT NULL AUTO INCREMENT
, FIRST_NAE VARCHAR(60) NOT NULL
, LAST_NAE VARCHAR(40) NOT NULL
, BIRTH DATE DATE
, VERSION INT NOT NULL DEFAULT
, CREATED_BY VARCAR(20)
, CREATED_DATE IS
, LAST_MODIFIED_BY VARCAR(20)
, LAST_MODIFIED_DATE IS
, UNIQUE UQ_CONTACT_AUDIT_l (FIRST_NAE, LAST_NAE)
, PRIARY (ID)
) ;
432 8. Spring JPA 2

, .
ContactAudi t,
8.38.

8.38. ContactAudi t
package com.apress.prospring4.ch8;
import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializae;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Tale;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
import javax.persistence.Version;
import javax.persistence.Temporal;
import javax.persistence.Tempora!Type;
import javax.persistence.Transient;
import org.hibernate.annotations.Type;
import org.springframework.data.domain.Auditae;
import org.joda.time.DateTime;
@Entity
@(name = "contact_audit")
puic class ContactAudit implements Auditae<String, Long>, Serializae {
private Long id;
private int version;
private String firstName;
private String lastName;
private Date birthDate;
private String createdBy;
private DateTime createdDate;
private String lastModifiedBy;
private DateTime lastModifiedDate;
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "ID")
puic Long getid() {
return this.id;

puic void setid( Long id) {


this.id = id;

@Version
@Column ( = "VERSION")
puic int getVersion() {
return this.version;

puic void setVersion(int version)


this.version = version;
8. Spring JPA 2 433
@Colurnn(name = "FIRST_NAE")
puic String getFirstNarne()
return this.firstName;

puic void setFirstName(String firstName) {


this.firstName = firstName;

@Colurnn(name = "LAST_NAE")
puic String getLastName()
return this.lastName;

puic void setLastName(String lastName) {


this.lastName = lastName;

@Temporal(TemporalType.DATE)
@Column(name = "BIRTH_DATE")
puic Date getBirthDate() {
return this.birthDate;

puic void setBirthDate(Date birthDate)


this.birthDate = birthDate;

@Colurnn(name="CREATED_BY")
puic String getCreatedBy()
return createdBy;

puic void setCreatedBy(String createdBy)


this.createdBy = createdBy;

@Column(name="CREATED_DATE"}
@Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
puic DateTime getCreatedDate() {
return createdDate;

puic void setCreatedDate(DateTirne createdDate) {


this.createdDate = createdDate;

@Colurnn(narne="LAST_MODIFIED_BY")
puic String getLastModifiedBy(}
return lastModifiedBy;

puic void setLastModifiedBy(String lastModifiedBy}


this.lastModifiedBy = lastModifiedBy;

@Column(narne="LAST_MODIFIED_ DATE"}
@Type(type="org.jadira.usertype.dateandtirne.joda.PersistentDateTirne"}
puic DateTime getLastModifiedDate() {
return lastModifiedDate;
434 8. Spring JPA 2
puic void setLastModifiedDate(DateTime lastModifiedDate)
this.lastModifiedDate = lastModifiedDate;

@Transient
puic boolean isNew()
if (id == null) {
return true;
else {
return false;

puic String toString()


return "Contact - Id: " + id + ", First name: " + firstName
+ " Last name: " + lastName + ", Birthday: " + birthDate
+ ", Create : " + createdBy + ", Create date: " + createdDate
+ ", Modified : " + lastModifiedBy + ", Modified date: "
+ lastModifiedDate;

ContactAudit Audit
.
@Column.
(createdDate lastModifiedDate)
Hibernate @
org. joda. time. con.trib. hibernate. PersistentDateTime. ,
Auditae Spring Data JPA DateTime
Joda-Time, joda-time-hibernate
Hibernate
TIMESTAP . isNew () Audit (
org. springframework. data. domain. Persistae<
ID extends Serializae>) . @Transient ,
. Spring Data JPA
, ,
createdBy createdDate.
, null, true,
.
8.39 ContactAuditService,
.
8.39. ContactAudi tService
package com.apress.prospring4.ch8;
import java.util.List;
puic interface ContactAuditService
List<ContactAudit> findAll();
ContactAudit findByid(Long id);
ContactAudit save(ContactAudit contact);
8. Spring JPA 2 435
ContactAudi tReposi tory,
8.40.

8.40. ContactAuditReposi tory


package com.apress.prospring4.ch8;
import org.springframework.data.repository.CrudRepository;
pulic interface ContactAuditRepository extends CrudRepository<ContactAudit, Long>
{
}

ContactAuditRepository CrudRepository,
,
C ontactAuditSe r vice. findByid ()
CrudRepository.findOne().
8.41 ContactAuditService impl.

8.41. ContactAuditServiceimpl
package com.apress.prospring4.ch8;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import com.google.common.collect.Lists;
@Service("contactAuditService")
@Repository
@Transactional
puic class ContactAuditServiceimpl implements ContactAuditService
@Autowired
private ContactAuditRepository contactAuditRepository;
@Transactional(readOnly=true)
puic List<ContactAudit> findAll() {
return Lists.newArrayList(contactAuditRepository.findA ll());

puic ContactAudit findByid(Long id) {


return contactAuditRepository.findOne(id);

pulic ContactAudit save(ContactAudit contact)


return contactAuditRepository.save(contact);

.
Audi tingEnti tyListener<T> -
JPA, .
/src/main/resources/META-INF/orm.xml
( , JPA)
, 8.42.
436 8. Spring JPA 2

8.42. w
<?xml version="l.O" encoding="UTF-8" ?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
version= "2.0">
<description>JPA</description>
<persistence-unit-metadata>
<persistence-unit-defaults>
<entity-listeners>
<entity-listener
class="org.springframework.data.jpa.domain.support.AuditingEntityListener" />
</entity-listeners>
</persistence-unit-defaults>
</persistence-unit-metadata>
</entity-mappings>

JPA ,
( ),
.
r Spring.
8.43 (app-context-annotation. xrnl).
8.43. w Spring
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<jdc:emedded-database id= "dataSource" type="H2">
<jdbc:script location="classpath:META-INF/sql/schema.sql"/>
<jdbc:script location="classpath:META-INF/sql/test-data.sql"/>
</jdbc:emedded-database>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf"/>
</bean>
8. Spring JPA 2 437
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="emf"
class= "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name= "jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
/>
</property>
<property name= "packagesToScan"
value="com.apress.prospring4.ch8"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.H2Dialect
</prop>
<prop key="hibernate.max_fetch_depth"></prop>
<prop key="hibernate.jdbc.fetch_size">SO</prop>
<prop key="hibernate.jdc.batch_size">lO</prop>
<prop key= "hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<context:component-scan base-package="com.apress.prospring4.ch8"/>
<jpa:repositories base-package="com.apress.prospring4.ch8"
entity-manager-factory-ref="emf"
transaction-manager-ref="transactionManager"/>
<jpa:auditing auditor-aware-ref="auditorAwareBean"/>
<bean id= "auditorAwareBean" class="com.apress.prospring4.ch8.AuditorAwareBean"/>
</beans>

< j : udi t ing> 1


Sprig Data JPA, audi torAwareBean - ,
. 8.44 Audi torAwareBean.

8.44. Audi torAwareBean


package com.apress.prospring4.ch8;
import org.springframework.data.domain.AuditorAware;
puic class AuditorAwareBean implements AuditorAware<String>
pulic String getCurrentAuditor() {
return "prospring4";

AuditorAwareBean AuditorAware<T>,
String.
, , User,
, .
String . AuditorAwareBean
438 8. Spring JPA 2

getCurrentAuditor (), prospring4.



. , Spring Security
SecurityContextHolder.
. 8.45
SpringJPASample.

8.45. Spring Data JPA


package com.apress.prospring4.ch8;
import java.util.List;
import java.util.Date;
import java.util.Set;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class SpringJPASample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:ETA-INF/spring/app-context-annotation.xml");
ctx.refresh();
ContactAuditService contactService = ctx.getBean(
"contactAuditService", ContactAuditService.class);
List<ContactAudit> contacts = contactService.findAll();
listContacts(contacts);
System.out.println("Add new contact");
ContactAudit contact = new ContactAudit();
contact.setFirstName("ichael");
contact.setLastName("Jackson");
contact.setBirthDate(new Date());
contactService.save(contact);
contacts = contactService.findAll();
listContacts(contacts);
contact = contactService.findByid(ll);
System.out.println("");
System.out.println("Contact with id 1:" + contact);
System.out.println("");
System.out.println("Update contact");
contact.setFirstName("Tom");
contactService.save(contact);
contacts = contactService.findAll();
listContacts(contacts);

private static void listContacts(List<ContactAudit> contacts)


System.out.println("");
System.out.println("Listing contacts without details:");
for (ContactAudit contact: contacts) {
System.out.println(contact);
System.out.println();
8. Spring JPA 2 439
8.45
.
:
Add new contact
Listing contacts without details:
Contact - Id: 1, First name: Michael, Last name: Jackson, Birthday:
2013-08-11, Create : prospring4, Create date: 2013-08-llTOS:29:37.660-
04:00, Modified : prospring4, Modified date: 2013-08-llTOS:29:37.660-04:00
Update contact
Listing contacts without details:
Contact - Id: 1, First name: Tom, Last name: Jackson, Birthday: 2013-08-11,
Create : prospring4, Create date: 2013-08-llTOS:29:37.660-04:00,
Modified : prospring4, Modified date: 2013-08-llTOS:29:37.864-04:00

,
.
. - ,
Spring Data JPA, .


Hibernate Envers
-
. ,
(customer relationship management - CRM)
, , ,
,
.
.
,

, -
(, ). ,
. ,
.
Hibemate Envers (Entity Yersioning System -
) - Hibemate,
.
Hibemate Envers ContactAudit.

! Hibernate Envers JPA.


, ,
, Spring Data JPA.

Hibernate Envers ,
. 8.4.
440 8. Spring JPA 2

8.4. Hibernate Envers





Hibernate Envers .
, ,
,

-
. ,
.
.
r Hibernate Envers ,
,

.
,
.
,
.



. , ,
( ContactAudit),
.
CONTACT AUDIT CONTACT AUDIT .
8.46 (schema. sql).

8.46. CONTACT_AUDIT_
CREATE TABLE CONTACT_AUDIT_H (
ID INT NOT NULL
, FIRST_NAE VARCAR( 60) NOT NULL
, LAST_NAE VARCHAR(40) NOT NULL
, BIRTH_DATE DATE
, VERSION INT NOT NULL DEFAULT
, CREATED_ BY VARCAR( 20)
, CREATED_DATE TIMESTAP
, LAST_MODIFIED_BY VARCHAR(20)
, LAST MODIFIED DATE TIMESTAP
, AUDIT_REVISION IN NOT NULL
, ACTION_YPE IN
, AUDIT_REVISION_END INT
, AUDIT_REVISION_END_TS IS
, UNIQUE UQ_CONTACT_AUDIT_H_l (FIRST_NAE, LAST N)
, PRIARY (ID, AUDIT_REVISION)
);
8. Sprig JPA 2 441

( 8.46
). . 8.5.
8.5. ,

AUDIT REVISION INT
AUDIT INT
: - , 1 -
, 2 -
AUDIT REVISION END INT
AUDIT-REVISION END-TS IS ,

ibernate Envers ,
, .
REVINFO. 8.47
(schema. sql).
8.47. REVINFO
CREATE TABLE REVINFO (
REVTSTMP BIGINT NOT NULL
, REV INT NOT NULL AUTO INCREENT
, PRIARY (REVTSTMP, REV)
);

REV ,
, .
REVTSTMP ( ),
.

Enti tyanagerFactory

Hiemate Envers EJB.
LocalContainerEntityManagerFactory.
8.48 (app-context-annotation. xml).
8.48. Hibernate Envers Spring
<?xrnl version="l.O" encoding="UTF-8"?>
<beans xrnlns="http://www.springfrarnework.org/scherna/beans"
xrnlns:xsi="http://www.w.org/2001/XLScherna-instance"
xrnlns:context="http://www.springframework.org/scherna/context"
xrnlns:jdbc="http://www.springfrarnework.org/scherna/jdc"
xrnlns:jpa="http://www.springfrarnework.org/scherna/data/jpa"
xrnlns:tx="http://www.springfrarnework.org/schema/tx"
442 8. Spring JPA 2
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdc/spring-jdbc.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<jdbc:embedded-database id="dataSource" type= "H2">
<jdc:script location="classpath:META-INF/sql/schema.sql"/>
<jdc:script location="classpath:ETA-INF/sql/test-data.sql"/>
</jdbc:emedded-database>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref= "dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="packagesToScan"
value= "com.apress.prospring4.ch8"/>
<property name="jpaProperties">
<props>
<prop key= "hibernate.dialect">
org.hibernate.dialect.H2Dialect
</prop>
<prop key= "hibernate.max_fetch_depth"></prop>
<prop key= "hibernate.jdc.fetch_size">SO</prop>
<prop key="hibernate.jdbc.batch_size">lO</prop>
<prop key= "hibernate.show_sql">true</prop>
<!-- Hibernate Envers -->
<prop key="org.hibernate.envers.audit_tale_suffix"> H</prop>
<prop key="org.hibernate.envers.revision_field_name">
AUDIT REVISION
</prop>
<prop key= "org.hibernate.envers.revision_type field name">
ACTION
</prop>
<prop key= "org.hibernate.envers.audit_strategy">
org.hibernate.envers.strategy.ValidityAuditStrategy
</prop>
<prop key="org.hibernate.envers.audit_strategy_validity_end
rev field name">
AUDIT REVISION END
</prop>
8. Spring JPA 2 443
<prop key="org.hibernate.envers.audit_strategy_validity_store
revend_timestamp">
True
</prop>
<prop key="org.hibernate.envers.audit_strategy_validity_
revend_timestamp_field_name">
AUDIT REVISION END TS
</prop>
</props>
</property>
</bean>
<context:component-scan base-package ="com.apress.prospring4.ch8"/>
<jpa:repositories base-package="com.apress.prospring4.ch8"
entity-manager-factory-ref="emf"
transaction-manager-ref="transactionManager"/>
<jpa:auditing auditor-aware-ref="auditorAwareBean"/>
<bean id="auditorAwareBean" class="com.apress.prospring4.ch8.AuditorAwareBean"/>
</beans>

Hibernate Envers (org. hibernate. envers.


event. AuditEventListener)
. ,

.
(pre-collection-update,
pre-collection-remove pre-collection-recreate)
. Hibemate Envers
(, "
" " "). Hibemate Envers
, . 8.6 ( ,
org. hibernate. envers, ).
8.6. Hibernate Envers

audit t suffix
. ,
ContactAudit,
CONTACT AUDIT, Hibernate Envers
CONTACT_
AUDIT_H, .. audit_tae_suffix

revision field name

revision_type_field_name

audit_strategy ,

444 8. Spring JPA 2
. 8.6


audit strategy_validity end rev
field name
.

audit_strategy_validity_store_ ,
revend_timestamp
.

audit_strategy_validity_revend_
timestamp_field_name ,
.

,
true



Jl ,
@Audi ted. 8.49
ContactAudi t @Audi ted.
8.49. ContactAudi t
package com.apress.prospring4.ch8;
import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializae;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Tale;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
import javax.persistence.Version;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import org.hibernate.annotations.Type;
import org.springframework.data.domain.Auditale;
import org.joda.time.DateTime;
import org.hibernate.envers.Audited;
@Entity
@Audited
@Tae(name = "contact_audit")
puic class ContactAudit implements Auditae<String, Long>, Serializae {
private Long id;
private int version;
private String firstName;
8. Spring JPA 2 445
private String lastName;
private Date birthDate;
private String createdBy;
private DateTime createdDate;
private String lastModifiedBy;
private DateTime lastModifiedDate;
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "ID")
pulic Long getid() {
return this.id;

puic void setid(Long id)


this. id = id;

@Version
@Column(name = "VERSION")
pulic int getVersion() {
return this.version;

puic void setVersion(int version)


this.version = version;

@Column(name = "E'IRST_NAE")
puic String getE'irstName()
return this.firstName;

puic void setE'irstName(String firstName) {


this.firstName = firstName;

@Column(name = "LAST_NAE")
puic String getLastName()
return this.lastName;

pulic void setLastName(String lastName) {


this.lastName = lastName;

@Temporal(TemporalType.DATE)
@Column(name = "BIRTH_DATE")
puic Date getBirthDate() {
return this.birthDate;

puic void setBirthDate(Date birthDate)


this.birthDate = birthDate;

@Column(name="CREATED_BY")
pulic String getCreatedBy()
return createdBy;
446 8. Spring JPA 2
puic void setCreatedBy(String createdBy) {
this.createdBy = createdy;

@Column(name= "CREATED_DATE")
@Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
puic DateTime getCreatedDate() {
return createdDate;

puic void setCreatedDate(DateTime createdDate) {


this.createdDate = createdDate;

@Column(name= "LAST_MODIFIED_BY")
puic String getLastModifiedBy()
return lastModifiedBy;

puic void setLastModifiedBy(String lastModifiedBy)


this.lastModifiedBy = lastModifiedBy;

@Column(name= "LAST_MODIFIED_DATE")
@Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
pulic DateTime getLastModifiedDate() {
return lastModifiedDate;

pulic void setLastModifiedDate(DateTime lastModifiedDate)


this.lastModifiedDate = lastModifiedDate;

@Transient
puic boolean isNew()
if (id == null) {
return true;
else {
return false;

puic String toString() {


return "Contact - Id: " + id + ", First name: " + firstName
+ " Last name: " + lastName + ", Birthday: " + irthDate
+ ", Create : " + createdBy + ", Create date: " + createdDate
+ ", Modified : " + lastModifiedBy + ", Modified date: "
+ lastModifiedDate;

@Audi ted,
Hibernate Envers
. Hibemate Envers
.
Hibernate Envers
org. hibernate. envers. Audi tReader, -
8. Spring JPA 2 447

AuditReaderFacto ry. ContactAuditService


findAuditByRevision (),
ContactAudit .
ContactAuditService 8.50.

8.50. ContactAuditService
findAudityRevision()
package com.apress.prospring4.ch8;
import java.util.List;
puic interface ContactAuditService
List<ContactAudit> findAll();
ContactAudit findByid(Long id);
ContactAudit save(ContactAudit contact);
ContactAudit findAuditByRevision(Long id, int revision);


. 8.51
findAuditByRevision ().

8.51. findAudi tyRevision()


package com.apress.prospring4.ch8;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import com.google.common.collect.Lists;
import org.hibernate.envers.AuditReader;
import org.hibernate.envers.AuditReaderFactory;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
@Service("contactAuditService")
@Repository
@Transactional
pulic class ContactAuditServiceimpl implements ContactAuditService
@Autowired
private ContactAuditRepository contactAuditRepository;
@PersistenceContext
private EntityManager entityManager;
@Transactional(readOnly=true)
pulic List<ContactAudit> findAll() {
return Lists.newArrayList(contactAuditRepository.findAll());

puic ContactAudit findByid(Long id) {


return contactAuditRepository.findOne(id);
448 8. Spring JPA 2
pulic ContactAudit save(ContactAudit contact) {
return contactAuditRepository.save(contact);

@Transactional(readOnly=true)
@Override
puic ContactAudit findAuditByRevision(Long id, int revision) {
AuditReader auditReader = AuditReaderFactory.get(entityManager);
return auditReader.find(ContactAudit.class, id, revision);

EntityManager AuditReader
Factory AuditReader.
AuditReader. find (), ContactAudit
.


, .
8.52 , ;
ApplicationContext listContacts ()
8.52 SpringJpaSample.

8.52.
package corn.apress.prospring4.ch8;
irnport java.util.List;
irnport java.util.Date;
irnport java.util.Set;
irnport org.springfrarnework.context.support.GenericXrnlApplicationContext;
puic class SpringJPASarnple {
puic static void rnain(String [] args) {
GenericXrnlApplicationContext ctx = new GenericXrnlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context-annotation.xrnl");
ctx.refresh();
ContactAuditService contactService = ctx.getBean(
"contactAuditService", ContactAuditService.class);
Systern.out.println("Add new contact");
ContactAudit contact = new ContactAudit();
contact.setFirstNarne("Michael");
contact.setLastNarne("Jackson");
contact.setBirthDate(new Date());
contactService.save(contact);
listContacts(contactService.findAll());
Systern.out.println("Update contact");
contact.setFirstNarne("Torn");
contactService.save(contact);
listContacts(contactService.findAll());
ContactAudit oldContact = contactService.findAuditByRevision(ll, 1);
Systern.out.println("");
Systern.out.println("Old Contact with id 1 and rev 1:" + oldContact);
Systern.out.println("");
8. Spring JPA 2 449
oldContact = contactService.findAuditByRevision(ll, 2);
System.out.println("");
System.out.println("Old Contact with id 1 and rev 2:" + oldContact);
System.out.println("");
)
private static void listContacts(List<ContactAudit> contacts)
System.out.println("");
System.out.println("Listing contacts without details:");
for (ContactAudit contact: contacts) {
System.out.println(contact);
System.out.println();

.
ContactAudi t I 2 .
:
Listing contacts without details:
Contact - Id: 1, First name: Tom, Last name: Jackson, Birthday: 2013-08-11,
Create : prospring4, Create date: 2013-08-llTO:06:21.216-04:00,
Modified : prospring4, Modified date: 2013-08-llTO:06:21.556-04:00
Old Contact with id 1 and rev l:Contact - Id: 1, First name: Michael,
Last name: Jackson, Birthday: 2013-08-11, Create : prospring4, Create
date: 2013-08-llTO:06:21.216-04:00, Modified : prospring4, Modified
date: 2013-08-llTO:06:21.216-04:00
Old Contact with id 1 and rev 2:Contact - Id: 1, First name: Tom, Last name:
Jackson, Birthday: 2013-08-11, Create : prospring4, Create date:
2013-08-llTO:06:21.216-04:00, Modified : prospring4, Modified date:
2013-08-llTO:06:21.556-04:00
,
ContactAudi t Tom.
1 Michael. 2 .
, 2
.

,
JPA
,
JPA. , JPA
. JPA
ORM, ,
Spring Data JPA Hibernate Envers,
.
JPA - JEE,
, (, JBoss,
GlassFish, WebSphere, Weogic ..). , JPA
.
, JDBC
JPA.
450 8. Spring JPA 2

, J- Spring
JPA .

- JDBC. , Spring

.

JPA ,
EntityManagerFactory JPA Spring, Hibemate
. JPA
.
I-
JPA.
, , Reposi tory Spring Data
JPA JPA,
Spring Data JPA
. Hibemate Envers
.
Spring.
9


.
.
, ,

.
( , ,
ERP ..), ,
.
Jv- ( JDBC, ,
JEE ,
Spring),
. JEE, -
EJ , ,
(container-managed transaction - ),
.
EJB ,
.
, (ean
managed transaction - ), .
, l-
Java (Java Transaction APl - JTA)
.
5, ,

r. -

, Spring, JEE ,
. ,
Spring .
Spring ,
.
452 9.
Spring ,
, - .
, - ( ),
,
, Spring . ,
.
Spring.
Spring ,
.
. ,
Spring Jv-
.
, L- , Jv
.
.
, ,
Spring TransactionTemplate,
.
h JTA. ,
, ,
Spring
JTA.


Spring
, Spring ,
-
.
r ( , JDBC),

.


,
(
JDBC), .
Spring,
,
,
.
Java l
Java (Java Transaction API - JTA).
JTA
, -
9. 453
( ,
). ,
(2 Phase Commit - 2)
.
,
, .
. 9.1 ,
JTA.




(Oracle, MySQL)




(WebSphere ,
JTA
ActiveMQ)

ERP

(SAP,
//
Oracle Fiacials)


JCA

. 9. 1. , JTA

. 9.1 , (
) .
- , ,
, (enter
pise resource planning - ERP) ..
,

. , MySQL
MysqlXADa taSource, Jv-
MySQL. < (MQ, ERP ..)
.
- JTA,
,
, .
, ,
. JTA
2, ,
, ,
454 9.
.
Java (Java Transaction Service - JTS).
. (,
, ..) ,
, Spring, .

, JEE. . 9.1,
JDBC, MQ JMS ERP
Java (Java Connector Architecture - JCA).
JTA
, JEE (, JBoss, WebSphere, Weogic GlassFish),
JNDI.
- (, Tomcat Jetty),
, JTA/XA
( , Atomikos, JOTM (Java Open Transaction Manager -
Java) Bitronix).

PlatformTransactionanager
Spring PlatformTransactionManager
TransactionDefinition TransactionStatus
.
.
. 9.2 PlatformTransactionManager Spring.
Spring Platform
TransactionManager. CciLocalTransactionManager JEE,
JCA CCJ (Common Client lnterface - ).
DataSourceTransactionManager
JDBC.
-
, JDO ( JdoTransactionManager), JPA (
JpaTransactionManager), ibernate 3 Hibernate 4 ( Hibernate
TransactionManager ).
JMS JMS 1.1
( JmsTransactionManager). JTA
JtaTransactionManager.
Spring JTA,
.
WebSphere ( WebSphereUowTransactionManager),
Weogic ( WebLogicJtaTransactionManager) Oracle OC4J (
OC4JJtaTransactionManager).


, Spring,
.
ACID (atomicity,
consistency, isolation, duraility - , , ,
<<implementationet.tss> >
- org::springframeworl!::tranuclien::jta::OC4JJtar.!nsactiooanagef
<<cimplemtationClass
org::sp,ingfrall18n::jca::cci::eomiec1i0n::C<:iLQ(:;)ITransactionManager
<<Cimple<1lionCltss>>
o,g:;springframework::transactlon:la: :WeloglcJtaransactlonanager

<c<imt)lementationCl:asS>>
org::springf.lmewoltc:trlll15tion::jUl:;JlaTr<1nlladionanager
org::spnngf-rk::lran$\i\,n::PL1tf11rmTrans.,ction..

"'<in\pl&mentationClass> >
org::springframeworlt:::jUl::WeSpherel./owT11111$11c:tion.nager

<<impJernenulionQas.s>>
org:::orm::j(lo::JdoTransactlonManaglf <c<i.mplementationClass>>
org::springframewoit<::jms::::JmsTni11$ictiellauw

<<implementationClass> >
org::sp,i::jm$::i;:onneclion::J111$Transactionanager102
imp/ementa1iclClass> >
org::springframewor'lc::On11::hiemare::HiemateTr.t11saclioR.uaager

<<imp/ementatiOClasS>>
org::springfraflleWOOl::orm::hillemale4::IIIemate'r8mactionlger

. 9.2. PlatformTransactionManager Spring


456 9.
),
. ,
, -
, ,
, .
Spring Transaction
Definition.
PlatformTransactionManager,
, JDBC JTA.
, PlatformTransactionManager. getTransaction (},
TransactionDefinition
TransactionStatus. TransactionStatus
, -
, , .

TransactionDefini tion
, TransactionDefinition
. ( 9.1)
.

9.1. TransactionDefini tion


package org.springframework.transaction;
import java.sql.Connection;
pulic interface TransactionDefinition {
//
int getPropagationBehavior();
int getisolationLevel();
int getTimeout();
boolean isReadOnly() ;
String getName();

getTimeout (},
( ),
, isReadOnly (}, ,
.
,
. getName (} .
, getPropagationBehavior (} getisolationLevel (},
.
getisolationLevel (}, ,
. . 9.1
, ,
, .
9. 457
9.1.

TransactionDefinition.ISOLATION
DEFAULT
TransactionDefinition.ISOLATION ;
READ UNCOITTED ,
,

TransactionDefinition.ISOLATION
READ ID ; ,
,
.
, ,

TransactionDefinition.ISOLATION , ISOLAION READ
REPEATALE READ ID; , -
,
, .
,

TransactionDefinition.ISOLATION
SERIALIZALE ;
,

,
.
, TransactionDefinition. ISOLATION_SERIALIZABLE,
.
getPropagationBehavior () ,
, . ,
, . 9.2.
9.2. ,

TransactionDefinition.PROPAGATION ,
REQUIRED . ,

TransactionDefinition.PROPAGATION ,
SUPPORTS . ,

TransactionDefinition.PROPAGATION ,
ANDATORY . ,

TransactionDefinition.PROPAGATION .
REQUIRES_NEW ,

458 9.
. 9.2

TransactionDefinition.PROPAGATION
NOT SUPPORTED .

TransactionDefinition.PROPAGATION ,
NEVER .
,
TransactionDefinition.PROPAGATION ,
NESTED .
,
TransactionDefinition.PROPAGATION_REQUIRED

TransactionStatus
TransactionStatus, 9.2,
. ,
,
.
9.2. TransactionStatus
package org.springframework.transaction;
puic interface TransactionStatus extends SavepointManager {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
boolean isCompleted();

TransactionStatus ;
setRollbackOnly (),
.
hasSavePoint ()
(..
). flush () ,
(, Hibemate). isCompleted ()
(.. ).



,
. JPA
Hibernate .
9. 459
,
Spring Data JPA .

Spring Data JPA


. JPA,
,
. . 9.3.

9.3. Maven Spring Data JPA




org.springframework. spring-data 1.5.0.RELEASE Spring Data JPA
data jpa
org.springframework spring-core 4.0.2.RELEASE Spring
org.springframework spring- 4.0.2.RELEASE Spring
context
org.hibernate.javax. hibernate- 1.0.0.Final l- JPA
persistence jpa-2.1-api Hibernate
org.hibernate hibernate- 4.2.3.Final
entitymanager Hibernate
. google.guava guava 14.0.1

log4j log4j 1.2.17
log4j
com.h2database h2 1.3.172 2
org.slf4j slf4j-log4j12 1.7.6 ,

SLF4J log4j
org.aspectj aspectjrt 1.7.2 (1.8..1
Java 8) AspectJ
org.aspectj aspectjweaver 1.7.2 (1.8.0.1
Java 8) AspectJ


, log4j DEBUG. 9.3
log4j .properties.

9.3. DEBUG log4j .properties


log4j.rootCategory=DEBUG, stdout
log4j.appender.stdout= org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.Pattern1ayout
log4j.appender.stdout.layout.ConversionPattern=%d % [%] - <%m>%n
log4j.category.org.springframework.transaction= INFO
log4j.category.org.hibernate.SQL=DEBUG
460 9.



CONTACT, , .
9.4 9.5 ;1 (schema.sql)
(test-data. sql).

9.4.
DROP L IF EXISTS CONTACT;
CREATE TABLE CONTACT (
ID INT NOT NULL AUTO INCREMENT
, FIRST_NAE VARCAR(60) NOT NULL
, LAST_NAE VARCAR(40) NOT NULL
, BIRTH DATE DATE
, VERSION INT NOT NULL DEFAULT
, UNIQUE UQ_CONTACT_l (FIRST_NAE, LAST_NAE)
, PRIARY (ID)
) ;

9.5.
insert into contact (first_name, last_name, birth_date)
values ('Chris', 'Schaefer', '1981-05-03');
insert into contact (first_name, last_name, birth date)
values ('Scott', 'Tiger', '1990-11-02');
insert into contact (first_name, last_name, birth_date)
values ('John', 'Smith', '1964-02-28');

; Contact 9.6.

9.6. Contact
package com.apress.prospring4.ch9;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Tale;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Version;
import java.io.Serializale;
import java.util.Date;
@Entity
@Tale(name = "contact")
@NamedQueries({
@NamedQuery(name="Contact.findAll", query="select from Contact "),
@NamedQuery(name= "Contact.countAll", query="select count(c) from Contact ")
})
9. 461
puic class Contact implements Serializae {
private Long id;
private int version;
private String firstName;
private String lastName;
private Date birthDate;
puic Contact()
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
pulic Long getid() {
return this.id;

puic void setid(Long id) {


this.id = id;

@Version
@Column(name = "VERSION")
puic int getVersion()
return this.version;

puic void setVersion(int version)


this.version = version;

@Column(name = "FIRST_NAE")
puic String getFirstName()
return this.firstName;

pulic void setFirstName(String firstName) {


this.firstName = firstName;

@Column(name = "LAST_N")
puic String getLastName(}
return this.lastName;

pulic void setLastName(String lastName) {


this.lastName = lastName;

@Temporal(TemporalType.DATE)
@Column(name = "BIRTH_DATE")
puic Date getBirthDate() {
return this.birthDate;

puic void setBirthDate(Date birthDate)


this.birthDate = birthDate;

@Override
puic String toString()
return "Contact - Id: " + id + ", First name: " + firstName
+ ", Last name: " + lastName + ", Birthday: " + irthDate;
462 9.
Spring Data JPA
ContactReposi tory,
CrudRepository<T, ID extends Serializae> Spring Data
Common. ContactRepository 9.7.
9.7. ContactReposi tory
package com.apress.prospring4.ch9;
import org.springframework.data.repository.CrudRepository;
pulic interface ContactRepository extends CrudRepository<Contact, Long> {

9.7 , ,
, CrudRepositoy,
, .
, ContactService,
-, Contact.
ContactService 9.8.
9.8. ContactService
package com.apress.prospring4.ch9;
import java.util.List;
puic interface ContactService
List<Contact> findAll();
Contact findByid(Long id);
Contact save(Contact contact);
long countAll();

.
, ,
ContactService.


Spring
Spring .
,
Jv-, - L-.
.
.



Spring.
, (-,
9. 463
, ..) r ,
.
Spring,
<tx: annotation-dri ven> L-
. (tx-annotation-app-context. xml)
9.9.

9.9. Spring
<?xml version= "l.0" encoding ="UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdc="http://www.springframework.org/schema/jdc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation= "http://www.springframework.org/schema/jdc
http://www.springframework.org/schema/jdc/spring-jdc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<jdbc:emedded-database id= "dataSource" type="H2">
<jdc:script location= "classpath:META-INF/config/schema.sql"/>
<jdc:script location= "classpath:META-INF/config/test-data.sql"/>
</jdc:emedded-database>
<bean id="transactionManager"
class= "org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref= "emf"/>
</bean>
<tx:annotation-driven/>

<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
/>
</property>
<property name="packagesToScan" value="com.apress.prospring4.ch9 "/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.H2Dialect
</prop>
<prop key="hibernate.max fetch depth"></prop>
<prop key="hibernate.jdbc.fetch size">50</prop>
<prop key="hibernate.jdbc.batch-size">lO</prop>
464 9.
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<context:component-scan
base-package="com.apress.prospring4.ch9" />
<jpa:repositories base-package="com.apress.prospring4.ch9"
entity-manager-factory-ref="emf"
transaction-manager-ref="transactionManager"/>
</beans>

2
. , JPA,
JpaTransactionManager. <tx: annotation-driven>
, .
Enti tyManagerFactory,
<context: cornponent-scan>,
. , <jpa: repositories>
Spring Data JPA.
ContactService
ContactService.
ContactService. findAll () . 9. 10
ContactServicelrnpl findAll ().
9.1 . ContactServiceimpl findAll ()
package com.apress.prospring4.ch9;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service("contactService")
@Repository
@Transactional
pulic class ContactServiceimpl implements ContactService
private ContactRepository contactRepository;
@Override
@Transactional(readOnly=true)
puic List<Contact> findAll()
return Lists.newArrayList(contactRepository.findAll());

@Autowired
pulic void setContactRepository(ContactRepository contactRepository)
this.contactRepository = contactRepository;
9. 465

- @Transactional. 9.10
@Transactional , ,
Spring
. @Transactional
, . . 9.4
r .

9.4. @Transactional


propagation Propagation.REQUIRED Propagation.REQUIRED
Propagation.SUPPORTS
Propagation.ANDATORY
Propagation.REQUIRES_NEW
Propagation.NOT_SUPPORTED
Propagation.NEVER
Propagation.NESTED
isolation Isolation.DEFAULT Isolation.DEFAULT
( Isolation.READ UNCOITTED
Isolation.READ ID
) Isolation.REPEATALE READ
Isolation.SERIALIZALE
timeout TransactionDefinition.
TIMEOUT DEFAULT ;
( - -

)
readOnly false true
false
rollbackFor ,


rollbackForClassName ,


noRollbackFor ,


noRollbackForClassName ,


value
(
)
466 9.
. 9.4, @Transactional ,
, -
, - , -.
findAll () 9.10 @Transactional (
readOnly=true). ,
,
.
9.11 findAll ().

9.11. findAll ()
package com.apress.prospring4.ch9;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class TxAnnotationSample {
puic static void main(String(] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/tx-annotation-app-context.xml");
ctx.refresh();
ContactService contactService = ctx.getBean("contactService",
ContactService.class);
List<Contact> contacts = contactService.findAll();
for (Contact contactTemp: contacts) {
System.out.println(contactTemp);

,
(
):
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday: 1981-05-03
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday: 1990-11-02
Contact - Id: 3, First name: John, Last name: Smith, Birthday: 1964-02-28
, ,
. findAll ()
JpaTransactionManager Spring (
)
, ,
@Transactional .
.
JpaTransactionManager.
.
findByid () save () ContactService.
9.12.
9. 467
9.12. ContactServiceimpl
findyid () save ()
package com.apress.prospring4.ch9;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service("contactService")
@Repository
@Transactional
puic class ContactServiceimpl implements ContactService
private ContactRepository contactRepository;
@Override
@Transactional(readOnly=true)
puic List<Contact> findAll()
return Lists.newArrayList(contactRepository.findAll());

@Override
@Transactional(readOnly=true)
puic Contact findByid(Long id)
return contactRepository.findOne(id);

@Override
puic Contact save(Contact contact) {
return contactRepository.save(contact);

@Override
pulic long countAll()
return ;

@Autowired
puic void setContactRepository(ContactRepository contactRepository)
this.contactRepository = contactRepository;

findByid () @Transactional (readOnly=


true). readOnly=true
. ,
,
. , Hibemate
,
.
468 9.
save() CrudRepository.save()
. ,
, .
TxAnnotationSample
save(), 9.13.
9.13. save ()
package com.apress.prospring4.ch9;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class TxAnnotationSample {
pulic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/tx-annotation-app-context.xml");
ctx.refresh();
ContactService contactService = ctx.getBean("contactService",
ContactService.class);
List<Contact> contacts = contactService.findAll();
for (Contact contactTemp: contacts) {
System.out.println(contactTemp);

Contact contact = contactService.findByid(lL);


contact.setFirstName("Peter");
contactService.save(contact);
System.out.println("Contact saved successfully: " + contact);

Contact 1,
, . ,
:
Contact saved successfully: Contact - Id: l, First name: Peter,
Last name: Schaefer, Birthdate: 1981-05-03
save() ,
@Transactional .
JpaTransactionManager , Hibernate
JD-
.
, countAll ().
. CrudRepository. count()
, .
. , ,
CrudRepository Spring Data,
.
9.14 countAllContacts(),
ContactRepository.
9. 469
9.14. ContactReposi tory countAllContacts ()
package com.apress.prospring4.ch9;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
puic interface ContactRepository extends CrudRepository<Contact, Long> {
@Query("select count(c) from Contact ")
Long countAllContacts();

countAllContacts () @Query
, JPQL-onepaop, .
countAll () ContactServiceimpl
9.15.
9.15. ContactServiceimpl countAll ()
package com.apress.prospring4.ch9;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service("contactService")
@Repository
@Transactional
puic class ContactServiceimpl implements ContactService
private ContactRepository contactRepository;
@Override
@Transactional(readOnly=true)
pulic List<Contact> findAll()
return Lists.newArrayList(contactRepository.findAll());

@Override
@Transactional(readOnly=true)
puic Contact findByid(Long id)
return contactRepository.findOne(id);

@Override
pulic Contact save(Contact contact) {
return contactRepository.save(contact);

@Override
@Transactional(readOnly=true)
puic long countAll() {
return contactRepository.countAllContacts();

@Autowired
puic void setContactRepository(ContactRepository contactRepository)
this.contactRepository = contactRepository;
470 9.

, .
9.16 .

9.16. countAll ()
package com.apress.prospring4.ch9;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class TxAnnotationSample {
pulic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/tx-annotation-app-context.xml");
ctx.refresh();
ContactService contactService = ctx.getBean("contactService",
ContactService.class);
List<Contact> contacts = contactService.findAll();
for (Contact contactTemp: contacts) {
System.out.println(contactTemp);

Contact contact = contactService.findByid(lL);


contact.setFirstName("Peter");
contactService.save(contact);
System.out.println("Contact saved successfully: " + contact);
System.out.println("Contact count: " + contactService.countAll());

:
Contact count: 3
, countAll () ,
, .
, countAll ().
, JPA.
.
Propagation. NEVER.
9.17 countAll ().

9.17. ContactServiceimpl
countAl1 ()
package com.apress.prospring4.ch9;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
9. 471
@Service("contactService")
@Repository
@Transactional
pulic class ContactServiceimpl implements ContactService
private ContactRepository contactRepository;
@Override
@Transactional(readOnly=true)
puic List<Contact> findAll()
return Lists.newArrayList(contactRepository.findAll());

@Override
@Transactional(readOnly= true)
puic Contact findByid(Long id)
return contactRepository.findOne(id);

@Override
puic Contact save(Contact contact) {
return contactRepository.save(contact);

@Override
@Transactional(propagation= Propagation.NEVER)
puic long countAll() {
return contactRepository.countAllContacts();

@Autowired
puic void setContactRepository(ContactRepository contactRepository)
this.contactRepository = contactRepository;

9.16, ,
countAll () .
,
.
-, ,
( ) , .

! JpaTransactionManager Spring
.
. Hibernate
,
HibernateJpaDialect.

L-

Spring. Spring 2
Spring -
472 9.
TransactionProxyFactoryBean. , Spring 2,

.
,
.
L-. 9.18 L-
(tx-declarative-app-context. xml).
9.18. L-
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdc="http://www.springframework.org/schema/jdc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/jdc
http://www.springframework.org/schema/jdc/spring-jdbc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:config>
<aop:pointcut id="serviceOperation" expression=
"execution(* com.apress.prospring4.ch9.*Serviceimpl.*{ ..))"/>
<aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/>
</aop:config>

<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="find*" read-only="true"/>
<tx:method name="count*" propagation="NEVER"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<jdc:emedded-database id="dataSource" type ="H2">
<jdc:script location="classpath:META-INF/config/schema.sql"/>
<jdbc:script location="classpath:META-INF/config/test-data.sql"/>
</jdc:emedded-database>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name ="entityManagerFactory" ref="emf"/>
</bean>
9. 473
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
/>
</property>
<property name="packagesToScan" value="com.apress.prospring4"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.H2Dialect
</prop>
<prop key="hibernate.max_fetch_depth"></prop>
<prop key="hibernate.jdc.fetch_size">SO</prop>
<prop key="hibernate.jdc.batch_size">lO</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<context:component-scan
base-package="com.apress.prospring4.ch9" />
<jpa:repositories base-package="com.apress.prospring4.ch9"
entity-manager-factory-ref="emf"
transaction-manager-ref="transactionManager"/>
</beans>

9.9.
<tx:annotation-driven> ,
<context:component-scan> ,
.
<aop:config> <tx:advice>.
<:config>
(.. com. apress.
prospring4. ch9). txAdvice,
<tx: advice>. <tx: advice>
,
. , ,
( find)
, ( count)
.
. ,
. 9.19
L.

9.19. ContactServiceimpl L-
package com.apress.prospring4.ch9;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
474 9.
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("contactService")
@Repository
puic class ContactServiceimpl implements ContactService
private ContactRepository contactRepository;
@Override
puic List<Contact> findAll() {
return Lists.newArrayList(contactRepository.findAll());

@Override
puic Contact findByid(Long id) {
return contactRepository.findOne(id);

@Override
pulic Contact save(Contact contact) {
return contactRepository.save(contact);

@Override
pulic long countAll()
return contactRepository.countAllContacts();

@Autowired
puic void setContactRepository(ContactRepository contactRepository)
this.contactRepository = contactRepository;

, ,
@Transactional,
Spring L-r. 9.20
.

9.20. L-
package com.apress.prospring4.ch9;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
import com.apress.prospring4.ch9.domain.Contact;
import com.apress.prospring4.ch9.service.ContactService;
puic class TxDeclarativeSample {
pulic static void main(String[J args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:tx-declarative-app-context.xml");
ctx.refresh();
ContactService contactService = ctx.getBean("contactService",
ContactService.class);
9. 475
// findAll()
List<Contact> contacts = contactService.findAll();
for (Contact contact: contacts) {
System.out.println(contact);

11 save()
Contact contact = contactService.findByid(ll);
contact.setFirstName("Peter");
contactService.save(contact);
System. out. println("Contact saved successfully");
11 countAll()
System.out.println("Contact count: " + contactService.countAll());

,
, Spring Hibernate,
. , ,
.



. . -
PlatformTransactionManager
.
TransactionTemplate, Spring,
.
TransactionTemplate.
ContactService. countAll ().
9.21 L-
(tx-programmatic-app-context. xml).
9.21. Spring
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdc/spring-jdbc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
476 9.
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<jdbc:emedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:ETA-INF/config/schema.sql"/>
<jdc:script location="classpath:ETA-INF/config/test-data.sql"/>
</jdbc:emedded-database>
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="propagationBehaviorName" value= "PROPAGATION_NEVER"/>
<property name="timeout" value= "30"/>
<property name="transactionManager" ref ="transactionanager"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.
JpaTransactionManager">
<property name="entityManagerFactory" ref="emf"/>
</bean>

<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name= "jpaVendorAdapter">
<bean class= "org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
/>
</property>
<property name="packagesToScan"
value="com.apress.prospring4.ch9"/>
<property name="jpaProperties">
<props>
<prop key= "hibernate.dialect">
org.hibernate.dialect.H2Dialect
</prop>
<prop key="hibernate.max_fetch_depth"></prop>
<prop key="hibernate.jdbc.fetch_size">SO</prop>
<prop key="hibernate.jdc.batch_size">lO</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<context:component-scan
base-package= "com.apress.prospring4.ch9" />
<jpa:repositories base-package="com.apress.prospring4.ch9"
entity-manager-factory-ref="emf"
transaction-manager-ref="transactionManager"/>
</beans>

.
transactionTemplate org. springframework.
transaction. support. TransactionTemplate,
. countAll (),
9.22.
9. 477
9.22.
package com.apress.prospring4.ch9;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
@Service("contactService")
@Repository
puic class ContactServiceimpl implements ContactService
private ContactRepository contactRepository;
private TransactionTemplate transactionTemplate;
@PersistenceContext
private EntityManager em;
@Override
pulic List<Contact> findAll()
return Lists.newArrayList(contactRepository.findAll());

@Override
pulic Contact findByid(Long id) {
return contactRepository.findOne(id);

@Override
pulic Contact save(Contact contact) {
return contactRepository.save(contact);

@Override
puic long countAll() {
return transactionTemplate.execute(new TransactionCallback<Long>() [
puic Long doinTransaction(TransactionStatus transactionStatus) {
return em.createNamedQuery( "Contact.countAll",
Long.class) .getSingleResult();
}
}) ;

@Autowired
puic void setContactRepository(ContactRepository contactRepository) [
this.contactRepository = contactRepository;

@Autowired
pulic void setTransactionTemplate(TransactionTemplate transactionTemplate) [
this.transactionTemplate = transactionTemplate;
478 9.
TransactionTemplate.
countAll () TransactionTemplate. execute ()
, Transaction
Callback<T>.
dolnTransaction ()
. , transaction
Template. 9.23.

9.23.
package com.apress.prospring4.ch9;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class TxProgrammaticSample {
puic static void main(String[J args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/tx-programmatic-app-context.xml");
ctx.refresh();
ContactService contactService = ctx.getBean("contactService",
ContactService.class);
System. out.println ( "Contact count: " + contactService. countAll());


.
, countAll () .


, ,
, .
,
.
,
, n

.
XML
, .
,
,
.
,
,
.
9. 479

Spring
Jv-
. , ,
-,
(CRM, ERP ..).
MQ JMS
, .
, ,
( ).
,
, ,
.
. Java -
JTA.
Spring JTA ,
, -. ,
, JTA Spring.
JTA
,
. 2 (
, ),
MySQL.
,
JTA -.
, Atomikos (http://www.
atornikos. corn/Main/TransactionsEssentials),
JTA ,
, JEE.
, , ,
, .
MySQL, JPA.
, ..
JPA .
MySQL , . 9.5.
9.5. MySQL


prospring4 ch9a : prospring4 ch9a schema.sql
apo:prospring4_ch9a test-data.sql
prospring4_ch9b : prospring4_ch9b schema.sql
apo:prospring4_ch9b test-data.sql


MySQL Atomikos. . 9.6.
480 9.

9.6. Maven MySQL Atomikos





mysql mysql-connector-java 5.1.29 Jv- MySQL 5
com.atomikos transactions-jc!c 3.9.3 JTA
Atomikos

JTA
Spring. 9.24
tx-j ta-app-context. xml.
9.24. Spring JTA
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="dataSourceA" class= "com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="XADBMSA"/>
<property name="xaDataSourceClassName"
value="com.mysql.jc!c.jdbc2.optional.MysqlXADataSource"/>
<property name="xaProperties">
<props>
<prop key="databaseName">prospring4_ch9a</prop>
<prop key="user">prospring4_ch9a</prop>
<prop key="password">prospring4_ch9a</prop>
</props>
</property>
<property name="poolSize" value="l"/>
</bean>
<bean id="dataSourceB" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="XADBMSB"/>
<property name="xaDataSourceClassName"
value="com.mysql.jc!c.jc!c2.optional.MysqlXADataSource"/>
<property name="xaProperties">
<props>
<prop key="databaseName">prospring4_ch9b</prop>
<prop key="user">prospring4_ch9b</prop>
<prop key="password">prospring4_ch9b</prop>
9. 481
</prop.s>
</property>
<property name="poolSize" value="l"/>
</bean>
<bean id="emfBase"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
abstract="true">
<property name="jpaVendorAdapter">
<bean class="org.springframework.onn.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="packagesToScan" value="com.apress.prospring4.ch9"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.transaction.factory_class">
org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory
</prop>
<prop key="hibernate.transaction.manager_lookup_class">
com.atomikos.icatch.jta.hibernate.TransactionManagerLookup
</prop>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLSDialect</prop>
<prop key="hibernate.max_fetch_depth"></prop>
<prop key="hibernate.jdc.fetch_size">SO</prop>
<prop key="hibernate.jdc.batch_size">lO</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="emfA" parent="emfBase">
<property name="dataSource" ref ="dataSourceA"/>
<property name="persistenceUnitName" value="emfA"/>
</bean>
<bean id="emfB" parent="emfBase">
<property name="dataSource" ref="dataSourceB"/>
<property name="persistenceUnitName" value="emfB"/>
</bean>
<tx:annotation-driven transaction-manager="transactionanager" />
<bean id="atomikosTransactionanager"
class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<property name="forceShutdown" value="true"/>
</bean>
<bean id="atomikosUserTransaction"
class="com.atomikos.icatch.jta.UserTransactionimp">
<property name="transactionTimeout" value ="OO"/>
</bean>
<bean id="transactionanager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionanager" ref="atomikosTransactionanager"/>
<property name="userTransaction" ref="atomikosUserTransaction"/>
</bean>
<context:component-scan base-package="com.apress.prospring4.ch9 " />
</beans>
482 9.
, . ,
,
. dataSourceA dataSourceB
prospring4 ch9a prospring4 ch9b.
com. atomikos. jdbc.AtomikosDataSourceBean,
,
MySQL (com. mysql. jdbc.
jdbc2 . optiona 1 . MysqlXADataSource );
MySQL. .
, poolSi ze
, Atomikos.
. , Atomikos
, 1.
, Atomikos, , atomikosTransaction
Manager atomikosUserTransaction.
Atomikos TransactionManager UserTransaction
JEE.
, JTA,
2.
Spring- transactionManager (
JtaTransactionManager) ,
Atomikos. Spring Atomikos
JTA .
EntityManagerFactory emfBase,
emfA emfB. emfBase - ,
JPA. emfBase
LocalContainerEntityManagerFactoryBean Sprig. emfA emfB
emfBase ,
(.. dataSourceA emfA,
dataSourceB - emfB). , emfA MySQL
cxee prospring4 _ch9a dataSourceA, emfB -
prospring4 _ch9b dataSourceB.
hibernate. transaction. factory_class hibernate.
transaction.manager lookup_class emfBase.
, .. Hibemate UserTransaction
TransactionManager, ,
.
9.25 ContactServiceimpl JTA.
, save () .
9.25. ContactService JTA
package com.apress.prospring4.ch9;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
9. 483
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service("contactService")
@Repository
@Transactional
pulic class ContactServiceimpl implements ContactService {
@PersistenceContext(unitName="emfA")
private EntityManager emA;
@PersistenceContext(unitName="emfB")
private EntityManager m;
@Override
@Transactional(readOnly=true)
puic List<Contact> findAll()
return null;

@Override
@Transactional(readOnly=true)
puic Contact findByid(Long id)
return null;

@Override
puic Contact save(Contact contact) {
Contact contactB = new Contact();
contactB.setFirstName(contact.getFirstName());
contactB.setLastName(contact.getLastName());
if (contact.getid() == null) {
emA.persist(contact);
em.persist(contactB);
// throw new JpaSystemException(new PersistenceException());
else {
emA.merge(contact);
emB.merge(contact);

return contact;

@Override
puic long countAll()
return ;

,
ContactServiceimpl. save ()
. throw ;
,
prospring4 ch9b. 9.26
.
484 9.
9.26. JTA
package com.apress.prospring4.ch9;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class TxJtaSample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/tx-jta-app-context.xml");
ctx.refresh();
ContactService contactService = ctx.getBean("contactService",
ContactService.class);
Contact contact = new Contact();
contact.setFirstName("Jta");
contact.setLastName("Manager");
contactService.save(contact);
System.out.println("Contact saved successfully");


ContactService. save ().
. , ,
( ):
Contact saved successfully
Atomikos ,
( MySQL), ,
..
.
, .
9 .25, emB. pers ist ()
. 9.27.
9.27. JTA
//emB.persist(contactB);
throw new JpaSystemException(new PersistenceException());

, ,
, MySQL (..
FIRST_N, Jta, LAST_NAE,
Manager). :
Exception in thread "main" org.springframework.orm.jpa.JpaSystemException:
nested exception is javax.persistence.PersistenceException

Caused : javax.persistence.PersistenceException
main org.springframework.orm.jpa.
JpaSystemException: javax.persistence.
PersistenceException

: javax.persistence.PersistenceException
9. 485
,
, - Atomikos .
prospring4 _ch9a ,
.

JTA
JTA
, . , Spring
JTA .
,
JEE, JTA,
JEE
JTA .
, .
-
.
, , JTA
.
, Spring
- J-,

. JTA
, JtaTransactionManager Spring.


. ,
Sprig ,
. ,
.
,
L- ,
.

JEE, Spring
. ,
,
JTA
.
10



.
,
-,

.

. ,
, , , .
, -
-. ,
( ).
,
-,
( ,
L-, Contact
) , (
, , yyyy-MM-dd).

.
, ,
.
.
, Spring
, . ,
.
488 1 .

Spring
.
(service provider interface - SPI)
(Fonnatter SPI). ,
,
Jv-.
Spring. , Spring
.
Spring Validator.
JSR-349:
Bean Yalidation (JSR-349: ).

, , ,
, . 10.1.
joda-time. , Java 8,
Spring 4 JSR-310,
l- javax. time.
10.1. Maven


javax.validation validation 1.1.0.Final l- JSR-349
api
org.hibernate hibernate 5.1.0.Final Hibernate Validator,
validator
JSR-349: Bean Validation
joda-time joda-time 2.3 l- ,


Java,
.

Spring
Spring 3 ,
Jv-
Sring-. ,
,
, Jv-.

Coverter SPI.
1 . 489



4 , . Spring .
String, , POJO .
(PropertyEditor). ,
Converter SPI (, . Spring 3.0),
.
Contact ,
10.1.
r 10.1. Contact
package com.apress.prospring4.ch10;
import java.net.URL;
import org.joda.time.DateTime;
puic class Contact {
private String firstName;
private String lastName;
private DateTime birthDate;
private URL personalSite;
pulic String getFirstName()
return firstName;

puic void setFirstName(String firstName) {


this.firstName = firstName;

puic String getLastName()


return lastName;

puic void setLastName(String lastName)


this.lastName = lastName;

puic DateTime getBirthDate()


return birthDate;

puic void setBirthDate(DateTime birthDate)


this.birthDate = birthDate;

puic URL getPersonalSite()


return personalSite;

puic void setPersonalSite(URL personalSite)


this.personalSite = personalSite;

puic String toString() {


return "First name: " + getFirstName ()
+ " Last name: " + getLastName()
+ " Birth date: " + getBirthDate()
+ " Personal site: " + getPersonalSite();
490 1 .
r (birthDate) DateTime Joda
Time. URL, -
, .
, Contact
ApplicationContext ,
Spring, . I0.2
L- Spring (prop-editor-app-context. xml).
10.2. Spring
<?xml version="l. " encoding= "UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util= "http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<context:annotation-config/>
<context:property-placeholder location="classpath:application.properties"/>
<bean id="customEditorConfigurer"
class="org.springframework.beans.factory.config.CustomEditorConfigurer"
p:propertyEditorRegistrars-ref="propertyEditorRegistrarsList"/>
<util:list id= "propertyEditorRegistrarsList">
<bean class="com.apress.prospring4.chl0.DateTimeEditorRegistrar">
<constructor-arg value= "${date.format.pattern}"/>
</bean>
</util:list>
<bean id="chris" class="com.apress.prospring4.chl0.Contact"
p:firstName= "Chris"
p:lastName= "Schaefer"
p:birthDate="l981-05-03"
p:personalSite="http://www.dtzq.com"/>
<bean id="myContact" class="com.apress.prospring4.chl0.Contact"
p:firstName="${myContact.firstName}"
p:lastName="${myContact.lastName}"
p:irthDate="S{myContact.birthDate}"
p:personalSite= "${myContact.personalSite}"/>
</beans>

Contact. chris
, ,
r myContact . ,
, String
DateTime Joda-lime,
1 . 491
. (application. properties)
10.3.
10.3. application.properties
date.forrnat.pattern=yyyy--dd
myContact.firstNarne=Scott
myContact.lastName=Tiger
myContact.birthDate= l984-6-30
myContact.personalSite=http://www.somedomain.com

10.4
String DateTime Joda-ime.
10.4. DateTime Joda-Time
package com.apress.prospring4.chl0;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeForrnat;
import org.joda.time.forrnat.DateTimeForrnatter;
import org.springframework.beans.PropertyEditorRegistrar;
import org.springfrarnework.beans.PropertyEditorRegistry;
import java.beans.PropertyEditorSupport;
pulic class DateTimeEditorRegistrar implements PropertyEditorRegistrar
private DateTimeForrnatter dateTimeForrnatter;
puic DateTimeEditorRegistrar(String dateForrnatPattern) {
dateTimeFormatter = DateTimeFormat.forPattern(dateFormatPattern);

@Override
puic void registerCustomEditors(PropertyEditorRegistry registry)
registry.registerCustomEditor(DateTime.class,
new DateTimeEditor(dateTimeFormatter));

private static class DateTimeEditor extends PropertyEditorSupport


private DateTimeForrnatter dateTirneFormatter;
puic DateTimeEditor(DateTimeFormatter dateTimeFormatter)
this.dateTimeFormatter = dateTimeFormatter;

@Override
puic void setAsText(String text) throws IllegalArgumentException
setValue(DateTime.parse(text, dateTimeFormatter));

10.4 PropertyEditorRegister
PropertyEditor.
DateTimeEditor,
String DateTime. , ..
492 1 .

PropertyEditorRegistrar.
. 10.5.
10.5.
package com.apress.prospring4.chl0;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class PropEditorExample {
pulic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:ETA-INF/spring/prop-editor-app-context.xml");
ctx.refresh();
Contact chris = ctx.getBean("chris", Contact.class);
System.out.println("Chris info: " + chris);
Contact myContact = ctx.getBean("myContact", Contact.class);
System.out. println(" contact info: " + myContact);

10.5, ApplicationContext
Contact, . :
Chris info: First name: Chris - Last name: Schaefer - Birth date:
1981-05-:00:00.000-04:00 - Personal site: http://www.dtzq.com
contact info: First name: Scott - Last name: Tiger - Birth date:
1984-06-:00:00.000-04:00 - Personal site: http://www.somedomain.com

,
Contact.

Spring
Spring 3.0,
, org. springframework. core. convert.
,

Jv- POJO (
Jv- ).


,
Contact.
,
String birthDate Contact,
DateTime Joda-tme.
,
org. springframework. core. convert. converter. Converter<S, >.
10.6.
1 . 493
10.6. DateTime
package com.apress.prospring4.ch10;
import javax.annotation.PostConstruct;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;
puic class StringToDateTimeConverter implements Converter<String, DateTime>
{
private static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";
private DateTimeFormatter dateFormat;
private String datePattern = DEFAULT_DATE_PATTERN;
puic String getDatePattern()
return datePattern;

@Autowired(required=false)
pulic void setDatePattern(String datePattern)
this.datePattern = datePattern;

@PostConstruct
puic void init()
dateFormat = DateTimeFormat.forPattern(datePattern);

@Override
pulic DateTime convert(String dateString) {
return dateFormat.parseDateTime(dateString);

Converter<String, DateTime>, ,
String ( s)
Da teT ime ( ). -
@Autowired ( required=false).
,
yyyy-MM-dd. ( init (),
@PostConstruct) DateTimeFormat
Joda-Time,
. , convert () ,
.
ConversionService

org. springframework. core. convert.
ConversionService ApplicationContext.
(conv-service-app-context. xml) 10.7.
494 1 .
1 . 7.
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p ="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.apress.prospring4.chl0.StringToDateTimeConverter"/>
</list>
</property>
</bean>
<bean id="chris" class= "com.apress.prospring4.chl0.Contact"
p:firstName="Chris"
p:lastName="Schaefer"
p:birthDate= "l981-05-03"
p:personalSite="http://www.dtzq.com"/>
</beans>

Spring,
, conversionService ConversionService
FactoryBean. , Spring
.

, , , , ,
.. , String Jv-
r , .
conversionService
String DateTime. 10.8 .
10.8.
package com.apress.prospring4.chl0;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class ConvServExample {
puic static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/conv-service-app-context.xml");
ctx.refresh();
Contact chris = ctx.getBean("chris", Contact.class);
System.out.println("Contact info: " + chris);
1 . 495
:
Contact info: First name: Chris - Last name: Schaefer - Birth date:
1981-05-:00:00.000-04:00 - Personal site: http://www.dtzq.com
, chris ,
.


.
, AnotherContact,
Contact. 10.9.
10.9. AnotherContact
package com.apress.prospring4.ch10;
import java.net.URL;
import org.joda.time.DateTime;
puic class AnotherContact {
private String firstName;
private String lastName;
private DateTime birthDate;
private URL personalSite;
puic String getFirstName()
return firstName;

puic void setFirstName(String firstName) {


this.firstName = firstName;

puic String getLastName()


return lastName;

puic void setLastName(String lastName)


this.lastName = lastName;

puic DateTime getBirthDate()


return birthDate;

puic void setBirthDate(DateTime birthDate)


this.birthDate = birthDate;
puic URL getPersonalSite()
return personalSite;

puic void setPersonalSite(URL personalSite)


this.personalSite = personalSite;
puic String toString() {
return "First name: " + getFirstName()
+ " Last name: " + getLastName()
+ " Birth date: " + getBirthDate()
+ " Personal site: " + getPersonalSite();
496 1 .

Contact
AnotherContact.
firstName lastName Contact
lastName firstName AnotherContact.
. 10. 10.
10.1 . ContactToAnotherContactConverter
package corn.apress.prospring4.chl0;
irnport org.springfrarnework.core.convert.converter.Converter;
pulic class ContactToAnotherContactConverter
irnplernents Converter<Contact, AnotherContact> {
@Override
puic AnotherContact convert(Contact contact) {
AnotherContact anotherContact = new AnotherContact();
anotherContact.setFirstNarne(contact.getLastNarne());
anotherContact.setLastNarne(contact.getFirstNarne());
anotherContact.setBirthDate(contact.getBirthDate());
anotherContact.setPersonalSite(contact.getPersonalSite());
return anotherContact;

; firstName
lastName Contact AnotherContact.
ApplicationContext,
conversionService conv-service-app-context. xml ,
10.11.
1 .11.
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springfrarnework.org/scherna/beans"
xrnlns:xsi="http://www.w.org/2001/XLScherna-instance"
xrnlns:context="http://www.springfrarnework.org/scherna/context"
xrnlns:p="http://www.springfrarnework.org/scherna/p"
xsi:schernaLocation="http://www.springfrarnework.org/scherna/beans
http://www.springfrarnework.org/scherna/beans/spring-beans.xsd
http://www.springfrarnework.org/scherna/context
http://www.springfrarnework.org/scherna/context/spring-context.xsd">
<context:annotation-config/>
<bean id="conversionService"
class="org.springfrarnework.context.support.ConversionServiceFactoryBean">
<property narne="converters">
<list>
<bean class="corn.apress.prospring4.chl0.StringToDateTirneConverter"/>
<bean class="corn.apress.prospring4.chl0.
ContactToAnotherContactConverter"/>
</list>
</property>
</bean>
1 . 497
<bean id="chris" class= "com.apress.prospring4.ch10.Contact"
p:firstName= "Chris"
p:lastName="Schaefer"
p:birthDate="l981-05-03"
p:personalSite= "http://www.dtzq.com"/>
</beans>

converters .

, .. ConvServExample. 10.12
main ().

10.12.
package com.apress.prospring4.ch10;
import org.springframework.context.support.GenericXrnlApplicationContext;
import org.springframework.core.convert.ConversionService;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
pulic class ConvServExample
puic static void main(String [] args) {
GenericXrnlApplicationContext ctx = new GenericXrnlApplicationContext();
ctx.load("classpath:META-INF/spring/conv-service-app-context.xml");
ctx.refresh();
Contact chris = ctx.getBean("chris", Contact.class);
System.out.println("Contact info: " + chris);
ConversionService conversionService = ctx.getBean(ConversionService.class);
AnotherContact anotherContact =
conversionService.convert(chris, AnotherContact.class);
System. out.println("Another contact info: " + anotherContact);
String[] stringArray = conversionService.convert("a,b,c", String[] .class);
System. out.println ("String array: " + stringArray [ ] +
stringArray[l] + stringArray[2]);
List<String> listString = new ArrayList<String>();
listString.add("a");
listString.add("b");
listString.add("c");
Set<String> setString = conversionService.convert(listString, HashSet.class);
for (String string: setString)
System.out.println("Set: " + string);

Applica tionContext
ConversionService. ConversionService
498 1 .
ApplicationContext ,
Contact,
, .
String (
) Array List Set.
:
Contact info: First name: Chris - Last name: Schaefer - Birth date:
1981-05-:00:00.000-04:00 - Personal site: http://www.dtzq.com
Another contact info: First name: Schaefer - Last name: Chris - Birth date:
1981-05-:00:00.000-04:00 - Personal site: http://www.dtzq.com
String array:
Set:
Set:
Set:
, Contact AnotherContact
, String Array
List Set. Spring

.
, .
(,
..).
.
Spring 3.0, Spring
( Formatter SPI,
).
-
<mvc: annotation-driven/>
( , StringToArrayConverter, StringToBooleanConverter
StringToLocaleConverter org. springframework. core. convert.
support) (, CurrencyFormatter, DateFormatter
NumerFormatter org. springframework.
format). 16,
- Spring.

Spring
, Sring-
- Formatter SPI.
, SI- ,
.
Formatter SPI,
, org. springframework. format. Formatter<T>.
Spring
, CurrencyFormatter, DateFormatter, NumberFormatter
PercentFormatter.
1 . 499


.
Contact
DateTi me birthDate String.
-
org.springframework.format.support.FormattingConversionServiceFactoryBean
Spring .
FormattingConversionServiceFactoryBean - ,
FormattingConversion
Service, ,
,
.
10.13 ,
FormattingConversi onServiceFactoryBean,
, DateTi me Joda-!me.
10.13. ApplicationConversionServiceFactoryean
package com.apress.prospring4.ch10;
import java.text. ParseException;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import javax.annotation.PostConstruct;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springfrarnework.format.Formatter;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
puic class ApplicationConversionServiceFactoryBean extends
FormattingConversionServiceFactoryBean {
private static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";
private DateTimeFormatter dateFormat;
private String datePattern = DEFAULT_DATE PATTERN;
private Set<Formatter<?>> formatters = new HashSet<Formatter<?>>();
pulic String getDatePattern()
return datePattern;

@Autowired(required=false)
pulic void setDatePattern(String datePattern)
this.datePattern = datePattern;

@PostConstruct
puic void init()
dateFormat = DateTimeFormat.forPattern(datePattern);
formatters.add(getDateTimeFormatter());
setFormatters(formatters);
500 1 .
pulic Formatter<DateTime> getDateTimeFormatter()
return new Formatter<DateTime>() {
@Override
pulic DateTime parse(String dateTimeString, Locale locale)
throws ParseException {
System.out.println("Parsing date string: " + dateTimeString);
return c\ateFormat.parseDateTime(dateTimeString);

@Override
pulic String print(DateTime dateTime, Locale locale) {
System.out.println("Formatting datetime: " + dateTime);
return dateFormat.print(dateTime);
};


. Formatter<DateTime> ,
. parse () String
DateTime ( ),
print () DateTime String.
(
yyyy-MM-dd). , init ()
setFormatters ().
, .

ConversionServiceFactoryBean
ApplicationConversionServiceFactoryBean
ApplicationContext,
. 10.14
conv-format-service-app-context.xml.
10.14. conv-format-service-app-context. xml
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation= "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean id="conversionService"
class="com.apress.prospring4.chl0.ApplicationConversionServiceFactoryBean"/>
<bean id="chris" class="com.apress.prospring4.ch10.Contact"
p:firstName="Chris"
p:lastName="Schaefer"
p:birthDate="l981-05-03"
p:personalSite="http://www.dtzq.com"/>
</beans>
1 . 501

10.15 .
10.15.
package com.apress.prospring4.ch10;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.convert.ConversionService;
puic class ConvFormatServExample (
pulic static void main(String[] args) (
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/conv-format-service-app-context.xml");
ctx.refresh();
Contact chris = ctx.getBean("chris", Contact.class);
System.out.println("Contact info: " + chris);
ConversionService conversionService =
ctx.getBean("conversionService", ConversionService.class);
System.out.println("Birthdate of contact is : " +
conversionService.convert(chris.getBirthDate(), String.class));

:
Parsing date string: 1981-05-03
Contact info: First name: Chris - Last name: Schaefer - Birth date:
1981-05-03::.000-04:00 - Personal site: http://www.dtzq.com
Formatting datetime: 1981-05-03:00:.-04:
Birthdate of contact is : 1981-05-03
, Spring parse ()
String DateTime
irthDate. ConversionService. convert ()
irthDate print () .

Spring

. ,
, , -
-.
,
,
(,
, -, JMS
).
,
, ,
, POJO
, . ,
502 1 .
-
. , -
Spring MVC, Spring
- String
(, String, ,
Date yyyy-MM-dd).
. ,
,
, .
, .
Spring .
Spring
or g .springframework.
validation.Validator.
JSR-349, .. l- ,
Spring. .

Valida tor Spring


Validator Spring
, .
, . , Contact,
, .
Contact ,
. 10.16.
10.16. ContactValidator
package com.apress.prospring4.ch10;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
@Component("contactValidator")
puic class ContactValidator implements Validator
@Override
pulic boolean supports(Class<?> clazz)
return Contact.class.equals(clazz);
@Override
puic void validate(Object obj, Errors ) {
ValidationUtils.rejectifEmpty(e, "firstName", "firstName.empty");

Validator .
suppor ts () ,
. validate ()
.
or g. springfrarnework. validation.Errors. validate ()
1 . 503
r firstName
ValidationUtils. rejectifEmpty () ,
. - ,
, ,
.
10.17 Spring
{spring-validator-app-context. xml).
1 . 17. r Spring
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.apress.prospring4.chl0"/>
</beans>

10.18 .

10.18.
package com.apress.prospring4.chl0;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
pulic class SpringValidatorSarnple {
pulic static void main(String [ J args) {
GenericXrnlApplicationContext ctx = new GenericXrnlApplicationContext();
ctx.load("classpath:META-INF/spring/spring-validator-app-context.xml");
ctx.refresh();
Contact contact = new Contact();
contact.setFirstNarne(null);
contact.setLastName("Schaefer");
Validator contactValidator =
ctx.getBean("contactValidator", Validator.class);
BeanPropertyBindingResult result =
new BeanPropertyBindingResult(contact, "Chris");
ValidationUtils.invokeValidator(contactValidator, contact, result);
List<ObjectError> errors = result.getAllErrors();
System.out.println("No of validation errors: " + errors.size());
for (ObjectError error: errors) {
System.out.println(error.getCode());
504 1 .
Contact , null.
ApplicationContext .

BeanPropertyBindingResult.
ValidationUtils. invokeValidator ().
.
:
No of validation errors: 1
firstName.empty
,
.

JSR-349: Validation
Spring 4 JSR-349,
/- (Bean Validation
/). j avax. valida tion. constraints
Jv- (, @NotNull),
.
(, )
.
Bean Validation /
. Bean Validation /,

/-,
. ,
, JSR-349, Hibernate Validator 5
(http: / /hibernate. org / subproj ects /val idator).
Spring Bean Validation /.

JSR-349 ,
JSR-349
ApplicationContext.
. Spring -
JSR-303, Hibernate Validator 4,
/- 1.0.


. 10.19 Customer
, firstName customerType.
10.19. Cus tomer
package com.apress.prospring4.chl0;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
1 . 505
puic class Customer {
@NotNull
@Size(min= 2, m= )
private String firstName;
private String lastName;
@NotNull
private CustomerType customerType;
private Gender gender;
puic String getFirstName()
return firstName;

puic void setFirstName(String firstName) {


this.firstName = firstName;

puic String getLastName()


return lastName;

puic void setLastName(String lastName) {


this.lastName = lastName;

puic CustomerType getCustomerType()


return customerType;

puic void setCustomerType(CustomerType customerType)


this.customerType = customerType;

pulic Gender getGender()


return gender;

puic void setGender(Gender gender)


this.gender = gender;

puic boolean isindividualCustomer()


return this.customerType.equals(CustomerType.INDIVIDUAL);

firstName .
@NotNull, , null.
, @Size firstName.
@NotNull customerType. l0.20 10.21
CustomerType Gender.

10.20. Customerype
package com.apress.prospring4.chl0;
puic enum CustomerType {
INDIVIDUAL("I"), CORPORATE("C");
506 1 .
private String code;
private CustomerType(String code)
this.code = code;

@Override
puic String toString()
return this.code;

10.21. Gender
package com.apress.prospring4.chl0;
puic enum Gender {
L (""), FEALE( "F") ;
private String code;
private Gender(String code) {
this.code = code;

@Override
pulic String toString()
return this.code;

( Cus tomerType) ,
, ( Gender)
- . null.
Spring
r Bean Validation [ ApplicationContext,
org. spri ngframework. validation. bean
vali dation. LocalValidatorFac toryBean Spring.
j sr34 9-app-context. xml 10.22.
10.22. Bean Validation API Spring
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation ="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan
base-package="com.apress.prospring4.ch10"/>
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
</beans>
1 . 507
LocalValidatorFactory
Bean. Spring Hibernate Validator
.
Customer. MyBeanValidationService
10.23.
10.23. yeanValidationService
package com.apress.prospring4.chl0;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service("myBeanValidationService")
puic class MyBeanValidationService
@Autowired
private Validator validator;
puic Set<ConstraintViolation<Customer>> validateCustomer(Customer customer)
{
return validator.validate(customer);

j avax. validation. Validator (


Validator, Spring,
org. springframework. validation. Validator).
LocalValidatorFactoryBean
Validator .
POJO Validator. validate ().
(List)
ConstraintViolation<T>.
10.24.
10.24. Jsr349Sample
package com.apress.prospring4.chl0;
import java.util.HashSet;
import java.util.Set;
import javax.validation.ConstraintViolation;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class Jsr349Sample {
pulic static void main(String[J args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:ETA-INF/spring/jsr349-app-context.xml");
ctx.refresh();
MyBeanValidationService myBeanValidationService =
ctx.getBean( "myBeanValidationService", MyBeanValidationService.class);
508 1 .
Customer customer = new Customer();
customer.setFirstName("C");
customer.setLastName("Schaefer");
customer.setCustomerType(null);
customer.setGender(null);
validateCustomer(customer, myBeanValidationService);

private static void validateCustomer(Customer customer,


MyBeanValidationService myBeanValidationService) {
Set<ConstraintViolation<Customer>> violations =
new HashSet<ConstraintViolation<Customer>>();
violations = myBeanValidationService.validateCustomer(customer);
listViolations(violations);

private static
void listViolations(Set<ConstraintViolation<Customer>> violations)
System.out.println("No. of violations: " + violations.size());
for (ConstraintViolation<Customer> violation: violations)
System.out.println("Validation error for property: " +
violation.getPropertyPath()
+ " with value: " + violation.getinvalidValue()
+ " with error message: " + violation.getMessage());

, Customer
firstName customerType, .
validateCustomer () MyBeanValidationService.
validateCustomer (), , , JSR-349 Bean
Valiadation API.
:
No. of violations: 2
Validation error for property: customerType with value:
null with error message: not null
Validation error for property: firstName with value:
with error message: size must between 2 and 60
, ,
. , Hibernate Yalidator
.
,
.


. , Customer
, lastName gender null.
1 . 509

. Bean Validation API
.
, 10.25.
, .

10.25. CheckindividualCustomer
package com.apress.prospring4.ch10;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Constraint(validatedBy=IndividualCustomerValidator.class)
@Documented
puic @interface CheckindividualCustomer {
String message () default "Individual customer should have gender and last
name defined";
Class<?>[J groups() default {};
Class<? extends Payload> [] payload() default {};

@Tar get (ElementTyp e.) ,


. @C onstraint ,
, validatedBy ,
. ( ),
.
message ( ) ,
.
.
groups ,
.
.
payload (,
javax.validation.Payload).
(,

).
10.26 IndividualCustomerValidator,
.
510 10.
10.26. IndividualCustomerValidator
package com.apress.prospring4.ch10;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
puic class IndividualCustomerValidator implements
ConstraintValidator<CheckindividualCustomer, Customer>
@Override
pulic void initialize(CheckindividualCustomer constraintAnnotation)
}
@Override
puic boolean isValid(Customer customer,
ConstraintValidatorContext context) {
boolean result = true;
if (customer.getCustomerType() != null &&
(customer.isindividualCustomer() && (customer.getLastName() null
1 1 customer.getGender() == null))) {
result = false;
return result;

Indi vidualCustomerValida tor Constraint


Validator<CheckindividualCustomer, Customer>, ,
CheckindividualCustomer Customer.
isValid () ,
( , ibernate Yalidator)
. ,
, , lastName gender null.
, , .
, @Check
IndividualCustomer Customer, 10.27.
10.27. Customer
package com.apress.prospring4.ch10;
@CheckindividualCustomer
puic class Customer {

,
10.28, main () Jsr349Sample 10.24.
10.28.
Customer
customer.setFirstName("Chris");
customer.setLastName("Schaefer");
customer.setCustomerType(CustomerType.INDIVIDUAL);
customer.setGender(null);
validateCustomer(customer, myBeanValidationService);
10. 511
( ):
No. of violations: 1
Validation error for property: with value: com.apress.prospring4.ch10.
Customer@5ae50ce6 with error message: Individual customer should have
gender and last name defined
, (
Customer) -
, .. gender null. ,
, .
@AssertTrue


Bean Validation \
@AssertTrue . , .
Customer @CheckindividualCustomer
10.29.
10.29. @AssertTrue Customer
pulic class Customer {

@AssertTrue(message= "ERROR ! Individual customer should have gender and


last name defined")
puic boolean isindividualCustomer()
boolean result = true;
if (getCustomerType() ! = null &&
(this.customerType.equals(CustomerType.INDIVIDUAL)
&& (gender == null 11 lastName == null))) {
result = false;
}
return result;

Customer isValidindividualCustomer (),


@AssertTrue ( javax.validation.constraints).

, true. JSR-349
@AssertFalse ,
false. (Jsr349Sample) ,
, .

,
JSR-349: @AssertTrue?
@AssertTrue ,
. ,
(, -
512 1 .
,
) ,

. ,
.

l-

Validator Spring Bean Va\idation
APJ , ? ,
JSR-349 .
JSR-349 - JEE,
(, Spring,
JPA 2, Spring MVC GW).
JSR-349 l-
, ,
.
4, Spring JSR-349.
, - Spring MVC
@Valid ( javax. validation), Spring
JSR-349 .
, - Spring MVC
<mvc: annotation-driven/> Spring
Spring,
JSR-349: Bean Validation.
JPA 2,
JSR-349 ,
.
JSR-349: Bean Validation
Hibernate Validator
Hibernate Validator (http: //docs. jboss. org/hibernate/
validator/5. 1/reference/en-US/html).

Spring,
Sl- . ,

.
, Spring ,
Validator JSR-349: Bean Validation.
11

Spring
[1
. :
( -,
), ( ,
) (
, ).
, .
Spring.
Spring, TaskScheduler,
Spring 3. ,
cron.
. ,
@Async Spring .
Spring. TaskExecutor
Spring .


. 11.1 ,
, .
11.1. Maven



org.springfrarnework. spring-data- 1.5.0. Spring Data JPA
data jpa RELEASE
joda-time joda-time 2.3 Joda-Time (http: //
joda-time.sourceforge.net/)
org.jadira.usertype usertype.core 3.0.0.GA
Hibernate, -

514 11. Spring

. 11. 1



com.google.guava guava 14.0.1

, ,
..
org.slf4j slf4j-log4j12 1.7.6
(www.slf4j.org),

.

SLF4J log4j

Spring
.
(
, , ,
..) ,
(, ),
(, 20:00 ).
, :
(), () .
Sring-
.
, . ,
,
Control-M AutoSys. u
Linux/Unix, crontab.
- REST, Spring,
Spring MVC .
,
Spring. Spring .
JD- Timer. Spring
Timer JDK.
Quartz. Spring Quartz Scheduler
(www. quartz-scheduler. org) -
.
TaskScheduler, Spring. Spring 3
TaskScheduler,
.

TaskScheduler .
11. Spring 515
TaskScheduler
TaskScheduler Spring
.
Trigger. org. springframework. scheduling. Trigger
. Spring n
Trigger. CronTrigger
cron, PeriodicTrigger -
.
. - -,
. Spring
Spring.
TaskScheduler. org. springframework. scheduling.
TaskS cheduler .
Spring TaskScheduler.
TimerManagerTaskScheduler ( org. springframework.
scheduling. commonj) commonj. timers.
TimerManager CommonJ,
JEE, WebSphere Weogic.
ConcurrentTaskScheduler ThreadPoolTaskScheduler (
org. springframework. scheduling. concurrent)
j ava. util. concurrent. ScheduledThreadPoolExecutor.
.
. 11.1 Trigger,
TaskScheduler ( java. lang. Runnae).

CronTrigger PeriodicTrigger SchedulerMethodRunnae

Task

TaskScheduler

TimerManagerTaskScheduler ConcurrentaskScheduler ThreadPoolTaskScheduler

. 11. 1. ,
516 11. Spring

TaskScheduler Spring
.
task L- Spring, - .
.


Spring
, - ,
. 11.1 r,
JPA.
11.1 . car
package com.apress.prospring4.chll;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Colurnn;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Tale;
import javax.persistence.Version;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;
@Entity
@Tale(name="car")
puic class Car {
private Long id;
private String licensePlate;
private String manufacturer;
private DateTime manufactureDate;
private int age;
private int version;
@Id
@GeneratedValue(strategy = IDENTITY)
@Colurnn(narne = "ID")
puic Long getid() {
return id;

@Colurnn(narne="LICENSE_PLATE")
puic String getLicensePlate()
return licensePlate;

@Colurnn(narne="ANUFACTURER")
puic String getManufacturer()
return rnanufacturer;

@Colurnn(narne="ANUFACTURE_DATE")
@Type(type="org.jadira.usertype.dateandtirne.joda.PersistentDateTirne")
puic DateTime getManufactureDate() {
return rnanufactureDate;
11. Spring 517
@Column(name= 11 AGE 11 )

puic int getAge()


return age;

@Version
puic int getVersion()
return version;

puic void setid(Long id)


this.id = id;

pulic void setLicensePlate(String licensePlate)


this.licensePlate = licensePlate;

puic void setManufacturer(String manufacturer)


this.manufacturer = manufacturer;

puic void setManufactureDate(DateTime manufactureDate)


this.manufactureDate = manufactureDate;

pulic void setAge(int age)


this.age = age;

puic void setVersion(int version)


this.version = version;

@Override
puic String toString()
return License:
11 + licensePlate +
11 Manufacturer:
11 - 11 + manufacturer
+ Manufacture Date:
11 - + manufactureDate + 11
11 - Age: 1 + age;
1

11.2 11.3 (schema. sql)


(test-data.sql ) Car.

11.2.
DROP L IF EXISTS CONTACT;
CREATE TABLE CAR (
ID INT NOT NULL AUTO INCREMENT
, LICENSE_PLATE VARCAR(20) NOT NULL
, ANUFACTURER VARCAR(20) NOT NULL
, ANUFACTURE_DATE DATE NOT NULL
, AGE INT NOT NULL DEFAULT
, VERSION INT NOT NULL DEFAULT
, UNIQUE UQ_CAR_l (LICENSE_PLATE)
, PRIARY (ID)
) ;
518 11. Spring

11..
insert into car (license_plate, manufacturer, manufacture_date)
values ('LICENSE-1001', 'Ford', '1980-07-30');
insert into car (license_plate, manufacturer, manufacture_date)
values ('LICENSE-1002', 'Toyota', '1992-12-30');
insert into car (license_plate, manufacturer, manufacture_date)
values ('LICENSE-1003', 'W', '2003-1-6');

Car.
Spring Data JPA .
11.4 CarReposi tory.

11.4. CarReposi tory


package com.apress.prospring4.chll;
import org.springframework.data.repository.CrudRepository;
puic interface CarRepository extends CrudRepository<Car, Long>
}

;
CrudReposi tory<Car, Long>. 11.5 11.6
CarService CarServiceimpl.

11.5. CarService
package com.apress.prospring4.chll;
import java.util.List;
puic interface CarService
List<Car> findAll();
Car save(Car car);
void updateCarAgeJo();

11.6. CarServiceimpl
package com.apress.prospring4.chll;
import com.google.common.collect.Lists;
import org.joda.time.DateTime;
import org.joda.time.Years;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service("carService")
@Repository
@Transactional
11. Spring 519
pulic class CarServiceimpl implements CarService (
final Logger logger = LoggerFactory.getLogger(CarServiceimpl.class);
@Autowired
CarRepository carRepository;
@Override
@Transactional(readOnly=true)
puic List<Car> findAll() (
return Lists.newArrayList(carRepository.findAll());

@Override
puic Car save(Car car) (
return carRepository.save(car);

@Override
pulic void updateCarAgeJo()
List<Car> cars = findAll();
DateTime currentDate = DateTime.now();
logger.info( 11 Car age update job started 11 );
for (Car car: cars) {
int age =
Years.yearsBetween(car.getManufactureDate(), currentDate).getYears();
car.setAge(age);
save(car);
logger. info( 11 Car age update--- 1
1
+ car);

logger.info( 11 Car age update job completed successfully 11 );

;
, Car. ,
updateCarAgeJob (), ,
,
.
11.7 Spring
(car-job-app-context.xml).

11.7. car-job-app-context.xml
<?xml version=11 l. " encoding= 11 UTF-8 11 ?>
<beans xmlns= 11 http://www.springframework.org/schema/beans 11
xmlns:context= 11 http://www.springframework.org/schema/context 11
xmlns:jdc= 11 http://www.springframework.org/schema/jdbc 11
xmlns:tx="http://www.springframework.org/schema/tx 11
xmlns:jpa= 11 http://www.springframework.org/schema/data/jpa 11
xmlns:xsi= 11 http://www.w3.org/2001/XMLSchema-instance 11
xsi:schemaLocation= 11 http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
520 11. Spring
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdc
http://www.springframework.org/schema/jdc/spring-jdc.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<jdbc:emedded-database id="dataSource" type="H2">
<jdbc:script location= "classpath:META-INF/config/schema.sql"/>
<jdbc:script location="classpath:META-INF/config/test-data.sql"/>
</jdc:embedded-database>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref= "emf"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="emf"
class= "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
/>
</property>
<property name="packagesToScan" value="com.apress.prospring4.chll"/>
<property name= "jpaProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.H2Dialect
</prop>
<prop key="hibernate.max_fetch_depth"></prop>
<prop key="hibernate.jdc.fetch_size">SO</prop>
<prop key="hibernate.jdc.batch_size">lO</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<jpa:repositories base-package="com.apress.prospring4.chll"
entity-manager-factory-ref="emf"
transaction-manager-ref="transactionManager"/>
<context:component-scan base-package="com.apress.prospring4.chll"/>
</beans>

.
Spring.

task
Spring, task

TaskScheduler, Spring.
11. Spring 521
task .
11.8 t s k
namespace-app-context. xml.

11.8. r Spring, task


<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd">
<import resource="car-job-app-context.xml"/>
<task:scheduler id= "myScheduler" pool-size="lO"/>
<task:scheduled-tasks scheduler= "myScheduler">
<task:scheduled ref="carService" method="updateCarAgeJob"
fixed-delay="lOOOO"/>
</task:scheduled-tasks>
</beans>

,
. <task: scheduler>, Spring
ThreadPoolTaskScheduler, pool-size
, .
<task: scheduled-tasks> .
<task: scheduled> Spring (
carService) (
updateCarAgeJob () ).
fix e d - d e l ay Spring
PeriodicTrigger Trigger TaskScheduler.
11.9 .

11.9. Spring
package com.apress.prospring4.chll;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class ScheduleTaskSample {
pulic static void main (String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/task-namespace-app-context.xml");
ctx.refresh();
while (true) {
}
522 11. Spring

ScheduleTaskSample ; Application
Context .
, I :
<Car age update job started>
<Car age update--- License: LICENSE-1001 - Manufacturer:
Ford - Manufacture Date: 1980-07-2920::.000-04: - Age: 33>
<Car age update--- License: LICENSE-1002 - Manufacturer:
Toyota - Manufacture Date: 1992-12-2919::.000-05: - Age: 21>
<Car age update--- License: LICENSE-1003 - Manufacturer:
W - Manufacture Date: 2003-01-0519::.000-05: - Age: 11>
<Car age update job cornpleted successfully>
, age .
-
, cron.
11.8:
<task:scheduled ref= "carService" rnethod="updateCarAgeJob"
fixed-delay="lOOOO"/>
:
<task:scheduled ref="carService" rnethod= "updateCarAgeJob"
cron="O * * * * *"/>

ScheduleTaskSample , .


TaskScheduler
Spring . Spring
@Scheduled.
,
<task: annotation-driven> L- Spring.
task-annotation-app-context. xml
11.10.
11.10. Spring
<?xrnl version= "l.O" encoding="UTF-8"?>
<beans xrnlns= "http://www.springfrarnework.org/scherna/beans"
xrnlns:task="http://www.springfrarnework.org/scherna/task"
xrnlns:xsi="http://www.w3.org/2001/XMLScherna-instance"
xsi:schernaLocation="http://www.springfrarnework.org/scherna/beans
http://www.springfrarnework.org/scherna/beans/spring-beans.xsd
http://www.springfrarnework.org/scherna/task
http://www.springfrarnework.org/scherna/task/spring-task.xsd">
<irnport resource= "car-job-app-context.xrnl"/>

<task:scheduler id="rnyScheduler" pool-size="lO"/>


<task:annotation-driven scheduler="rnyScheduler"/>
</beans>
11. Spring 523
<task: annotation-driven>
, scheduler
myScheduler.
Spring,
@Scheduled .
11.11 updateCarAgeJob ()
CarServiceimpl.
11.11. updateCarAqeJob () CarServiceimpl
@Scheduled(fixedDelay=lOOOO)
puic void updateCarAgeJob()

11.12.
11.12.
package com.apress.prospring4.chll;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class ScheduleTaskAnnotationSample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/task-annotation-app-context.xml");
ctx.refresh();
while (true) {

,
task. @Scheduled,
(.. fixedDelay, fixedRate, cron).
.

Spring
Spring 3.0,
.
@Async.
, . 11.13
11.14 AsyncService AsyncServiceimpl.
11.1 . AsyncService
package com.apress.prospring4.chll;
import java.util.concurrent.Future;
pulic interface AsyncService {
void asyncTask();
Future<String> asyncWithReturn(String name);
524 11. Spring
11.14. AsyncServiceimpl
package com.apress.prospring4.chll;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
@Service ( "asyncService")
puic class AsyncServiceimpl implements AsyncService
final Logger logger = LoggerFactory.getLogger(AsyncServiceimpl.class);
@Async
@Override
puic void asyncTask()
logger.info("Start execution of async. task");
try {
Thread.sleep(lOOOO);
catch (Exception ) {
ex.printStackTrace();

logger.info("Complete execution of async. task");

@Async
@Override
puic Future<String> asyncWithReturn(String name) {
logger.info( 11 Start execution of async. task with return");
try {
Thread.sleep(SOOO);
catch (Exception ) {
ex.printStackTrace();

logger.info( 1 Complete execution of async. task with return 1


1 1
) ;

return new AsyncResult<String> ( Hello: 11 + name) ;


11

AsyncService . asyncTask() -
, .
asyncWithReturn() String
j ava. ut i l. concurrent. Future<V>.
asyncWithReturn() org.
springframework. scheduling. annotation. AsyncResul t<V>,
Future<V>
. J 1.15
Spring (async-app-context. xml).

11.15. Spring
<?xml version= 11 l.O" encoding= 11 UTF-8"?>
<beans xmlns= 11 http://www.springframework.org/schema/beans 11
11. Spring 525
xmlns:xsi="http://www.w3.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd">
<context:component-scan base-package="com.apress.prospring4.chll"/>
<task:annotation-driven />
</beans>

<task:annotation-driven /> 11.15


@As ync. 11.16.

11.16.
package com.apress.prospring4.chll;
import java.util.concurrent.Future;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class AsyncTaskSample {
puic static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/async-app-context.xml");
ctx.refresh();
AsyncService asyncService = ctx.getBean ( "asyncService", AsyncService.class);
for (int i = ; i < 5; i++) {
asyncService.asyncTask();

Future<String> resultl = asyncService.asyncWithReturn("Chris");


Future<String> result2 = asyncService.asyncWithReturn("John");
Future<String> result3 = asyncService.asyncWithReturn("Robert");
try {
Thread.sleep(6000);
System.out.println("Resultl: " + resultl.get());
System.out.println("Result2: " + result2.get());
System.out.println("Result3: " + result3.get());
catch (Exception ) {
ex.printStackTrace();

asyncTask () asyncWithReturn ()
, .
:
2014-03-13 12:40:06,474 INFO [com.apress.prospring4.chll.AsyncServiceimpl]
- <Start execution of async. task>
2014-03-13 12:40:06,474 INFO [com.apress.prospring4.chll.AsyncServiceimpl]
- <Start execution of async. task>
526 11. Spring
2014-03-13 12:40:06,475 INFO (com.apress.prospring4.chll.AsyncServiceimpl]
- <Start execution of async. task>
2014-03-13 12:40:06,475 INFO (com.apress.prospring4.chll.AsyncServiceimpl]
- <Start execution of async. task>
2014-03-13 12:40:06,475 INFO (com.apress.prospring4.chll.AsyncServiceimpl]
- <Start execution of async. task>
2014-03-13 12:40:06,475 INFO (com.apress.prospring4.chll.AsyncServiceimplJ
- <Start execution of async. task with return>
2014-03-13 12:40:06,475 INFO (com.apress.prospring4.chll.AsyncServiceimpl]
- <Start execution of async. task with return>
2014-03-13 12:40:06,475 INFO (com.apress.prospring4.chll.AsyncServiceimpl]
- <Start execution of async. task with return>
2014-03-13 12:40:11,477 INFO (com.apress.prospring4.chll.AsyncServiceimpl]
- <Complete execution of async. task with return>
2014-03-13 12:40:11,477 INFO (com.apress.prospring4.chll.AsyncServiceimpl]
- <Complete execution of async. task with return>
2014-03-13 12:40:11,477 INFO (com.apress.prospring4.chll.AsyncServiceimpl]
- <Complete execution of async. task with return>
Resultl: Hello: Chris
Result2: Hello: John
Result3: Hello: Robert
2014-03-13 12:40:16,477 INFO (com.apress.prospring4.chll.AsyncServiceimpl]
- <Complete execution of async. task>
2014-03-13 12:40:16,477 INFO (com.apress.prospring4.chll.AsyncServiceimpl]
- <Complete execution of async. task>
2014-03-13 12:40:16,477 INFO (com.apress.prospring4.chll.AsyncServiceimpl]
- <Complete execution of async. task>
2014-03-13 12:40:16,477 INFO (com.apress.prospring4.chll.AsyncServiceimpl]
- <Complete execution of async. task>
2014-03-13 12:40:16,477 INFO (com.apress.prospring4.chll.AsyncServiceimpl]
- <Complete execution of async. task>
, .

. , asyncTask () .

Spring
Spring 2.0,
TaskExecutor. TaskExecutor
, : , Jv
Run n ae. Spring
TaskExecutor, .
TaskExecutor http: //docs. spring.
io/spring/docs/4.0.2.RELEASE/java doc-api/org/springframework/
core/task/TaskExecutor.html.
TaskExecutor.
SimpleAsyncTaskExecutor. ;
.
SyncTaskExecutor. ,
.
11. Spring 527
SimpleThreadPool TaskExecutor. SimpleThreadPool
Quartz, ,
, Quartz
.
ThreadPoolTaskExecutor. TaskExecutor
ThreadPoolExecutor
TaskExecutor
Spring.
TaskExecutor ,
.
, TaskExecutor ,
, . ,
. TaskExecutor
SimpleAsyncTaskExecutor. ,
( 11.17).
11.17. TaskToExecute
package com.apress.prospring4.chll;
import org.springframework.core.task.TaskExecutor;
puic class TaskToExecute {
private TaskExecutor taskExecutor;
pulic void executeTask () {
for (int i=O; i < 10; i++) {
taskExecutor.execute(new Runnale()
@Override
puic void run() {
System.out.println("Hello from thread: "
+ Thread.currentThread() .getName());
}
}) ;

puic void setTaskExecutor(TaskExecutor taskExecutor)


this.taskExecutor = taskExecutor;

POJO,
TaskExecutor executeTask ().
executeTask () execute ()
TaskExecutor Runnae,
, .
(app-context. xml), 11.18.
11.18.
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
528 11. Spring
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="taskExecutorSample"
class="com.apress.prospring4.chll.TaskToExecute"
p:taskExecutor-ref="taskExecutor"/>
<bean id= "taskExecutor"
class="org.springframework.core.task.SimpleAsyncTaskExecutor"/>
</beans>

taskExecutor
SimpleAsyncTaskExecutor TaskExecutor.
TaskToExecute.
( 11.19).
11.19.
package com.apress.prospring4.chll;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class TaskExecutorSample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/app-context.xml");
ctx.refresh();
TaskToExecute taskToExecute = ctx.getBean(TaskToExecute.class);
taskToExecute.executeTask();

, :
Hello from thread: SimpleAsyncTaskExecutor-1
Hello from thread: SimpleAsyncTaskExecutor-3
Hello from thread: SimpleAsyncTaskExecutor-2
Hello from thread: SimpleAsyncTaskExecutor-5
Hello from thread: SimpleAsyncTaskExecutor-4
Hello from thread: SimpleAsyncTaskExecutor-6
Hello from thread: SimpleAsyncTaskExecutor-7
Hello from thread: SimpleAsyncTaskExecutor-8
Hello from thread: SimpleAsyncTaskExecutor-9
Hello from thread: SimpleAsyncTaskExecutor-10
, ( )
. ,
(SimpleAsyncTaskExecutor),
.

Sprig.
Spring TaskScheduler

. , Spring
.
Sprig TaskExecutor .
12


Spring

. , , , ;
,
.
, .

. ,
; - .
- -
,
.
, - .
, ,
,
(, Java, .NET ++).
-

.
,
.
Java
. (Java 1.)

RMI (Remote Method Invocation - ). J2EE
EJB
JMS. XML
XML , Java API RPC
XML (JAX-RPC), Java API - XML (JAX-RPC) ,
(, Hessian Burlap). Spring
,
530 12. Spring

- Spring (Spring invoker).


- (,
Ajax) ,
.
Java API - REST (JAX-RS),
.
, Comet HTMLS WebSocket. ,
.
, Sprig
( - Spring),
, (, RMI, EJB, JMS, Hessian, Burlap, JAX-RPC,
JAX-WS JAX-RS). ,
. ,
.
- Spring. ,
, Spring, - Spring
,
. , - Spring
,
.
JMS Spring. Java (Java
Messaging Service - JMS)
. , Sprig
JMS.
- REST Spring.
, - REST
,
-
, Ajax.
JAX-RS Spring MVC
, RestTemplate.
r .
AMQP Spring. Spring Advanced Message
Queuing Protocol (AMQP) Sing-
AMQP RabitMQ.
,
RPC.


JPA
. . 12.1
,
JPA 2 Hibernate . ,
Spring Data JPA.
12. Sprig 531
12. 1. Maven




org.springframework spring-context 4.0.2.RELEASE Spring
org.springframework spring-orm 4.0.2.RELEASE Sprig ORM
org.springframework spring-tx 4.0.2.RELEASE -
Spring
org.springframework spring-web 4.0.2.RELEASE - Spring
org.springframework spring-webmvc 4.0.2.RELEASE - Spring MVC
org.springframework. spring-data-jpa 1.5.0.RELEASE Spring Data JPA
data
org.springframework spring-oxm 4.0.2.RELEASE Spring
org.hibernate hibernate- 4.2.3.Final
entitymanager Hibernate JPA 2
org.hibernate.javax. hibernate- 1.0.0.Final l- JPA -
persistence jpa-2.1-api Hibernate
com.h2database h2 1.3.172 2 -
JDBC
joda-time joda-time 2.3 JodaTime - API-
,
-


,

Java. n-
Java 8
Spring
API-
javax.time.
-
-

org .jadira.usertype usertype.core 3.0.0.GA Jodaime -
Hibernate, -


com.google.guava guava 14.0.1 -

log4j log4j 1.2.17 -
Log4j
org.codehaus.castor castor-xrnl 1.3.3 -
Castor
532 12. Spring

. 12.1


com.fasterxml. jackson-core 2.3.2 Jackson
jackson.core
com.fasterxml. jackson- 2.3.2 Jackson
jackson.core dataind DataBind
org.springframework. spring- 3.2.1.RELEASE - Spring Security
security security-web
org.springframework. spring- 3.2.1.RELEASE
security security- Spring Security
config
org.apache. httpclient 4.3 Apache
httpcomponents HTTPClient


,
CONTACT .
12.1 (schema. sql).

12. 1.
DROP TABLE IF EXISTS CONTACT;
CREATE TABLE CONTACT (
ID INT NOT NULL AUTO INCREMENT
, FIRST_NAE VARCHAR(O) NOT NULL
, LAST_NAE VARCAR(40) NOT NULL
, BIRTH_DATE DATE
, VERSION INT NOT NULL DEFAULT
, UNIQUE UQ_CONTACT_l (FIRST_NAE, LAST_NAE)
, PRIMARY (ID)
) ;

, CONTACT
. 12.2
(test-data. sql).

12.2.
insert into contact (first_name, last_name, rth_date)
values ('Chris', 'Schaefer', '1981-05-03');
insert into contact (first_name, last_name, rth_date)
values ('Scott', 'Tiger', '1990-11-02');
insert into contact (first_name, last_name, rth_date)
values ('John', 'Smith', '1964-02-28');
12. Spring 533
ContactService
,
.
ContactService
JPA 2, Spring Data JPA Hibernate .
, Spring.
tactService

. ,
Contact, 12.3.
12.. Contact
package com.apress.prospring4.ch12;
import static javax.persistence.GenerationType.IDENTITY;
import java.io.Serializale;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Tale;
import javax.persistence.Version;
@Entity
@ (name = "contact")
pulic class Contact implements Serializae {
private Long id;
private int version;
private String firstName;
private String lastName;
private DateTime rthDate;
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "ID")
pulic Long getid() {
return id;

@Version
@Column(name = "VERSION")
pulic int getVersion() {
return version;

@Column(name = "FIRST_NAE")
puic String getFirstName()
return firstName;
534 12. Spring
@Column(name = "LAST_NAE")
puic String getLastName()
return lastName;

@Column(name = "BIRTH_DATE")
@ (type= "org. jadira.usertype. dateandtime. joda. PersistentDateTime")
puic DateTime getBirthDate() {
return birthDate;

puic void setid(Long id) {


this.id = id;

puic void setVersion(int version)


this.version = version;

pulic void setFirstName(String firstName) {


this.firstName = firstName;

puic void setLastName(String lastName)


this.lastName = lastName;

puic void setBirthDate(DateTime birthDate)


this.birthDate = birthDate;

@Override
pulic String toString()
return "Contact - Id: " + id + ", First name: " + firstName
+ ", Last name: " + lastName + ", Birthday: " + irthDate;

, JPA.
DateTime Joda-lime birthDate.
, ; 12.4
ContactService , .
12.4. ContactService
package com.apress.prospring4.chl2;
import java.util.List;
puic interface ContactService
List<Contact> findAll();
List<Contact> findByFirstName(String firstName);
Contact findByid(Long id);
Contact save(Contact contact);
void delete(Contact contact);

.
Spring Data JPA, ContactRepository
( 12.5).
12. Spring 535
12.5. ContactReposi tory
package com.apress.prospring4.chl2;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
pulic interface ContactRepository extends CrudRepository<Contact, Long> {
List<Contact> findByFirstName(String firstName);

CrudRepository<T, ID extends Serializae>


ContactService findByFirstName ().
12.6 ContactService.

12.6. ContactServiceimpl
package com.apress.prospring4.chl2;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.Lists;
@Service("contactService")
@Repository
@Transactional
pulic class ContactServiceimpl implements ContactService
@Autowired
private ContactRepository contactRepository;
@Override
@Transactional(readOnly=true)
puic List<Contact> findAll()
return Lists.newArrayList(contactRepository.findAll());

@Override
@Transactional(readOnly=true)
pulic List<Contact> findByFirstName(String firstName) {
return contactRepository.findByFirstName(firstName);

@Override
@Transactional(readOnly=true)
puic Contact findyid(Long id)
return contactRepository.findOne(id);

@Override
puic Contact save(Contact contact) {
return contactRepository.save(contact);

@Override
puic void delete(Contact contact)
contactRepository.delete(contact);
536 12. Spring
,
ApplicationContext -,
.


JPA
datasource-tx-jpa. xml, 12.7.
12.7. datasource-tx-jpa.nl
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdc="http://www.springframework.org/schema/jdbc"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:tx= "http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdc
http://www.springframework.org/schema/jdc/spring-jdc.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<jdbc:emedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:META-INF/config/schema.sql"/>
<jdbc:script location="classpath:META-INF/config/test-data.sql"/>
</jdbc:embedded-database>
<bean id="transactionManager" class="org.springframework.orm.jpa.
JpaTransactionManager">
<property name="entityManagerFactory" ref="emf"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
/>
</property>
<property name="packagesToScan" value="com.apress.prospring4.chl2"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect
</prop>
<prop key="hibernate.max fetch depth"></prop>
<prop key="hibernate.jdc.fetch_size">SO</prop>
<prop key="hibernate.jdbc.batch_size">lO</prop>
12. Spring 537
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<context:annotation-config/>
<jpa:repositories base-package="com.apress.prospring4.chl2"
entity-manager-factory-ref="emf"
transaction-manager-ref="transactionManager"/>
</beans>

- Spring MVC,
WebApplicationContext.
Spring MVC /src/main/webapp/WEB-INF/spring/
root-context. xml.
12.8.
12.8. root-context.xml
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<import resource="classpath:ETA-INF/spring/datasource-tx-jpa.xml" />
<context:component-scan base-package="com.apress.prospring4.chl2" />
</beans>

context.
datasource-tx-jpa. xml WebApplicationContext
, , Spring
Spring.
.

- Spring
, ,
Spring, -
Sprig.
WebApplicationContext .
.


, root-context. xml
, 12.9.
538 12. Spring
12.9.
- Spring
<bean name="contactExporter"
class="org.springframework.remoting.httpinvoker.HttpinvokerServiceExporter">
<property name="service" ref="contactService" />
<property name="serviceinterface"
value="com.apress.prospring4.ch12.ContactService" />
</bean>

contactExporter HttpinvokerService
Exporter, Spring
-. . ,
service, , .
contactService. , serviceinterface,
, com. apress. prospring4. chl2. ContactService.

- (/src/main/webapp/WEB-INF/web. xml).
web. xml 12.1 .

12.1 . -
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app__O.xsd"
version=".0">
<display-name>Spring Invoker Sample</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>contactExporter</servlet-name>
<servlet-class>
org.springframework.web.context.support.HttpRequestHandlerServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>contactExporter</servlet-name>
<url-pattern>/remoting/ContactService</url-pattern>
</servlet-mapping>
</web-app>
12. Spring 539
12.10 HttpRequestHandlerServlet,
Spring,
WebApplicationContext. ,
(contactExporter) (.
12.9; contactExporter).
URL /remoting/ContactService - (..
http://localhost:8080/chl2/remoting/ContactService) .
.
Spring MVC, WR-
. - ,
Tomcat, Tomcat, I D-,
Tomcat,
, Maven.
,
,
ID-. , ,
Maven .
.
- ,
. URL
ContactService(http://localhost:8080/chl2/remoting/ContactService)
500, , ..
, .


- Spring .
ApplicationContext, 12.11
(http-invoker-app-context. xml).
12.11. ApplicationContext -
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="remoteContactService"
class="org.springframework.remoting.httpinvoker.HttpinvokerProxyFactoryBean">
<property name="serviceUrl"
value="http://localhost:8080/ch12/remoting/ContactService" />
<property name="serviceinterface"
value="com.apress.prospring4.ch12.ContactService" />
</bean>
</beans>

12.11 Httpinvoker
ProxyFactoryBean .
540 12. Spring
serviceUrl ,
http: / /localhost: 8080/chl2/remoting/ContactService.
serviceinterface (.. ContactService).
, ContactService
Contact
.
12.12 .

12.12. HttpinvokerClientSample

package com.apress.prospring4.chl2;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
pulic class HttpinvokerClientSample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/http-invoker-app-context.xml");
ctx.refresh();
ContactService contactService =
ctx.getBean("remoteContactService", ContactService.class);
System.out.println("Finding all contacts");
List<Contact> contacts = contactService.findAll();
listContacts(contacts);
System.out.println("Finding contact with first name equals Chris");
contacts = contactService.findByFirstName("Chris");
listContacts(contacts);

private static void listContacts(List<Contact> contacts)


for (Contact contact: contacts) {
System.out.println(contact);

System.out.println("");

12.12 ,
Spring. ApplicationContext,
contactService. ,
. :
Finding all contacts
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday:
1981-05-0220::.000-04:
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday:
1990-11-0119::.000-05:
Contact - Id: 3, First name: John, Last name: Smith, Birthday:
1964-02-2719::.000-05:
Finding contact with first name equals Chris
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday:
1981-05-0220::.000-04:
12. Spring 541
, findAll () findByFirstName ()
.

JMS Spring
,
( MQ) -
.
(message queue - MQ) ,
.
Java MQ
JMS. MQ ,
, .
.
.
"-". ,
MQ
.
. "
-".
. , MQ
, .
, ,
(, ).
JMS MQ
. MQ
. JMS 1.1
l-,
l-
. "-"
,
. JMS
MQ.
Apache ActiveMQ
(acti vemq. apache. org) - MQ .
Maven,
. 12.2. .
12.2. Maven JMS ActiveMQ



org.springframework spring-jms 4.0.2.RELEASE Spring JMS
org.apache.activemq activemq-core 5.7.0 Jv-
ActiveMQ
javax.jms jms 1.1 l- JMS 1.1
542 12. Spring

ActiveMQ
ActiveMQ
. Tomcat , ActiveMQ

( Maven). ,
Tomcat. ,
- ActiveMQ (http: //
acti vemq. apache. org/download. html). ,
ActiveMQ ,
, .

JMS Spring
,
j avax. jms. MessageListener onMessage ().
12.13.
12.1 . JMS
package com.apress.prospring4.chl2;
import javax.jms.JSException;
import javax. jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
puic class SimpleMessageListener implements MessageListener
private static final Logger logger =
LoggerFactory.getLogger(SimpleMessageListener.class);
@Override
puic void onMessage(Message message) {
TextMessage textMessage = (TextMessage) message;
try {
logger. info( "Message received: " + textMessage.getText());
catch (JSException ) {
logger.error("JS error", );

onMessage ()
j avax. jms. Message.
j avax. jms. TextMessage,
TextMessage. getText () .
JEE.

ApplicationContext. 12.14
jms-listener-app-context. xml.
12. Spring 543
12.14. JMS
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd">
<bean id="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory"
p:brokerURL="tcp://localhost:61616" />
<bean id="simpleMessageListener"
class="com.apress.prospring4.chl2.SimpleMessageListener"/>
<jms:listener-container container-type="default"
connection-factory="connectionFactory" acknowledge="auto">
<jms:listener destination="prospring4"
ref="simpleMessageListener" method="onMessage" />
</jms:listener-container>
</beans>

javax. jms. ConnectionFactory,


Jv- ActiveMQ ( ActiveMQConnectionFactory).
SimpleMessageListener. ,
<jms: listener-container>,
jms Sprig,
(. . prospring4), ,
.
, prospring4.

JMS Spring
,
JMS Spring. org.
springframework. jms. core. JmsTemplate. ,
MessageSender SimpleMessageSender.
12.15 12.16.
12.15. MessageSender
package com.apress.prospring4.chl2;
pulic interface MessageSender {
void sendMessage(String message);

12.16. SimpleessageSender
package com.apress.prospring4.chl2;
import javax.jms.JSException;
544 12. Spring
import javax.jms.Message;
import javax.jms.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;
@Component("messageSender")
puic class SimpleMessageSender implements MessageSender
@Autowired
private JmsTemplate jmsTemplate;
@Override
puic void sendessage(final String message)
this.jmsTemplate.send(new MessageCreator() {
@Override
pulic Message createMessage(Session session)
throws JSException {
return session.createTextMessage(message);
)
)) ;

, JmsTemplate.
sendMessage () JmsTemplate. send ()
org. springframework. jms. core.
MessageCreator.
MessageCreator createMessage (),
TextMessage, ActiveMQ.
12.17 Spring J MS
(jms-sender-app-context. xml).
12.17. r Spring
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory"
p:brokerURL= "tcp://localhost:61616" />
<bean id="jmsTemplate" class= "org.springframework.jms.core.JmsTemplate">
<constructor-arg name= "connectionFactory" ref= "connectionFactory"/>
<property name= "defaultDestinationName" value= "prospring4"/>
</bean>
<context:component-scan base-package= "com.apress.prospring4.chl2"/>
</beans>
12. Sprig 545
, , connectionFactory. ,
JmsTemplate connectionFactory
defaultDestinationName, prospring4.
, JMS
. 12.18
.

12.18.
package com.apress.prospring4.chl2;
import org.springframework.context.support.GenericXmlApplicationContext;
puic class JmsSample {
puic static void main(String [] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/jms-sender-app-context.xml",
"classpath:META-INF/spring/jms-listener-app-context.xml");
ctx.refresh();
MessageSender messageSender =
ctx.getBean("messageSender", MessageSender.class);
for(int i=O; i < 10; i++) {
messageSender.sendessage("Test message: " + i) ;

. .
JmsListenerSample ,
:
INFO ss.prospring4.chl2.SimpleMessageListener: 19 - Message received:
Test message:
INFO ss.prospring4.chl2.SimpleMessageListener: 19 - Message received:
Test message: 1
INFO ss.prospring4.chl2.SimpleMessageListener: 19 - Message received:
Test message: 2
INFO ss.prospring4.chl2.SimpleMessageListener: 19 - Message received:
Test message: 3
INFO ss.prospring4.chl2.SimpleMessageListener: 19 - Message received:
Test message: 4
INFO ss.prospring4.ch12.SimpleMessageListener: 19 - Message received:
Test message: 5
INFO ss.prospring4.chl2.SimpleMessageListener: 19 - Message received:
Test message: 6
INFO ss.prospring4.chl2.SimpleMessageListener: 19 - Message received:
Test message: 7
INFO ss.prospring4.chl2.SimpleMessageListener: 19 - Message received:
Test message:
INFO ss.prospring4.chl2.SimpleMessageListener: 19 - Message received:
Test message: 9
546 12. Spring
, , L
- (, ,
). ,
Spring JMS .
JMS.
JEE.

JMS 2.0
Spring Framework 4.0 JMS 2.0.
JMS 2.0 - JR- JMS 2.0
JMS 1..
ActiveMQ JMS 2.0,
HometQ ( JMS 2.0,
2.4.0.Final)
. HornetQ
; HornetQ http: //docs.jboss.org/
hornetq/2.4.0.Final /docs/quickstart-guide/html/index.html.
JMS 1.1 / ActiveMQ,
, HornetQ.
JMS 2.0, JMS 1.1, . 12.3.
12.. Maven JMS 2.0



org.springfrarnework spring-jms 4.0.2.RELEASE SpringJMS
org. slf4j slf4j-log4jl2 1.7.6 log4j

SLF4J
javax. jms javax.jms-api 2.0 l- JMS 2.0
org.hornetq hornet-jms-client 2.4.0.Final l
HornetQ JMS

HometQ JMS
. , HometQ.
conf ig /stand-alone/non-cl ustered/hornetq-jms.xml,
, 12.19.
12.19. HornetQ
<configuration xmlns= "urn:hornetq"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation= "urn:hornetq /schema/hornetq-jms.xsd">
<queue name="p rospring4">
<entry name="/queue/prosp ring4"/>
</queue>
</configuration>
12. Spring 547
HometQ run. sh (
) ,
.
HometQ ActiveMQ. ,
Spring (jms-sender-app-context. xml),
12.20.
12.20. Spring HornetQ
<?xrnl version= "l.O" encoding= "UTF-8"?>
<beans xrnlns= "http://www.springfrarnework.org/schema/beans"
xrnlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context= "http://www.springfrarnework.org/schema/context"
xsi:schemaLocation="http://www.springfrarnework.org/schema/beans
http://www.springfrarnework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id= "connectionFactory"
class="org.hornetq.jms.client.HornetQJSConnectionFactory">
<constructor-arg narne= "ha" value="false" />
<constructor-arg>
<bean class ="org.hornetq.api.core.TransportConfiguration">
<constructor-arg
value="org.hornetq.core.remoting.impl.netty.NettyConnectorFactory"
/>
<constructor-arg>
<map key-type="java.lang.String" value-type="java.lang.Object">
<entry key= "host" value="l27.0.0.l"/>
<entry key= "port" value="5445"/>
</map>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
<bean id="jmsTemplate" class="org. springframework. jms.core. JmsTemplate">
<constructor-arg narne= "connectionFactory" ref="connectionFactory"/>
<property name="defaultDestinationNarne" value="prospring4"/>
</bean>
<context:component-scan base-package= "com.apress.prospring4.chl2"/>
</beans>

connectionFactory HometQ.
, URL
.
Spring (jms-listener-app-context. xml) 12.21.
12.21. HornetQ
<?xml version="l.0" encoding= "UTF-8"?>
<beans xrnlns= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
548 12. Spring
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd">
<bean id="connectionFactory"
class="org.hornetq.jms.client.HornetQJSConnectionFactory">
<constructor-arg name="ha" value="false" />
<constructor-arg>
<bean class="org.hornetq.api.core.TransportConfiguration">
<constructor-arg
value="org.hornetq.core.remoting.impl.netty.NettyConnectorFactory"
/>
<constructor-arg>
<map key-type="java.lang.String" value-type="java.lang.Object">
<entry key="host" value="l27.0.0.1"/>
<entry key= "port" value="5445"/>
</map>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
<bean id="simpleMessageListener"
class="com.apress.prospring4.chl2.SimpleMessageListener"/>
<jms:listener-container container-type="default"
connection-factory="connectionFactory"
acknowledge="auto">
<jms:listener destination="prospring4" ref="simpleMessageListener"
method="onMessage" />
</jms:listener-container>
</beans>

, SimpleMessageSender,
JmsTemplate ( 12.22). (Delivery
Delay) JmsTemplate, JMS 2.0.
,
, JMS
. JR- JMS 2.0, JMS 1.,
Spring ,
JMS 2.0.
12.22. JMS 2.0
package com.apress.prospring4.chl2;
import javax.jms.JSException;
import javax.jms.Message;
import javax.jms.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;
12. Spring 549
@Component("messageSender")
puic class SimpleMessageSender implements MessageSender
@Autowired
private JmsTemplate jmsTemplate;
@Override
puic void sendessage(final String message)
jmsTemplate.setDeliveryDelay(5000L);
this.jmsTemplate.send(new MessageCreator() {
@Override
puic Message createMessage(Session session)
throws JSException {
return session.createTextMessage(message);
}
});

, ,
.

- REST Spring
- REST (RESTful-WS) , ,
. - REST
,
- Ajax.
- REST .
. - REST
. URL -
. , URL http: //somedomain.com/restful/customer/1
- GET ,
, 1.
. - REST
- SOAP,
, .
REST ,
-.
. - REST
( HTTPS),

.
- REST
Spring Spring .
550 12. Spring

- REST
REST REpresentational State Transfer (
). REST ,
11 .

.

(Uniform Resource ldentifier - URI).
, URL www.somedomain.com/api/contact/1 - URI,
,
1. I ,
404, , - .
www.somedomain.com/api/contacts -
URI, , .

, . 12.4.
12.4.

GET
HEAD GET, ;

POST
PUT
DELETE
OPTIONS -

- REST Ajax and REST Recipes:


Proem-Solution Approach (Apress, 2006 r.).


,
. 12.5. .
12.5. Maven - REST




org.springframework spring-oxm 4.0.2.RELEASE
Spring XML
org.codehaus.jackson jackson 1.9.13 Jackson
mapper-lgpl JSON

JSON
12. Spring 551
. 12.5




org.codehaus.castor castor-xml 1.3.3 Ca stor
XML,


L-
org.springframework. security spring 3.2.1.RELEASE Spring
security-core Security
org.springframework. security spring 3.2.1.RELEASE - Spring
security-web Security
- REST
org. springframework.security spring 3.2.1.RELEASE
security-config Spring Security
org.apache.httpcomponents httpclient 4.3 Apache
Components.


- REST

- REST
RESTful-WS
, -
URL . - REST
, , .

. Sprig MVC.
ContactController com. apress. prospring4. chl2.
URL, -,
. 12.6. URL http: / /localhost: 8080/
chl2/restful. XML JSON.
Accept
-.
12.6. -: REST

URL -

/contact/listdata GET listData ( ... )
/contact/{id} GET findContactByid( ... )

/contact POST create( ... )
/contact/{id} PUT - update( ... )

/contact DELETE delete( ... )

552 12. Spring

Spring MVC - REST


, Spring MVC ,
, - REST ,
.
ContactService, - Spring.
- Contacts.
12.23.
12.23. contacts
package com.apress.prospring4.chl2;
import java.io.Serializae;
import java.util.List;
puic class Contacts implements Serializae
private List<Contact> contacts;
puic Contacts() {
}
puic Contacts(List<Contact> contacts)
this.contacts = contacts;

puic List<Contact> getContacts()


return contacts;

puic void setContacts(List<Contact> contacts)


this.contacts = contacts;

Contacts ,
Contact.
( listData () ContactController) XML
JSON.

Castor XML
XML
Castor XML (http: / /castor. codehaus. org).

POJO L,
L-. (oxm-mapping. xml)
12.24.

12.24. Castor XML


<mapping>
<class name="com.apress.prospring4.ch12.Contacts">
<field name= "contacts" type="com.apress.prospring4.ch12.Contact"
collection="arraylist">
<bind-xml name="contact" />
</field>
</class>
12. Spring 553
<class name="com.apress.prospring4.ch12.Contact" identity="id">
<map-to xml="contact" />
<field name="id" type="long">
<ind-xml name="id" node="element"/>
</field>
<field name="firstName" type="string">
<ind-xml name="firstName" node="element" />
</field>
<field name="lastName" type="string">
<ind-xml name="lastName" node="element" />
</field>
<field name="birthDate" type="string" handler="dateHandler">
<ind-xml name="irthDate" node="element" />
</field>
<field name="version" type="integer">
<ind-xml name="version" node="element" />
</field>
</class>
<field-handler name="dateHandler"
class="com.apress.prospring4.ch12.DateTimeFieldHandler">
<param name="date-format" value="yyyy--dd" />
</field-handler>
</mapping>

. <class>
Contacts, contacts ( Contact)
<bind-xml name ="contact" />.
Contact ( <map-to xml="contact" />
<class>). ,
DateTime, Joda-ime ( irthDate Contact),
Castor XML.
12.25.

12.25. DateTime Castor XML


package com.apress.prospring4.chl2;
import java.util.Properties;
import org.exolab.castor.mapping.GeneralizedFieldHandler;
import org.exolab.castor.mapping.ValidityException;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
pulic class DateTimeFieldHandler extends GeneralizedFieldHandler
private static String dateFormatPattern;
@Override
puic void setConfiguration(Properties config) throws ValidityException
{
dateFormatPattern = config.getProperty("date-format");
554 12. Spring
@Override
puic Object convertUponGet(Object value)
DateTime dateTime = (DateTime) value;
return format(dateTime);

@Override
pulic Object convertUponSet(Object value)
String dateTimeString = (String) value;
return parse(dateTimeString);

@Override
pulic Class<DateTime> getFieldType()
return DateTime.class;

protected static String format(final DateTime dateTime) {


String dateTimeString = "";
if (dateTime != null) {
DateTimeFormatter dateTimeFormatter =
DateTimeFormat.forPattern(dateFormatPattern);
dateTimeString = dateTimeFormatter.print(dateTime);

return dateTimeString;

protected static DateTime parse(final String dateTimeString)


DateTime dateTime = new DateTime();
if (dateTimeString != null) {
DateTimeFormatter dateTimeFormatter =
DateTimeFormat.forPattern(dateFormatPattern);
dateTime = dateTimeFormatter.parseDateTime(dateTimeString);

return dateTime;

org. exolab. castor.m apping. GeneralizedField


Handler Castor XML convertUponGet (), convert
UponSet () getFieldType ().
DateTime String, Castor XML.
Castor XML.
(castor.properties) 12.26.

12.26. castor .properties


org.exolab.castor.indent=true

Castor XML
L- , .
12. Spring 555
ContactControl.l.er
, ContactController.
12.27 ContactController,
. 12.6.
12.27. ContactController

package com.apress.prospring4.ch12;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariale;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping(value="/contact")
puic class ContactController {
final Logger logger = LoggerFactory.getLogger(ContactController.class);
@Autowired
private ContactService contactService;
@RequestMapping(value = "/listdata", method = RequestMethod.GET)
@ResponseBody
puic Contacts listData() {
return new Contacts(contactService.findAll());

@RequestMapping(value="/{id}", method=RequestMethod.GET)
@ResponseBody
pulic Contact findContactByid(@PathVariae Long id) {
return contactService.findByid(id);

@RequestMapping(value="/", method=RequestMethod.POST)
@ResponseBody
puic Contact create(@RequestBody Contact contact)
logger.info("Creating contact: " + contact);
contactService.save(contact);
logger.info("Contact created successfully with info: " + contact);
return contact;

@RequestMapping(value="/{id}", method=RequestMethod.PUT)
@ResponseBody
puic void update(@RequestBody Contact contact,
@PathVariale Long id) {
logger.info("Updating contact: " + contact);
contactService.save(contact);
logger.info("Contact updated successfully with info: " + contact);
556 12. Spring
@RequestMapping(value="/{id}", method=RequestMethod.DELETE)
@ResponseBody
pulic void delete(@PathVariae Long id) {
logger.info("Deleting contact with id: " + id);
Contact contact = contactService.findByid(id);
contactService.delete(contact);
logger.info("Contact deleted successfully");

, 12.27.
@Controller, ,
Spring MVC.
@RequestMapping (value= " /contact") ,
URL -.
URL,
http: //localhost: 8080/chl2/contact.
ContactService
.
@Requ e s t M a p pin g
ContactController URL
, . ,
listData () URL http: //localhost: 8080/chl2/
contact/listdata - GET. update ()
URL http: //localhost: 8080/ch12/contact/ { id} -
PUT.
@ResponseBody .

.
, (, findContactByid () ),
@PathVariae.
Sprig URL (
, http: / /localhost: 8080/ch12/contact/l) id
findContactByid (). , id Long,
Spring
String Long.
create () update () Contact
@RequestBody. Spring
- Contact.

HttpMessageConverter<Object> ( org. springframework.
http. converter) ,
.
12. Spring 557

REST
Spring
. DispatcherServlet (
org. springframework. web. servlet) Sprig
REST ContactController.
, 12.28
- (src/main/webapp/WEB-INF/web. xml).
12.28. - REST
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app__O.xsd"
version=".O">
<display-name>Spring REST Sample</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>restful</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/rest-context.xml</param-value>
</init-param>
<load-on-startup>l</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>restful</servlet-name>
<url-pattern>/restful/*</url-pattern>
</servlet-mapping>
</web-app>

restful, DispatcherServlet
( DispatcherServlet 16). Spring V
DispatchServlet WebApplicationContext
( , root-context. xml,
WebApplicationContext,
WebApplicationContext ).
<servlet-mapping> - (, Tomcat),
URL /restful/* (, http: //localhost: 8080/ch12/
restful/contact) restful.
12.28, restful ,
WebApplicationContext DispatcherServlet
rest-context. xml.
12.29.
558 12. Spring
12.29. WepplicationContext - REST
<?xml version="l.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.
MappingJackson2HttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.
MarshallingHttpMessageConverter">
<property name="marshaller" ref="castorMarshaller"/>
<property name="unmarshaller" ref="castorMarshaller"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<context:component-scan base-package="com.apress.prospring4.chl2"/>
<bean id="castorMarshaller"
class="org.springframework.oxm.castor.CastorMarshaller">
<property name="mappingLocation"
value="classpath:META-INF/spring/oxm-mapping.xml"/>
</bean>
</beans>

, 12.26.
<mvc: annotation-driven>
Spring (.. @Controller),
Spring. ,
JSR-349.
<mvc: annotation-driven> <mvc: message-converters>
- HttpMessageConverter,
.
, <mvc: message-converters> Spring 3.1.
JSON XML,
. , MappingJackson2HttpMessage
Converter , Jackson JSON (http: //jac kson.
codehaus. org). , MarshallingHttpMessageConverter,
spring-oxm /
XML. MarshallingHttpMessageConverter
,
Castor L.
12. Spring 559
castorMarshaller Spring-acc org. springframework.
oxm. castor. CastorMarshaller, Castor,
, Castor.
<context: component-scan> Spring
.
, .
WR-, -, ,
I D- STS, Tomcat.

curl - REST
- RES.
curl (htt p: //curl.
haxx. se) -
URL. r -
.
, ,
Windows Unix/Linux, -
REST , 12.30.
12.30. curl - REST JSON
curl -v - "Accept: application/json"
http://localhost:8080/chl2/restful/contact/listdata

"contacts": (
"id": 1,
"version": ,
"firstName": "Chris",
"lastName": "Schaefer",
"irthDate": {
"year": 1981,
"dayOfMonth": 2,
"dayOfWeek": 6,
"era": 1,
"dayOfYear": 122,
"weekyear": 1981,
"weekOfWeekyear": 18,
"monthOfYear": 5,
"yearOfEra": 1981,
"yearOfCentury": 81,
"centuryOfEra": 19,
"millisOfSecond": ,
"millisOfDay": 72000000,
"secondOfMinute": ,
"secondOfDay": 72000,
"minuteOfHour": ,
"minuteOfDay": 1200,
"hourOfDay": 20,
"chronology": {
"zone": {
560 12. Spring
"fixed": false,
"uncachedZone":
"fixed": false,
"h": true,
"id": "Arnerica\/New-York"
},
"id": "Arnerica\/New York"
},
"zone": {
"fixed": false,
"uncachedZone":
"fixed": false,
"h": true,
"id": "Arnerica\/New York"
},
"id": "Arnerica\/New York"
},
"millis": 357696000000,
"afterNow": false,
"beforeNow": true,
"equalNow": false
}
},
11 id": 2,
"version": ,
"firstName": "Scott",
"lastName": "Tiger",
"irthDate": {
"year": 1990,
"dayOfMonth": 1,
"dayOfWeek": 4,
"era": 1,
"dayOfYear": 305,
"weekyear": 1990,
"weekOfWeekyear": 44,
"monthOfYear": 11,
"yearOfEra": 1990,
"yearOfCentury": 90,
"centuryOfEra": 19,
"millisOfSecond": ,
"millisOfDay": 68400000,
"secondOfMinute": ,
"secondOfDay": 68400,
"minuteOfHour": ,
"minuteOfDay": 1140,
"hourOfDay": 19,
"chronology": {
"zone": {
"fixed": false,
"uncachedZone":
"fixed": false,
"h": true,
"id": "Arnerica\/New York"
},
12. Sprig 561
"id": "America\/New York"
}
},
"zone": {
"fixed": false,
"uncachedZone":
"fixed": false,
"h": true,
"id": "America\/New-York"
},
"id": "America\/New York"
},
"millis": 657504000000,
"afterNow": false,
"beforeNow": true,
"equalNow": false
}
},
{
"id": 3,
"version": ,
"firstName": "John",
"lastName": "Smith",
"birthDate": {
"year": 1964,
"dayOfMonth": 27,
"dayOfWeek": 4,
"era": 1,
"dayOfYear": 58,
"weekyear": 1964,
"weekOfWeekyear": 9,
"monthOfYear": 2,
"yearOfEra": 1964,
"yearOfCentury": 64,
"centuryOfEra": 19,
"millisOfSecond": ,
"millisOfDay": 68400000,
"secondOfMinute": ,
"secondOfDay": 68400,
"minuteOfHour": ,
"minuteOfDay": 1140,
"hourOfDay": 19,
"chronology": {
"zone": {
"fixed": false,
"uncachedZone":
"fixed": false,
"h": true,
"id": "America\/New York"
},
"id": "America\/New York"
}
) '
"zone": {
"fixed": false,
562 12. Spring
"uncachedZone": {
"fixed": false,
"h": true,
"id": "America\/New York"
},
"id": "America\/New York"
},
"millis": -184377600000,
"afterNow": false,
"beforeNow": true,
"equalNow": false

- - RES;
listData () ContactController
. - Accept ,
, JSON.
JSON
. XML;
12.JI.
12.31. curl - REST XML
curl -v - "Accept: application/xml"
http://localhost:8080/ch12/restful/contact/listdata
<?xml version="l.O" encoding="UTF-8"?>
<contacts>
<contact>
<id>l</id>
<firstName>Chris</firstName>
<lastName>Schaefer</lastName>
<birthDate>1981-05-02</birthDate>
<version>O</version>
</contact>
<contact>
<id>2</id>
<firstName>Scott</firstName>
<lastName>Tiger</lastName>
<birthDate>1990-11-01</birthDate>
<version>O</version>
</contact>
<contact>
<id></id>
<firstName>John</firstName>
<lastName>Smith</lastName>
<birthDate>1964-02-27</birthDate>
<version>O</version>
</contact>
</contacts>
12. Spring 563
, 12.30
. Accept JSON XML.
XML.
HttpMessageConverter WebApplicationContext RES;
Spring
Accept, - ,
-.

RestTemplate
- REST
Sring- RestTernplate,
- RES. ,
.
, ApplicationContext
Spring-acca RestTernplate, 12.32 (restful
client-app-context. xrnl).
12.32. restful-client-app-context.xml
<?xrnl version= "l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="restTemplate"
class= "org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.xrnl.MarshallingHttpMessageConverter">
<property name= "marshaller" ref="castorMarshaller"/>
<property name= "unmarshaller" ref="castorMarshaller"/>
<property name= "supportedediaTypes">
<list>
<bean class="org.springframework.http.MediaType">
<constructor-arg index="O" value="application"/>
<constructor-arg index="l" value="xml"/>
</bean>
</list>
</property>
</bean>
</list>
</property>
</bean>
<bean id="castorMarshaller"
class= "org.springframework.oxm.castor.CastorMarshaller">
<property name="mappingLocation"
value= "classpath:META-INF/spring/oxm-mapping.xml"/>
</bean>
</beans>
564 12. Spring

restTemplate RestTemplate.
Castor messageConverters
MarshallingHttpMessageConverter,
, .

. , restTemplate
MarshallingHttpMessageConverter supportedMediaTypes
MediaType,
XML. XML
, Castor XML
POJO L.
.
12.33.
12.33. RestTemplate
package com.apress.prospring4.ch12;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.web.client.RestTemplate;
puic class RestfulClientSample {
private static final String URL_GET_ALL_CONTACTS =
"http://localhost:8080/ch12/restful/contact/listdata";
private static final String URL_GET_CONTACT_BY_ID =
"http://localhost:8080/ch12/restful/contact/(id}";
private static final String URL_CREATE_CONTACT =
"http://localhost:8080/chl2/restful/contact/";
private static final String URL_UPDATE_CONTACT =
"http://localhost:8080/chl2/restful/contact/{id}";
private static final String URL_DELETE_CONTACT =
"http://localhost:8080/ch12/restful/contact/{id}";
pulic static void main(String (] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/restful-client-app-context.xml");
ctx.refresh();
Contact contact;
RestTemplate restTemplate = ctx.getBean("restTemplate", RestTemplate.class);
System.out.println("Testing retrieve all contacts:");
Contacts contacts =
restTemplate.getForObject(URL_GET_ALL_CONTACTS, Contacts.class);
listContacts(contacts);

private static void listContacts(Contacts contacts)


for (Contact contact: contacts.getContacts())
System.out.println(contact);

System.out.println("");
12. Spring 565
URL ,
. main ()
RestTemplate RestTemplate. getForObject () (
- GET), URL
- Contacts, .
, .
:
Testing retrieve all contacts:
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday:
1981-05-0200::.000-04:
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday:
1990-11-0lT00:00:00.000-05:00
Contact - Id: 3, First name: John, Last name: Smith, Birthday:
1964-02-27::.000-05:
, MarshallingHttpMessageConverter,
RestTemplate, POJO.
.
12.34 main () RestfulClientSample.
12.34. RestTemplate

System.out.println("Testing retrieve contact id :");
contact = restTemplate.getForObject(URL_GET_CONTACT_BY_ID, Contact.class, 1);
System.out.println(contact);
System.out.println("");

12.34 RestTemplate.
getForObject (),
U RL ( { id} URL_GET
CONTACT BY_ID). URL ,
Map<String, Object>
.
URL.
( ):
Testing retrieve contact id :
Contact - Id: 1, First name: Chris, Last name: Schaefer, Birthday:
1981-05-02::.-04:
, .
. 12.35 ma in ()
RestfulClientSample.
12.35. RestTemplate
contact = restTemplate.getForObject(URL_UPDATE_CONTACT, Contact.class, 1);
contact.setFirstName("John Doe");
System.out.println("Testing update contact id :");
restTemplate.put(URL_UPDATE_CONTACT, contact, 1);
System. out.println("Contact update successfully: " + contact);
System.out.println("");
566 12. Spring
, .
RestTemplate. put (),
- PUT, URL ,
.
( ):
Testing update contact id :
Contact update successfully: Contact - Id: l, First name: John Doe,
Last name: Schaefer, Birthday: 1981-05-02::.-04:
.
12.36 main () RestfulClientSample.
12.36. RestTemplate
restTemplate.delete(URL_DELETE_CONTACT, 1);
System.out.println("Testing delete contact id :");
contacts = restTemplate.getForObject(URL_GET_ALL_CONTACTS, Contacts.class);
listContacts(contacts);

RestTemplate. delete (),


DELETE, URL .
.
( ):
Testing delete contact id :
Contact - Id: 2, First name: Scott, Last name: Tiger, Birthday:
1990-ll-OlT00:00:00.000-05:00
Contact - Id: 3, First name: John, Last name: Smith, Birthday:
1964-02-27::.000-05:
, 1 . ,
. 12.37
main () RestfulClientSample.
12.37. RestTemplate
System.out.println("Testing create contact :");
Contact contactNew = new Contact();
contactNew.setFirstName("James");
contactNew.setLastName("Gosling");
contactNew.setBirthDate(new DateTime());
contactNew =
restTemplate.postForObject(URL_CREATE_CONTACT, contactNew, Contact.class);
System. out. println( "Contact created success fully: " + contactNew);

, Contact.
RestTemplate. postForObj ect (), - POST,
URL, Contact .
:
Testing create contact :
Contact created successfully: Contact - Id: null, First name: James,
Last name: Gosling, Birthday: 2014-03-l:00:00.000-04:00
12. Spring 567
.

- REST Spring Security


,
- . - REST
. ,
Spring Security - REST .
Spring Security 3.2 (
3.2.1. RELEASE), -
RES.
Spring Security - REST
. - (web. xml)
;
12.38.
12.38. Spring Security w. xml
<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>/restful/*</url-pattern>
</filter-mapping>

, Spring Security
, .
- RES,
URL /restful/* ( <filter-mapping>).
Spring Security,
WebApplicationContext.
web-security. xml 12.39.
12.39. Spring Security
<?xml version="l.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<http pattern="/restful/**" create-session="stateless">
<intercept-url pattern= ' /**' access='ROLE_REMOTE' />
<http-basic />
</http>
568 12. Spring
<authentication-manager>
<authentication-provider>
<user-service>
<user name="remote" password="remote" authorities="ROLE_REMOTE" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>

security (
xmlns= "http://www. springframework. org/schema/security")

. <http> , URL
/restful/**. create-session, Spring Security 3.1.0,
,
. - REST ,
stateless, Spring Security ,
- REST .
- RES.
<intercept-url> ,
REST ROLE_ REMOTE.
<http-basic/> , - REST
.
<authentication-manager> ,
.
( remote)
ROLE_REMOTE. ,
, , LDAP.
Spring Security
WebApplicationContext. root-context. xml :
<import resource="web-security.xml" />
.
RestfulClientSample , (
):
Exception in thread "main" org. springframework. web.cient.
HttpClientErrorException: 401 Unauthorized
main org. springframework. web. cient.
HttpClientErrorException: 401
401,
. RestTemplate
.

REST 12.40
rest ful-cl ient-app-context. xml.
12. Spring 569
12.40. restful-client-app-context.xml
<?xrnl version="l.O" encoding="UTF-8"?>
<beans xrnlns="http://www.springfrarnework.org/scherna/beans"
xrnlns:xsi="http://www.w.org/2001/XLScherna-instance"
xsi:schernaLocation="http://www.springfrarnework.org/scherna/beans
http://www.springfrarnework.org/scherna/beans/spring-beans.xsd">
<bean id="restTernplate"
class="org.springfrarnework.web.client.RestTernplate">
<constructor-arg ref="httpRequestFactory"/>
<property narne="rnessageConverters">
<!-- , , -->
</property>
</bean>
<bean id="castorMarshaller"
class="org.springfrarnework.oxm.castor.CastorMarshaller">
<property name="rnappingLocation"
value="classpath:META-INF/spring/oxm-mapping.xrnl"/>
</bean>
<bean id="httpRequestFactory"
class= "org.springfrarnework.http.client.HttpComponentsClientHttpRequestFactory">
<constructor-arg>
<bean class="org.apache.http.impl.client.DefaultHttpClient">
<property name="credentialsProvider">
<bean
class="com.apress.prospring4.ch12.CustomCredentialsProvider">
<property name="credentials">
<bean
class="org.apache.http.auth.UsernamePasswordCredentials">
<constructor-arg name="userNarne" value="remote"/>
<constructor-arg name="password" value="remote"/>
</bean>
</property>
</bean>
</property>
</bean>
</constructor-arg>
</bean>
</beans>

restTemplate
httpRequest Factory. httpRequestFactory
HttpComponentsClientHttpRequestFactory,
Spring ;1 HttpClient Apache HttpComponents;
DefaultHttpClient,
.
CustomCredentialsProvider,
12.41.
570 12. Spring

12.41. CustomCredentialsProvider
package com.apress.prospring4.ch12;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
puic class CustomCredentialsProvider extends BasicCredentialsProvider
puic void setCredentials(Credentials credentials) {
this.setCredentials(AuthScope.ANY, credentials);

CustomCredenti alsProvider BasicCredentials


Provider HttpComponents,
. 12.40,
,
UsernamePasswordCredentials. UsernamePasswordCredentials
, remote.
httpRequestFactory RestTemplate
RES, ,
. RestfulClientSample,
, .

AMQP Spring

RPC (remote procedure call - )
AMQP (Advanced Message Queuing Protocol -
) . JMS,
AMQP .
AMQP RabitMQ (www. rabbi tmq. org).
Spring .
Spring AMQP (http: //
projects. spring. io/spring-amqp),
l- . Spring AMQP
AMQP ,
RabitMQ.
AMQP Spring AMQP,
RPC.
, RabitMQ www. rabitmq. /
download. html . RabitMQ
, .. .
RabitMQ , .
(Weather Service),
.
WeatherService ( 12.42).
12. Spring 571
12.42. WeatherService
package com.apress.prospring4.chl2;
puic interface WeatherService {
String getForecast(String stateCode);

WeatherService,

, ( 12.43).

12.43. WeatherService
package com.apress.prospring4.chl2;
puic class WeatherServiceimpl implements WeatherService
@Override
puic String getForecast(String stateCode)
if ("FL".equals (stateCode)) {
return "Hot"; //
else if ("".equals (stateCode))
return "Cold"; / /

return "Not availae at this time";


//

, (amqp-rpc
app-context. xml), AMQP
WeatherService, 12.44.

12.44. WeatherService
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:rabit="http://www.springfrarnework.org/schema/rabit"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/rabit
http://www.springframework.org/schema/rabit/spring-rabit.xsd">
<rabit:connection-factory id="connectionFactory" host="localhost" />
<rabit:template id="amqpTemplate"
connection-factory="connectionFactory"
reply-timeout="2000" routing-key="forecasts"
exchange="weather" />
<rabit:admin connection-factory="connectionFactory" />
<rabit:queue name="forecasts" />
572 12. Spring
<rabbit:direct-exchange name="weather">
<rabbit:bindings>
<rabit:inding queue="forecasts" key="forecasts" />
</rabit:indings>
</rabit:direct-exchange>
<bean id="weatherServiceProxy"
class="org.springframework.amqp.remoting.client.AmqpProxyFactoryBean">
<property name="amqpTemplate" ref="amqpTemplate" />
<property name="serviceinterface"
value= "com.apress.prospring4.ch12.WeatherService" />
</bean>
<rabbit:listener-container connection-factory="connectionFactory">
<rabit: listener ref="weatherServiceExporter" queue-names="forecasts" />
</rabit:listener-container>
<bean id="weatherServiceExporter"
class= "org.springframework.amqp.remoting.service.AmqpinvokerServiceExporter">
<property name="amqpTemplate" ref="amqpTemplate" />
<property name="serviceinterface"
value="com.apress.prospring4.ch12.WeatherService" />
<property name="service">
<bean class="com.apress.prospring4.ch12.WeatherServiceimpl"/>
</property>
</bean>
</beans>

RabitMQ
. AmqpProxyFactoryBean,
RPC.
AmqpinvokerServiceExporter,
.
Q . ,
JMS , ,
.. , JMS
AMQP ,
- AMQP (www. amqp. org),
.
RPC ( 12.45).

12.45. AmqpRpcSample
package com.apress.prospring4.ch12;
import org.springframework.context.support.GenericxmlApplicationContext;
pulic class AmqpRpcSample {
pulic static void main(String[] args) {
GenericxmlApplicationContext ctx = new GenericxmlApplicationContext();
ctx.load("classpath:META-INF/spring/amqp-rpc-app-context.xml");
ctx.refresh();
WeatherService weatherService = ctx.getBean(WeatherService.class);
12. Spring 573
System.out.println("Forecast for FL: "
+ weatherService.getForecast("FL") );
System. out. println ("Forecast for : "
+ weatherService. getForecast(""));
System.out.println("Forecast for : "
+ weatherService.getForecast("CA"));
ctx.close() ;

:
Forecast for FL: Hot
Forecast for : Cold
Forecast for : Not availae at this time


Sing-.
Spring,
- Spring.
, JMS.
, - REST Spring
RestTemplate. ,
Spring Q RPC
RabitMQ.
Spring
.
13
Spring

,
(,
..). , ,
, .

.

.

, ,
.
, ,
Sring-. ,
Spring
. , .
.
.
. ,
.
.
- ,
"" .
Spring
Jv-
.
.


-.
, ..
.
, ,
" "
576 13. Spring
.
, JPA 2 ibemate Spring Data
JPA 2 .
"" Hibemate Spring Data JPA
.

2 .
,
.
.
, -
, .
, -,
,
, . ,
,
,
(, ,
).

.




.
, ,

- .
.
, - .
(
, -, ..).
. 13.1 ,
, .

( ,
) ,
TestContext Spring
.
,
Spring Framework ,
,
TestContext,
.
13. Spring 577
13. 1.



: JUnit,
, TestNG
-: Mockito,
EasyMock
: 2
: DbUnit
- :
, " ". Jetty

(
, - ..)
Selenium

.
,



: PMD, Checkstyle,
, FindBugs, Sonar
: Cobertura,
EclEmma
(, , : Gradle,
Maven
..). , : Hudson,
Jenkins
,


IBM Rational Systems Tester



.

,


,


578 13. Spring

. 13.1


IBM Rational Functional Tester,
Unified Functional Testing
-. - -
,
,
,

, -.
" ",




- - Apache JMeter, LoadRunner
,

.


,



.
,
..
IBM Rational TestManager,
Quality Center
,

.


.


.


Spring
, ,
( @Autowired @Resource)
Spring , .
, -
13. Spring 579
, ,
, . . 13.2
.
13.2. Spring

@ContextConfiguration ,

ApplicationContext
@WebAppConfiguration ,
, ApplicationContext
WebApplicationContext
@ContextHierarchy ,
ApplicationContext
.
@ContextConfiguration,

@ActiveProfiles , ,

@DirtiesContext ,
,
- ,


@TestExecutionListeners ,
TestExecutionListener,

TestContextManager
@TransactionConfiguration ,
,
(
transactionanager)
@Rollback ,
,
.


@BeforeTransaction , ,

,
@Transactional
@AfterTransaction , ,

,
@Transactional
580 13. Spring

. 13.2


@IfProfileValue ,
,

@ProfileValueSource ,
Configuration ProfileValueSource, -
@IfProfileValue. -
,
SystemProfileValueSource
@Timed ,
,

@Repeat ,
,


,
. ,
.
,
ContactController,
.

Mockito (http: //code. google. com/p/mockito).


,
. 13.3. ,
, Contact, ContactService ..
13.3. Maven



org.mockito mockito-core 1.9.5 -
Mockito
org.springframework spring-context 4.0.2.RELEASE Spring
org.springframework spring-test 4.0.2.RELEASE Spring
org.springframework spring-web 4.0.2.RELEASE - Spring
junit junit 4.11 -
JUnit
13. Spring 581
. 13.3




org. slf4j slf4j-log4jl2 1.7.6 log4j
SLF4J
joda-time joda-time 2.3
JodaTime
org.jadira.usertype usertype.core 3.0.0.GA

Hibernate/Jodaime

Spring MVC

.
-.
,
(
DI Spring) .
(,
, REST ..)
( ) Spring

.

,
.
,
.
ContactController
listData () create ().
.
l.istData ()
ContactController.
listData (). ,
,
, .
13.1.
13.1. listData ()
package com.apress.prospring4.chl3;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
582 13. Spring
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnock;
import org.mockito.stubbing.Answer;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.ui.ExtendedodelMap;
puic class ContactControllerTest {
private final List<Contact> contacts = new ArrayList<Contact>();
@Before
puic void initContacts() {
Contact contact = new Contact();
contact.setid(ll);
contact.setFirstName("Chris");
contact.setLastName("Schaefer");
contacts.add(contact);

@Test
pulic void testList() throws Exception {
ContactService contactService = mock(ContactService.class);
when(contactService.findAll()).thenReturn(contacts);
ContactController contactController = new ContactController();
ReflectionTestUtils.setField(contactController,
"contactService", contactService);
ExtendedodelMap uiModel = new ExtendedodelMap();
uiModel.addAttribute("contacts", contactController.listData());
Contacts modelContacts = (Contacts) uiModel.get("contacts");
assertEquals(l, modelContacts.getContacts() .size());

-, initContacts (),
@Before, JUnH,
( ,
,
@BeforeClass). ini tContacts ()
.
-, testList () @Test,
JUnit , ,
. contactService (
ContactService) Mockito .mock ()
Mock.ito ( import static).
Mockito when () ContactService.
findAll (), ContactController.
-, ContactController,
contactService, Spring ,
setField ()
ReflectionTestUtils, Spring. ReflectionTestUtils
13. Spring 583
, ,

. , Extended.odelMap
( org. springframework. ui. Model).
-, ContactControll er. listData ().
(
JUnit),
, .
, .
ID-.
create ().

crea te ()
13.2 ,
create ().

13.2. create ()
package com.apress.prospring4.chl3;

import org.mockito.stubbing.Answer;
import org.mockito.invocation.InvocationOnMock;

puic class ContactControllerTests {

@Test
pulic void testCreate()
final Contact newContact = new Contact();
newContact.setid(9991);
newContact.setFirstName("Rod");
newContact.setLastName("Johnson");
ContactService contactService = mock(ContactService.class);
when(contactService.save(newContact)).
thenAnswer(new Answer<Contact>() {
puic Contact answer(InvocationOnMock invocation)
throws Throwae {
contacts.add(newContact);
return newContact;
}
}) ;
ContactController contactController = new ContactController();
ReflectionTestUtils.setField(contactController, "contactService",
contactService);
Contact contact = contactController.create(newContact);
assertEquals(Long.valueOf(999l), contact.getid());
assertEquals("Rod", contact.getFirstName());
assertEquals("Johnson", contact.getLastName());
assertEquals(2, contacts.size());
584 13. Spring

ContactService. save ()
Contact .
org. mockito. stubing. Answer<T>,
.
ContactController. create (),
.
.
create () ,
. ,
, .



. . apress.
prospring4. chl. ContactServiceimpl, J
com. apress. prospring4. chl. ContactService.


2 JPA (Hibernate Spring Data JPA).
, , ContactServiceimpl
-.
,
ContactServiceimpl .


,


. ,
Microsoft \. ,
. ,
, ,
DbUnit (http: / /dbunit. sourceforge. net).
Apache POI (http: / /poi. apache. org),
, Microsoft Excel.
. 13.4 .
13.4. Maven


org.dunit dunit 2.4.9 DbUnit
org.apache.poi poi 3.2-FINAL Apache POI,

Microsoft Office. 3.2-
FINAL -
DbUnit
13. Spring 585




org.spring spring-data- 1.5.0 Spring Data JPA
framework.data jpa
org. spring-orm 4.0.2.RELEASE Spring ORM
springframework
com.h2database h2 1.3.172 2
javax.validation validation- 1.1.0.Final l- -
api JSR-349

org.hibernate hibernate- 5.1.0.Final l- -


validator JSR-349 Hiernate
javax.el el-api 2.2 l- EL



, Spring 3.1,

. ,
ApplicationContext
.
.
(dev). .
, 2
,
.
(test).
. , 2
,
.
r
. (.. ,
JPA, ..) L- datasource
tx-j . xml.
dev. ,
. 13.3
datasource-tx-jpa. xml .
13..
<?xml version="l.O" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdc="http://www.springframework.org/schema/jdc"
586 13. Spring
xmlns:jpa= "http://www.springframework.org/schema/data/jpa"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="transactionanager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref ="emf"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="packagesToScan" value= "com.apress.prospring4.chl3"/>
<property name= "jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect
</prop>
<prop key="hibernate.max_fetch_depth"></prop>
<prop key="hibernate.jdc.fetch_size">SO</prop>
<prop key="hibernate.jdc.batch_size">lO</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<context:annotation-config/>
<jpa:repositories base-package="com.apress.prospring4.chl3"
entity-manager-factory-ref= "emf"
transaction-manager-ref="transactionManager"/>
<beans profile="dev">
<jdc:emedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:META-INF/config/schema.sql"/>
<jdbc:script location="classpath:META-INF/config/test-data.sql"/>
</jdbc:emedded-database>
</beans>
</beans>

, dataSource
<beans> profile, dev, ,
. ,
13. Spring 587
, , JVM
-Dspring. profiles. active=dev.



\.
, ,
@DataSets, Excel
.
(, Spring)
.

, \.
w
org. springframework. test. context. TestExecutionListener
spring-test \- ,

(, ,
..).
@DataSets.

. , ContactService. findAll ()
, 13.4.
13.4. @DataSets
@DataSets(setUpDataSet="/com/apress/prospring4/chl3/ContactServiceimplTest.xls")
@Test
pulic void testE'indAll () throws Exception (
List<Contact> result = contactService.findAll();

@DataSets ,

\.
,
13.5.
13.5. (@DataSets)
package com.apress.prospring4.chl3;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
588 13. Spring
puic @interface DataSets {
String setUpDataSet() default 11 11
;

@DataSets .
, TestExecutionListener
( 13.6).
13.6. w
package com.apress.prospring4.ch13;
import org.dunit.IDatabaseTester;
import org.dunit.dataset.IDataSet;
import org.dunit.util.fileloader.XlsDataFileLoader;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestExecutionListener;
pulic class ServiceTestExecutionListener implements TestExecutionListener
private IDatabaseTester databaseTester;
@Override
puic void afterTestClass(TestContext argO) throws Exception {
}
@Override
puic void afterTestMethod(TestContext argO) throws Exception {
if (databaseTester != null) {
databaseTester.onTearDown();

@Override
pulic void beforeTestClass(TestContext argO) throws Exception {
}
@Override
pulic void beforeTestMethod(TestContext testCtx) throws Exception
DataSets dataSetAnnotation =
testCtx.getTestMethod().getAnnotation(DataSets.class);
if (dataSetAnnotation == null ) {
return;

String dataSetName = dataSetAnnotation.setUpDataSet();


if (!dataSetName.equals( 11 11 ) } {
databaseTester = (IDatabaseTester}
testCtx.getApplicationContext(} .getBean( 11databaseTester 11 };
XlsDataFileLoader xlsDataFileLoader = (XlsDataFileLoader}
testCtx.getApplicationContext() .getBean( 11 xlsDataFileLoader 11 };
IDataSet dataSet = xlsDataFileLoader.load(dataSetName};
databaseTester.setDataSet(dataSet);
databaseTester.onSetup(};

@Override
puic void prepareTestinstance(TestContext argO} throws Exception {
}
13. Spring 589
TestExecutionListener
.
beforeTestMethod() afterTestMethod(),

. , Spring
TestContext,
ApplicationContext, Spring Framework.
beforeTestMethod() . -,
@DataSets .
, \.
IDatabaseTester ( org.dbunit.
DataSourceDatabaseTester, )
TestContext. IDatabaseTester DbUnit

.
-, XlsDataFileLoader TestContext.
XlsDataFileLoader - DbUnit
Excel. Microsoft Office
Apache POI.
XlsDataFileLoader. load(),
IDataSet, .
, -,
IDatabaseTester. setDataSet(), -
IDatabaseTester.onSetup().
afterTestMethod ()
IDatabaseTester.onTearDown().

.
13.7 , Java Config.
13.7. ServiceTestConfig
package com.apress.prospring4.chl3;
import javax.sql.DataSource;
import org.dbunit.DataSourceDatabaseTester;
import org.dunit.util.fileloader.XlsDataFileLoader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.emedded.
EmeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.emedded.EmeddedDatabaseType;
@Configuration
@ImportResource("classpath:META-INF/spring/datasource-tx-jpa.xml")
@ComponentScan(basePackages= {"com.apress.prospring4.ch13"})
@Profile("test")
590 13. Spring
puic class ServiceTestConfig
@Bean
puic DataSource dataSource()
return new EmeddedDatabaseBuilder().setType(EmeddedDatabaseType.H2)
.addScript("classpath:schema.sql").build();

@Bean(name="databaseTester")
puic DataSourceDatabaseTester dataSourceDatabaseTester()
DataSourceDatabaseTester databaseTester =
new DataSourceDatabaseTester(dataSource());
return databaseTester;

@Bean(name="xlsDataFileLoader")
puic XlsDataFileLoader xlsDataFileLoader()
return new XlsDataFileLoader();

ServiceTestConfig ApplicationContext
. -, L-
datasource-tx-jpa. xml,
JPA, .
@ComponentScan, Spring
, . @Profile ,
, , test.
-, dataSource,
schema.sql 2,
. Excel
databaseTester xlsDataFileLoader.
, dataSourceDatabaseTester
dataSource, .


, ContactService.
findAll () ContactService. findByFirstNameAndLastName (). ,
Excel.
,
, . ,
/src/test/java/com/apress/prospring4/
chl/data/ContactServiceimplTest.xls.
.
(CONTACT),
. , ,
. ID,
. ,
. Excel
, .
13.8 11
.
13. Spring 591
13.8.
package com.apress.prospring4.ch13;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.AstractTransactionalJUnit4S
pringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner. class)
@ContextConfiguration(classes = {ServiceTestConfig.class})
@TestExecutionListeners({ServiceTestExecutionListener.class})
@ActiveProfiles("test")
puic class ContactServiceimplTest
extends AstractTransactionalJUnit4SpringContextests
@Autowired
ContactService contactService;
@DataSets(setUpDataSet=
"/com/apress/prospring4/ch13/ContactServiceimplTest.xls")
@Test
pulic void testFindAll{) throws Exception {
List<Contact> result = contactService.findAll{);
assertNotNull(result);
assertEquals(l, result.size());

@DataSets(setUpDataSet=
"/com/apress/prospring4/ch13/ContactServiceimplTest.xls")
@Test
puic void testFindByFirstNameAndLastName_l() throws Exception
Contact result =
contactService.findByFirstNameAndLastName("Chris", "Schaefer");
assertNotNull(result);

@DataSets(setUpDataSet=
"/com/apress/prospring4/chl3/ContactServiceimplTest.xls")
@Test
pulic void testFindByFirstNameAndLastName_2() throws Exception
Contact res