Caching and Messaging Improvements in Spring Framework 4.1
description
Transcript of Caching and Messaging Improvements in Spring Framework 4.1
© 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)
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Caching improvements
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) { }!
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));! }!!}!
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) { }!!}!
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) { }!}!
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) { }!!}!
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<String> getCacheNames(CacheOperationInvocationContext<?> context) {! return getCacheNames(context.getTarget().getClass());! }!! private Collection<String> getCacheNames(Class<?> serviceType) { }! !}!
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) { }!!}!
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));! }!!}!
Standard JCache bootstraping
11
@Configuration!@EnableCaching!public class ApplicationConfig {!! @Bean! public CacheManager cacheManager() {! return new JCacheCacheManager();! }!!}!
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
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Messaging improvements
Messaging infrastructure recap
14
public class OrderMessageHandler {!! public OrderStatus handleMessage(Order order) {! // order processing, return status! }!}!
<beans ...>! <jms:listener-container message-converter="jmsMessageConverter">! <jms:listener destination="order" ref="orderMessageHandler" method="handleMessage"/>! </jms:listener-container>!! <bean id="orderMessageHandler" class="sgx2014.messaging.spr40.OrderMessageHandler"/>!! <bean id="jmsMessageConverter"! class="org.springframework.jms.support.converter.MappingJackson2MessageConverter">! <property name="targetType" value="TEXT"/>! <property name="typeIdPropertyName" value="__type"/>! </bean>!</beans>!
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!}!
Transition from your existing config
16
<?xml version="1.0" encoding="UTF-8"?>!<beans ...>!! <jms:annotation-driven/>!! <jms:listener-container factory-id="jmsListenerContainerFactory" ! message-converter="jmsMessageConverter"/>!! <bean id="jmsMessageConverter"! class="org.springframework.jms.support.converter.MappingJackson2MessageConverter">! <property name="targetType" value="TEXT"/>! <property name="typeIdPropertyName" value="__type"/>! </bean>!!</beans>!
… 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;! }!}!
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) { }
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<OrderStatus> processOrder(Message<Order> order) { }!
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<Order> orderMessage = MessageBuilder.! withPayload(order).setHeader("orderType", "sell").build();!messagingTemplate.send("order", orderMessage);!
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
https://github.com/SpringOne2GX-2014/messaging-improvements
Demo
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);! }!}!
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);!
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
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) { }!}!
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Q/A
Thank you!