Slide 1

Slide 1 text

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission. Caching and messaging improvements in Spring 4.1 Juergen Hoeller (@springjuergen) - Stéphane Nicoll (@snicoll)

Slide 2

Slide 2 text

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission. Caching improvements

Slide 3

Slide 3 text

Cache abstraction recap 3 public class BookRepository {! ! ! ! ! ! ! ! ! ! ! ! ! ! }! @Cacheable("books")! public Book findById(String id) { } @Cacheable(value = "books", key = "T(s2gx.caching.BookIdResolver).resolveBookId(#isbn)")! public Book findById(ISBN isbn) { }! @CachePut(value = "books", key = "#book.id")! public Book update(Book book) { } @CacheEvict(value = "books")! public void delete(String id) { }!

Slide 4

Slide 4 text

Cache abstraction recap (cont’d) 4 @Configuration! @EnableCaching! public class ApplicationConfig {! ! @Value("classpath:my-ehcache.xml")! private Resource ehCacheConfig;! ! @Bean! public CacheManager cacheManager() {! return new EhCacheCacheManager(! EhCacheManagerUtils.buildCacheManager(ehCacheConfig));! }! ! }!

Slide 5

Slide 5 text

Class level customizations 5 @CacheConfig("books")! public class BookRepository {! ! @Cacheable! public Book findById(String id) { }! ! @Cacheable(key = "T(s2gx.caching.BookIdResolver).resolveBookId(#isbn)")! public Book findById(ISBN isbn) { }! ! @CachePut(key = "#book.id")! public Book update(Book book) { }! ! @CacheEvict! public void delete(String id) { }! ! }!

Slide 6

Slide 6 text

Custom key generator 6 @Component! public class IsbnKeyGenerator implements KeyGenerator {! ! ! @Override! ! public Object generate(Object target, Method method, Object... params) {! ! ! ISBN isbn = extract(params);! ! ! if (isbn != null) {! ! ! ! return BookIdResolver.resolveBookId(isbn);! ! ! }! ! ! throw new IllegalStateException(getClass().getName() +! ! ! ! ! " could not generate a cache id from " + Arrays.toString(params));! ! }! ! ! private ISBN extract(Object... params) { }! }!

Slide 7

Slide 7 text

Operation level customizations 7 @CacheConfig("books")! public class BookRepository {! ! @Cacheable! public Book findById(String id) { }! ! @Cacheable(keyGenerator = "isbnKeyGenerator")! public Book findById(ISBN isbn) { }! ! @CachePut(key = "#book.id")! public Book update(Book book) { }! ! @CacheEvict! public void delete(String id) { }! ! }!

Slide 8

Slide 8 text

CacheResolver 8 public interface CacheResolver {! ! Collection extends Cache> resolveCaches(CacheOperationInvocationContext> context);! ! }! public class MyCacheResolver extends AbstractCacheResolver {! ! @Autowired! public MyCacheResolver(CacheManager cacheManager) {! super(cacheManager);! }! ! @Override! protected Collection getCacheNames(CacheOperationInvocationContext> context) {! return getCacheNames(context.getTarget().getClass());! }! ! private Collection getCacheNames(Class> serviceType) { }! ! }!

Slide 9

Slide 9 text

JCache (JSR-107) support 9 import javax.cache.annotation.CacheDefaults;! import javax.cache.annotation.CachePut;! import javax.cache.annotation.CacheRemove;! import javax.cache.annotation.CacheResult;! import javax.cache.annotation.CacheValue;! ! @CacheDefaults(cacheName = "books")! public class BookRepository {! ! @CacheResult! public Book findById(String id) { }! ! @CacheResult(cacheKeyGenerator = IsbnCacheKeyGenerator.class)! public Book findById(ISBN isbn) { }! ! @CachePut! public void update(String id, @CacheValue Book book) { }! ! @CacheRemove! public void delete(String id) { }! ! }!

Slide 10

Slide 10 text

JCache configuration 10 @Configuration! @EnableCaching! public class ApplicationConfig {! ! @Value("classpath:my-ehcache.xml")! private Resource ehCacheConfig;! ! @Bean! public CacheManager cacheManager() {! return new EhCacheCacheManager(! EhCacheManagerUtils.buildCacheManager(ehCacheConfig));! }! ! }!

Slide 11

Slide 11 text

Standard JCache bootstraping 11 @Configuration! @EnableCaching! public class ApplicationConfig {! ! @Bean! public CacheManager cacheManager() {! return new JCacheCacheManager();! }! ! }!

Slide 12

Slide 12 text

Wrapping up • More use cases are covered out-of-the-box, no need to fallback on programmatic cache access: • CacheResolver: fine-grained runtime cache resolution • Class-level customizations via @CacheConfig: cache name(s), key generator, cache manager and/or cache resolver • Operation-level customizations • JCache (JSR-107) support • Supported automatically when the JSR-107 API is on the classpath • Reuse your existing infrastructure/configuration • Others • Convenient putIfAbsent on Cache interface • Better exception handling 12

