Bring your Spring knowledge up-to-date by attending this workshop.
Instead of diving into functionality which was already there in older Spring versions, we will focus on the new Spring 4 features. We will however point out small API differences.
The structure of the Workshop will be as follows:
1. Java SE & Java EE support
2. Spring Core
3. Spring WebMVC
4. WebSockets & Messaging
5. Testing Improvements
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...
Spring 4 - A&BP CC
1. Spring 4
Ken Coenen, Dieter Hubau, Tim De Grande, Steve De Zitter,
Serguei Storojenko, Andreas Evers
2. Agenda
Steve De Zitter
Java SDK & EE support
Tim De Grande
Spring Core
Serguei Storojenko
Spring WebMVC
Ken Coenen
WebSockets and Messaging
Dieter Hubau
Testing improvements
Andreas Evers
Spring Core
4. Java 8 features in Spring 4/4.1
▪ Lambda expressions
▪ Method references
▪ JSR-310 Date/Time Support
▪ Repeatable annotations
▪ Parameter name discovery
▪ Java.util.Optional
▪ Related new injection features
▪ Ordering, @Priority, Generic types
5. Java 8 lamda conventions
▪ Functional interfaces
▪ Typically callback interfaces such as Runnable/Callable
▪ Common functional interfaces in java.util.function
▪ Function, Predicate, Supplier
▪ Used extensively in Java8 Streams Api
6. Lambda conventions in Spring api’s
▪ TransactionTemplate with TransactionCallback
▪ JdbcTemplate/JdbcOperations with PreparedStatementSetter
▪ JdbcTemplate/JdbcOperations with RowMapper
▪ TaskExecutor
▪ ListenableFuture
7. Lambdas JdbcOperations example
▪ PreparedStatementSetter and RowMapper pre Java 8
List<Beer> beers = jdbcOperations.query(SELECT_BEER_BY_NAME_AND_ALCOHOL_PERCENTAGE,
new PreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps) throws SQLException{
ps.setString(1, "%" + name + "%");
ps.setBigDecimal(2, alcoholPercentage);
}
},
new RowMapper<Beer>() {
@Override
public Beer mapRow(ResultSet rs, int rowNum) throws SQLException{
return new Beer(rs.getLong("id"), rs.getString("name"),
rs.getString("description"),
rs.getBigDecimal("alcoholPercentage"),
rs.getTimestamp("modifiedTimestamp”));
}
}
);
8. Lambdas JdbcOperations example
▪ PreparedStatementSetter and RowMapper with lambdas
List<Beer> beers = jdbcOperations.query(
SELECT_BEER_BY_NAME_AND_ALCOHOL_PERCENTAGE,
ps -> {
ps.setString(1, "%" + name + "%");
ps.setBigDecimal( 2, alcoholPercentage);
},
(rs, rowNum) -> new Beer(rs.getLong( "id"),
rs.getString("name"),
rs.getString("description"),
rs.getBigDecimal( "alcoholPercentage”))
);
9. Lambdas TaskExecutor example
▪ TaskExecutor (ThreadPoolTaskExecutor) pre Java 8
return threadPoolTaskExecutor.submitListenable( new Callable<List<Beer>>() {
@Override
public List<Beer> call() throws Exception {
return beerRepository.getAllBeers();
}
});
▪ TaskExecutor with lambdas
return threadPoolTaskExecutor.submitListenable(
() -> beerRepository.getAllBeers()
);
10. ListenableFuture example
▪ ListenableFuture pre Java 8 with ListenableFutureCallback
ListenableFuture<List<Beer>> future =
taskExecutorService.getBeersAsyncUsingTaskExecutor();
future.addCallback( new ListenableFutureCallback<List<Beer>>() {
@Override
public void onFailure(Throwable throwable) {
//Handle Failure
}
@Override
public void onSuccess(List<Beer> beers) {
//Handle success
}
});
11. ListenableFuture example
▪ ListenableFuture pre Java 8 with success and failure callback
ListenableFuture<List<Beer>> future =
taskExecutorService.getBeersAsyncUsingTaskExecutor();
future.addCallback( new SuccessCallback<List<Beer>>() {
@Override
public void onSuccess(List<Beer> beers) {
//Handle success
}
}, new FailureCallback() {
@Override
public void onFailure(Throwable throwable) {
//Handle Failure
}
});
13. Method references
▪ PreparedStatementSetter and RowMapper method reference example
List<Beer> beers = jdbcOperations.query(
SELECT_BEER_BY_NAME_AND_ALCOHOL_PERCENTAGE,
ps -> {
ps.setString(1, "%" + name + "%");
ps.setBigDecimal( 2, alcoholPercentage);
},
this::mapRow
);
14. JSR-310 Date/Time Api
▪ Support for Java8 LocalDate, LocalDateTime, …
▪ @DateTimeFormat annotation is also applicable to Java8 Date/Time
types.
▪ Bind String to JSR-310 Date/Time objects
▪ Render JSR-310 objects to Strings
15. JSR-310 Date/Time Api support example
▪ Mapping incoming @PathVariable to LocalDateTime
@RequestMapping (value = "/modified/{modifiedDate}",method = RequestMethod.
GET)
public List<Beer> getBeersModifiedAfterDate(
@PathVariable @DateTimeFormat(pattern="ddMMyyyyHHmm”)
LocalDateTime modifiedDate){
return beerRepository.getBeersLastModifiedTimestampGreaterThan(
Timestamp.valueOf(modifiedDate));
}
▪ /modified/110320151930
16. JSR-310 Date/Time Api support example
▪ Domain object
public class Beer {
private Long id;
private String name;
private String description;
private BigDecimal alcoholPercentage;
// @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private LocalDate since;
@DateTimeFormat (pattern = "ddMMyyyyHHmm")
private LocalDateTime modifiedTimestamp;
17. Rendering out the LocalDateTime property
▪ Jsp Snippet
Beer modified timestamp: <form:input path="modifiedTimestamp" />
▪ Renders:
21. Spring 4 Parameter discovery
▪ As of Spring 4.0 aware of Java8’s parameter reflection
▪ Parameter names now available in Spring through common Java8
reflection methods.
▪ Java8
▪ ‘-parameters’ compiler flag
▪ Java 6 and 7: via asm
▪ ‘-debug’ compiler flag
22. Spring 4 parameter discovery
▪ Without parameter discovery (no –debug or –parameters compilation flag)
@RequestMapping (value = "/{id}", method = RequestMethod. GET)
public Beer getBeerById( @PathVariable("id") Long id) {
return beerRepository.getBeerById(id);
}
▪ With Parameter discovery
@RequestMapping (value = "/{id}", method = RequestMethod. GET)
public Beer getBeerById( @PathVariable Long id) {
return beerRepository.getBeerById(id);
}
23. Spring data custom query parameter discovery
▪ Custom query in Spring data JPA without parameter name discovery
▪ Custom query in Spring data JPA with parameter name discovery
24. Java 8 Optional
▪ Java.util.Optional as method parameter type with annotations that have
required attribute
▪ @RequestParam
▪ @RequestHeader
▪ @MatrixVariable
▪ …
▪ Optional on Autowired dependencies
26. Optional on MVC handler method parameter
▪ Usage of Optional on @RequestHeader parameter
@RequestMapping (value = "/{id}", method = RequestMethod. GET)
public Beer getBeerById(
@PathVariable Long id,
@RequestHeader Optional<String> country) {
country.ifPresent(System.out::println);
return beerRepository.getBeerById(id);
}
27. Optional on Injected dependencies
▪ Required=false on dependency
@RestController
@RequestMapping ("/beers")
public class BeerController {
@Autowired(required = false)
private NotificationService notificationService;
▪ Using the dependency
@RequestMapping (value = "/{id}", method = RequestMethod. GET)
public Beer getBeerById(
@PathVariable Long id,
@RequestHeader Optional<String> country) {
if(notificationService != null)
notificationService.sendNotification("getBeerForId: " + id);
28. Optional on Injected dependencies
▪ Optional dependency
@RestController
@RequestMapping ("/beers")
public class BeerController {
@Autowired
private Optional<NotificationService> notificationService;
▪ Using the dependency
@RequestMapping (value = "/{id}", method = RequestMethod. GET)
public Beer getBeerById( @PathVariable Long id,
@RequestHeader Optional<String> country) {
notificationService.ifPresent(
service -> service.sendNotification( "getBeerForId: " + id)
);
return beerRepository.getBeerById(id);
}
29. Injection of Ordered Lists (Spring 4.0)
▪ Injection point or Ordered List
@RestController @RequestMapping ("/beers")
public class BeerController {
@Autowired
private List<MyService> services;
▪ MyService dependency with @Order(1)
@Service @Order (1)
public class MyServiceImpl implements MyService {
▪ MyService dependency with @Order(2)
@Service @Order (2)
public class MyOtherServiceImpl implements MyService {
30. ▪ Injection point for Ordered List
@RestController @RequestMapping ("/beers")
public class BeerController {
@Autowired
private List<MyService> services;
▪ MyService dependency with @Order(1)
@Bean @Order(1)
public MyService service1() {
return new MyServiceImpl();
}
▪ MyService dependency with @Order(3)
@Bean @Order(3)
public MyService service2() {
return new MyOtherServiceImpl();
}
@Order on @Bean methods (Spring 4.1)
31. @javax.annotation.Priotity
▪ Injection point for Ordered List
@RestController
@RequestMapping ("/beers")
public class BeerController {
@Autowired
private List<MyService> services;
▪ MyService dependency with @Priority(1)
@Service @Priority (1)
public class MyServiceImpl implements MyService {
▪ MyService dependency with @Priority(2)
@Service @Priority (2)
public class MyOtherServiceImpl implements MyService {
32. @Priority for primary candidate selection
▪ Inject 1 Bean with multiple @Priority beans
@RestController @RequestMapping ("/beers")
public class BeerController {
@Autowired
private MyService service; //Injects MyServiceImpl
▪ Inject 1 Bean with multiple @Order beans
▪ Fails! Causes: org.springframework.beans.factory.
NoUniqueBeanDefinitionException
▪ This can be solved however!
▪ By Electing 1 of the @Order beans with @Primary (Spring 3 annotation)
@Service
@Order(1) @Primary
public class MyServiceImpl implements MyService {
33. @Qualifier for candidate selection
@Service @Qualifier ("myServiceImpl")
public class MyServiceImpl implements MyService {
@Service @Qualifier("myOtherServiceImpl")
public class MyOtherServiceImpl implements MyService {
@RestController @RequestMapping ("/beers")
public class BeerController {
@Autowired @Qualifier ("myServiceImpl")
private MyService service; //Injects MyServiceImpl
34. Generic type for candidate selection (Spring 4.0)
@Service
public class BeerServiceImpl implements MyService<Beer> {
@Service
public class MyOtherServiceImpl implements MyService<OtherEntity> {
@RestController @RequestMapping ("/beers")
public class BeerController {
@Autowired
private MyService<Beer> service; //Injects BeerServiceImpl
43. Conditions have access to:
Different strokes for different folks (3)
Annotated object Condition Context
Annotations
Meta annotations
Class hierarchy
...
Bean definition registry
Scopes
Beans that are created
Classloader
Environment
Resources
...
48. 48
General Web Improvements Spring 4.0
▪ Focused primarily on Servlet 3.0+ environments.
▪ WebSocket support
▪ New @RestController annotation
▪ New AsyncRestTemplate class
▪ Comprehensive time zone support
49. 49
Focus on Servlet 3.0 + environments
▪ Deployment to Servlet 2.5 servers
remains an option
▪ Keep in mind: If you are using the
Spring MVC Test Framework you
will need to ensure that a Servlet
3.0 compatible JAR is in your test
classpath.
▪ Main practical implication: web.xml
is no longer needed (still
supported, though)
52. 52
AsyncRestTemplate
▪ Web applications often need to
query external REST services these
days. The very nature of HTTP and
synchronous calls can lead up to
challenges when scaling
applications for those needs:
multiple threads may be blocked,
waiting for remote HTTP responses.
58. 58
Comprehensive time zone support (4)
▪ Out of box, there is a bunch of classes implementing
LocalContextResolver interface.
▪ Some of them support setting default TimeZone
▪ Some of them also support fall back to the server TimeZone
59. 59
Comprehensive time zone support (5)
▪ When available, the user’s TimeZone can be obtained using the
RequestContext.getTimeZone() method.
▪ Time zone information will automatically be used by Date/Time Converter and
Formatter objects registered with Spring’s ConversionService.
60. 60
Comprehensive time zone support (6)
Question
How to pass time zone info from the client to LocaleContext?
61. 61
Comprehensive time zone support (7)
▪ Old good Locale scenario:
- Locale info passed as a request parameter (ex: user chooses language)
- Out-of-box LocaleChangeInterceptor would intercept the request and
set the required Locale in LocaleResolver
62. 62
Comprehensive time zone support (8)
▪ Possible TimeZone scenario:
- TimeZone info passed as a request parameter (ex: JavaScript function
returning TimeZone)
- Extending LocaleChangeInterceptor (writing own interceptor) to
handle TimeZone info and setting the correct LocaleContext in
LocaleContextResolver
63. 63
Spring 4.1 web improvement
▪ There is a number of small and bigger improvements. Further, in this
presentation some of them will be highlighted.
▪ For the complete and comprehensive list of the improvements, please, consult
the Spring documentation
64. 64
JDK 1.8’s java.util.Optional support
▪ Optional is now supported for @RequestParam, @RequestHeader, and
@MatrixVariable controller method arguments.
▪ DEMO
65. 65
@JsonView
▪ Jackson’s @JsonView is supported directly on @ResponseBody and
ResponseEntity controller methods for serializing different amounts of detail
for the same POJO (e.g. summary vs. detail page).
▪ Also supported with View-based rendering by adding the serialization view type
as a model attribute under a special key.
▪ DEMO
66. 66
New type: RequestEntity
▪ Provides a builder-style API to guide client-side REST code towards the
preparation of HTTP requests.
▪ For example:
68. 68
Full list of improvements
▪ Full list of improvements to be found here:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/new-in-
4.1.html
80. Polling disadvantages
● Client initiates a request (even with long polling mechanism)
● Traffic and overhead (even if there is no data!)
● Big delay between event and notification
● Consider server loads
81. And with HTML5 came… WebSockets!
What do you think about a
protocol upgrade?
82. And with HTML5 came… WebSockets! (2)
What do you think about a
protocol upgrade?
Sure, why not!
HTTP 101 Switching Protocols
84. What about AJAX? Can I still use it?
AJAX
High latency (HTTP req/res for each
roundtrip)
Small to medium messages
WebSockets
Low latency (TCP socket remains
open)
Large and frequent messages
Realtime applications (stocks,
games, …)
● Not every project needs WebSockets!
85. WebSockets in Spring
● New Spring WebSocket module
● Fallback option with SockJS
● as underlying sub-protocol (https://stomp.github.io/)
○ Simple interoperable protocol for asynchronous messaging
○ Client actions: SEND, SUBSCRIBE / UNSUBSCRIBE, ACK / NACK
○ Server actions: MESSAGE, RECEIPT, ERROR
86. WebSockets in Spring (2)
● Generic Spring Messaging Module
○ Some Spring integration types promoted to Core (eg. Message,
@MessageMapping, …)
○ Also usable when using JMS
87. WebSockets in Spring (3)
@EnableWebSocket @EnableWebSocketMessageBroker
Raw WebSocket handler support
Extend TextWebSocketHandler or
BinaryWebSocketHandler and
implement handleTextMessage
WebSocket using a higher-level
messaging sub-protocol (eg. STOMP)
88. Raw example
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.TextMessage;
public class MyHandler extends TextWebSocketHandler {
@Override
public void handleTextMessage(WebSocketSession session, TextMessage msg) {
// ...
}
}
89. Raw example (2)
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/myHandler");
}
@Bean
public WebSocketHandler myHandler() {
return new MyHandler();
}
}
90. Demo application
● AngularJS application
● Spring WebMVC backend
● SockJS with higher-level STOMP protocol and Jackson serialization
93. Cleaning up after Spring 3.x (2)
● Many packages/classes/methods were marked as deprecated in the Spring 3.x version
● In Spring 4.x:
○ All deprecated packages have been removed
○ Many deprecated methods and fields have been removed
● Before upgrading from 3.x to 4.x → Look at the deprecation warnings!
94. Pruning in Spring 4.0
● Several things have been pruned to improve the testing experience
< 4.0 4.0+
No more JUnit 3.8 support Use JUnit 4 or TestNG
@ExpectedException Use @Test(expected = MyEx.class) or @Rule
@NotTransactional Use @Transactional(propagation = NOT_SUPPORTED)
SimpleJdbcTestUtils Use JdbcTestUtils or ScriptUtils or @Sql
95. Changes in dependencies in Spring 4.0
● Servlet API mocks → upgraded to Servlet 3.0 API
○ Servlet 3.0 API is easier, more powerful and more versatile
○ Servlet 2.5 API is still supported
● JUnit
○ minimum version 4.8
○ recommended version 4.11
● TestNG → Use version 6.8.5
96. Changes in dependencies in Spring 4.1
● Servlet API mocks → upgraded to Servlet 3.0 API
○ Servlet 3.0 API is easier, more powerful and more versatile
○ Servlet 2.5 API is still supported
● JUnit
○ minimum version 4.9 is supported
○ version 4.11 is recommended
● TestNG
○ version 6.8.8 is recommended
97. New in Spring 4.0
● SocketUtils
○ Used to scan for available UDP and TCP ports
○ Handy for setting up different containers / servers during integration tests
● ActiveProfilesResolver API
○ Programmatic alternative to static profile strings (like in Spring 3.x)
○ Use the resolver attribute in @ActiveProfiles annotation
● Meta-annotation support for tests
○ Easy to create annotations for your annotations
98. New in Spring 4.1
● Groovy scripts can be used to configure your Spring context
● Programmatically start/stop/commit your test transaction with
TestTransaction
● Default & Custom TestExecutionListeners can now be automatically
discovered
● Custom TestExecutionListeners can be merged with the default ones
● @Sql and @SqlConfig allow you to configure execution of SQL scripts
declaratively:
○ before/after a test class
○ before/after a test method