Slide 13

Slide 13 text

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission. Messaging improvements

Slide 14

Slide 14 text

Messaging infrastructure recap 14 public class OrderMessageHandler {! ! public OrderStatus handleMessage(Order order) {! // order processing, return status! }! }! ! ! ! ! ! ! ! ! ! ! ! !

Slide 15

Slide 15 text

Annotated endpoint 15 @Component! public class OrderMessageHandler {! ! @JmsListener(destination = "order")! public OrderStatus process(Order order) {! // order processing, return status! }! }! @JmsListener(id = "orderListener", containerFactory = "myContainerFactory", ! destination = "order", selector = "orderType = 'sell'", concurrency = "2-10")! public OrderStatus process(Order order) {! // order processing, return status! }!

Slide 16

Slide 16 text

Transition from your existing config 16 ! ! ! ! ! ! ! ! ! ! ! ! !

Slide 17

Slide 17 text

… or remove XML altogether 17 @EnableJms! @Configuration! public class ApplicationConfig {! ! @Bean! public JmsListenerContainerFactory> jmsListenerContainerFactory(! ConnectionFactory connectionFactory) {! ! DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();! factory.setConnectionFactory(connectionFactory);! factory.setMessageConverter(jmsMessageConverter());! return factory;! }! ! @Bean! public MessageConverter jmsMessageConverter() {! MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();! converter.setTargetType(MessageType.TEXT);! converter.setTypeIdPropertyName("__type");! return converter;! }! }!

Slide 18

Slide 18 text

Flexible method signature 18 @JmsListener(destination = "order")! public void processOrder(Order order) { } @JmsListener(destination = "order")! public void processOrder(Session session, TextMessage textMessage) { } @JmsListener(destination = "order")! public void processOrder(@Valid Order order) { } @JmsListener(destination = "order")! public void processOrder(Order order, @Header String orderType) { } @JmsListener(destination = "order")! @SendTo("orderStatus")! public OrderStatus processOrder(Order order) { }

Slide 19

Slide 19 text

Messaging abstraction • Introduced in Spring Framework 4.0 • org.springframework.messaging.Message is a generic message representation with headers and a body ! ! ! ! • Full access to body and headers for both inbound and outbound messages 19 @JmsListener(destination = "order")! @SendTo("orderStatus")! public Message processOrder(Message order) { }!

Slide 20

Slide 20 text

JmsMessagingTemplate • Similar to JmsTemplate, using o.s.messaging.Message • Exception translation • No JMS api involved at all • Implements common spring-messaging interfaces • MessageSendingOperations • MessageReceivingOperations • MessageRequestReplyOperations 20 Message orderMessage = MessageBuilder.! withPayload(order).setHeader("orderType", "sell").build();! messagingTemplate.send("order", orderMessage);!

Slide 21

Slide 21 text

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission. https://github.com/SpringOne2GX-2014/messaging-improvements Demo

Slide 22

Slide 22 text

Programmatic endpoints registration 22 @EnableJms! @Configuration! public class ApplicationConfiguration implements JmsListenerConfigurer {! ! @Override! public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {! SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint();! endpoint.setDestination("myQueue");! endpoint.setConcurrency("2-10");! endpoint.setMessageListener(message -> {! // message processing! });! registrar.registerEndpoint(endpoint);! }! }!

Slide 23

Slide 23 text

Container recovery • Recovery policy when the broker becomes unreachable • BackOff interface • FixedBackOff: retry every X sec (default to 5 sec) • ExponentialBackOff: increases the back off period for each retry attempt • Implement your own! 23 ExponentialBackOff backOff = new ExponentialBackOff();! backOff.setInitialInterval(2 * 1000); // initial retry every 2 sec! backOff.setMultiplier(1.5); // increase each attempt by 50%! backOff.setMaxInterval(30 * 1000); // stop increasing at 30 sec! factory.setBackOff(backOff);!

Slide 24

Slide 24 text

Wrapping Up • Annotation-driven endpoints • Full java config support • Flexible method signature: @Payload, @Valid, @Header, @Headers • Messaging abstraction integration • JmsMessagingTemplate • Message> can be used as method argument / return type • Endpoint abstraction, programmatic endpoint registration • Container recovery customization • Further JMS 2.0 alignments (shared subscriptions) 24

Slide 25

Slide 25 text

One more thing … • You can use that with AMQP too • Spring AMQP 1.4.0.M1 25 @Component! public class OrderMessageHandler {! ! @RabbitListener(queues = "order")! @SendTo("orderStatus")! public OrderStatus processOrder(Order order, @Header String orderType) { }! }!

Slide 26

Slide 26 text

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission. Q/A Thank you!