spring 4 advanced final_xtr_presentation

Download Spring 4 advanced final_xtr_presentation

If you can't read please download the document

Upload: sourabh-aggarwal

Post on 09-Feb-2017

405 views

Category:

Engineering


4 download

TRANSCRIPT

By : Sourabh AggarwalDate : 08 OCT 2015

SPRING 4 ++
(ADVANCED)

Cache Improvements in 4.1

Springs caching abstraction is available as from Spring 3.1. Now we have JCache (JSR-107) annotations support.

The following table describes the mapping between the Spring annotations and the JSR-107 counterpart.

SPRINGJSR-107

@Cacheable@CacheResult

@CachePut@CachePut

@CacheEvict@CacheRemove

@CacheEvict(allEntries=true)@CacheRemoveAll

@CacheResult

@CacheResult is fairly similar to @Cacheable, the following rewrites the original example using the @CacheResult annotation.

Code rewrite:@CacheResult(cacheName = "books")public Employee findEmployee(String employeeID) {...}

Keys generation can be customized using the CacheKeyGenerator interface. If no specific implementation is specified, the default implementation, per spec, takes all parameters unless one or more parameters are annotated with the @CacheKey annotation, in which case only those are used. Assuming that the method above needs now an extra attribute that should not be part of the key, this is how we would write it with Jcache.

Code rewrite:@CacheResult(cacheName = "book")public Employee findEmployee(@CacheKey String employeeID, boolean stillThere) { ... }

Caching Exception

@CacheResult brings the concept of exception cache: whenever a method execution failed, it is possible to cache the exception that was raised to prevent calling the method again. Lets assume that InvalidIsbnNotFoundException is thrown if the structure of the employeeID is invalid. This is a permanent failure, no book could ever be retrieved with such parameter. The following caches the exception so that further calls with the same, invalid employeeID, throws the cached exception directly instead of invoking the method again..

Code rewrite:@CacheResult(cacheName = "Employees", exceptionCacheName = "failures"cachedExceptions = InvalidIdNotFoundException.class)public Employee findEmployee(@CacheKey String employeeID) { ... }

CacheResolverFactory

JCache has this cool notion of CacheResolver that permits to resolve the cache to use at runtime. Because JCache supports regular caches and exception caches, the CacheResolver instances to use are determined by a CacheResolverFactory. The obvious default is to resolve the cache to use based on the cacheName and exceptionCacheName attributes, respectively. However, it is also possible to customize the factory to use per operation.

Code rewrite:@CacheResult(cacheName = "Employees", cacheResolverFactory = MyFactory.class)public Employee findEmployee(@CacheKey String employeeID) { ... }

Finally, @CacheResult has a skipGet attribute that can be enabled to always invoke the method regardless of the status of the cache. This is actually quite similar to our own use of @CachePut.

@CachePut

While the annotations have the same name, the semantic in JCache is fairly different. A simple update for our employee would be written like this.

Code rewrite:@CachePut(value = "Employees", key = "#p0")public Employee update(String employeeId, Employee updatedEmployee) { ... }

While JCache would require you to write it like this.

Code rewrite:@CachePut(cacheName = "Employees")public void update(String employeeId, @CacheValue Employee updatedEmployee) { ... }

Note that even though updatedEmployee should not be part of the key, we didnt have to add a @CacheKey to the first argument. This is because the parameter annotated with @CacheValue is automatically excluded from the key generation.

As for @CacheResult, @CachePut allows to manage any exception that is thrown while executing the method, preventing the put operation to happen if the thrown exception matches the filter specified on the annotation.

@CachePut

While the annotations have the same name, the semantic in JCache is fairly different. A simple update for our employee would be written like this.

Code rewrite:@CachePut(value = "Employees", key = "#p0")public Employee update(String employeeId, Employee updatedEmployee) { ... }

While JCache would require you to write it like this.

Code rewrite:@CachePut(cacheName = "Employees")public void update(String employeeId, @CacheValue Employee updatedEmployee) { ... }

Note that even though updatedEmployee should not be part of the key, we didnt have to add a @CacheKey to the first argument. This is because the parameter annotated with @CacheValue is automatically excluded from the key generation.

As for @CacheResult, @CachePut allows to manage any exception that is thrown while executing the method, preventing the put operation to happen if the thrown exception matches the filter specified on the annotation.

@CacheRemove and @CacheRemoveAll

These are really similar to @CacheEvict and @CacheEvict(allEntries = true) respectively. @CacheRemove has a special exception handling to prevent the eviction if the annotated method throws an exception that matches the filter specified on the annotation.

@CacheDefaults

@CacheDefaults is a class-level annotation that allows you to share common settings on any caching operation defined on the class. These are:The name of the cache

The custom CacheResolverFactory

The custom CacheKeyGenerator

Code rewrite:@CacheDefaults(cacheName = "Employees")public class EmployeeRepositoryImpl implements EmployeeRepository { @CacheResult public Employee findEmployee(@CacheKey String employeeId) { ... }}

Enabling JSR-107 support

The implementation of the JCache support uses our own Cache and CacheManager abstraction which means that you can use your existing CacheManager infrastructure, and yet use standard annotations!

To enable the support of Spring caching annotations, you are used to either @EnableCaching or the xml element, for instance something like:@Configuration@EnableCachingpublic class AppConfig { @Bean public CacheManager cacheManager() { ...}}

So, what does it take to bring the support of standard annotations into the mix? Well, not much. Just add the JCache API and the spring-context-support module in your classpath if you havent already and youll be set.

Cache Improvements in 4.1

@Cachable is used to so that the Employees are cached within the Employees cache.@Componentpublic class SimpleEmployeeRepository implements EmployeeRepository {long time = 5000L;private void simulateSlowService() { try { Thread.sleep(time); } catch (InterruptedException e) { throw new IllegalStateException(e); } }@Cacheable("Employees")public Employee getByEmployeeId(String employeeId) { simulateSlowService(); return new Employee("ABCD", "XI265");}public Employee getByEmployeeIdWithoutCaching(String employeeId) { simulateSlowService(); return new Employee("FGHJ", "XI789");}}

Cache Improvements in 4.1

Output cachable object :2015-10-07 15:56:47:::::::::::: XI265 -->Employee{name='ABCD', employeeId='XI265'}2015-10-07 15:56:52:::::::::::: XI265 -->Employee{name='ABCD', employeeId='XI265'}2015-10-07 15:56:52:::::::::::: XI265 -->Employee{name='ABCD', employeeId='XI265'}

Output non cachable object :2015-10-07 15:57:24:::::::::::: XI789 -->Employee{name='FGHJ', employeeId='XI789'}2015-10-07 15:57:29:::::::::::: XI789 -->Employee{name='FGHJ', employeeId='XI789'}2015-10-07 15:57:34:::::::::::: XI789 -->Employee{name='FGHJ', employeeId='XI789'}

Caching support

Hands on!!!!

New modules added

Spring-websocket : Helps the two way communication between client and server.

WebSocket-style messaging in web applications including use of STOMP as an application level WebSocket sub-protocol.

SockJS Fallback Options explains the SockJS protocol and shows how to configure and use it.

Module is added in Spring 4.0 not present in previous versions.

Spring-messaging :The module includes a set of annotations for mapping messages to methods, similar to the Spring MVC annotation based programming model.

Spring Framework 4 includes a new spring-messaging module with key abstractions from the Spring Integration project such as Message, MessageChannel, MessageHandler, and others that can serve as a foundation for such a messaging architecture.

Module is added in Spring 4.0 not present in previous versions.

Web-Socket Module

WebSocket is a very thin, lightweight layer above TCP.

It makes it very suitable to use "subprotocols" to embed messages.

In example well dive in and use STOMP(Simple or Streaming Text Oriented Message Protocol) messaging with Spring to create an interactive web application.

STOMP, formerly known as TTMP, is a simple text-based protocol, designed for working with message-oriented middleware (MOM).

Example that sends messages back and forth, between a browser and the server.

STOMP(Streaming Text Oriented Message Protocol)

The protocol is broadly similar toHTTP, and works overTCPusing the following commands:CONNECT

SEND

SUBSCRIBE

UNSUBSCRIBE

BEGIN

COMMIT

ABORT

ACK

NACK

DISCONNECT

Communication between client and server is through a "frame" consisting of a number of lines. The first line contains the command, followed by headers in the form : (one per line), followed by a blank line and then the body content, ending in a null character. Communication between server and client is through a MESSAGE, RECEIPT or ERROR frame with a similar format of headers and body content.

Example.......

Well build a server that will accept a message carrying a users name. In response, it will push a greeting into a queue that the client is subscribed to.

STOMP message for name sourabh {"name": "sourabh"}.

Message carrying the name, you can create a plain old Java object with a name property and a corresponding getName() method.public class HelloMessage { private String name; public String getName() { return name; }}

Example.......

Upon receiving the message and extracting the name, the service will process it by creating a greeting and publishing that greeting on a separate queue that the client is subscribed to. The greeting will also be a JSON object, which might look something like this{ "content": "Hello, Fred!"}

To model the greeting representation, you add another plain old Java object with a content property and corresponding getContent() method.public class Greeting { private String content;

public Greeting(String content) { this.content = content; }

public String getContent() { return content; }}

Example.......

GreetingController is mapped to handle messages to destination "/hello". STOMP messages can be routed to controller.

The @MessageMapping annotation ensures that if a message is sent to destination "/hello", then the greeting() method is called.

After the 3 second delay, the greeting() method creates a Greeting object and returns it. The return value is broadcast to all subscribers to "/topic/greetings" as specified in the @SendTo annotation.@Controller

public class GreetingController { @MessageMapping("/hello") @SendTo("/topic/greetings") public Greeting greeting(HelloMessage message) throws Exception { Thread.sleep(3000); // simulated delay return new Greeting("Hello, " + message.getName() + "!"); } }

Example.......

@Configuration indicate that it is a Spring configuration class.@EnableWebSocketMessageBroker enables WebSocket message handling, backed by a message broker.

enableSimpleBroker() to enable a simple memory-based message broker to carry the greeting messages back to the client on destinations prefixed with "/topic". It also designates the "/app" prefix for messages that are bound for @MessageMapping-annotated methods.

The registerStompEndpoints() method registers the "/hello" endpoint, enabling SockJS fallback options so that alternative messaging options may be used if WebSocket is not available. This endpoint, when prefixed with "/app", is the endpoint that the GreetingController.greeting() method is mapped to handle.

@Configuration@EnableWebSocketMessageBrokerpublic class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/hello").withSockJS(); }}

Web-Socket support

Hands on!!!!

Messaging Module

By contrast a WebSocket application may use a single URL only for the initial HTTP handshake. All messages thereafter share and flow on the same TCP connection. This points to an entirely different, asynchronous, event-driven, messaging architecture. One that is much closer to traditional messaging applications (e.g. JMS, AMQP).

We uses Messaging with JMS(Java Message Service) to create, send and read messages.

This example walks you through the process of publishing and subscribing to messages using a JMS broker.

Well build an application that uses Springs JmsTemplate to post a single message and subscribes to it with a @JmsListener annotated method of a managed bean.

JMS Introduction

There are two types of messaging domains in JMS.Point-to-Point Messaging Domain.

In PTP model, one message is delivered to one receiver only. Here, Queue is used as a message oriented middleware (MOM).

In PTP model, there is no timing dependency between sender and receiver.

Publisher/Subscriber Messaging Domain.

In Pub/Sub model, one message is delivered to all the subscribers. It is like broadcasting. Here, Topic is used as a message oriented middleware that is responsible to hold and deliver messages.

In PTP model, there is timing dependency between publisher and subscribe.

JMS Programming Model

Point-to-Point Messaging Domain

Pub/Sub Messaging Domain

Example.......

The JmsListener annotation defines the name of the Destination that this method should listen to and the reference to the JmsListenerContainerFactory to use to create the underlying message listener container.@Component

public class Receiver { @Autowired ConfigurableApplicationContext context; @JmsListener(destination = "mailbox-destination", containerFactory = "myJmsContainerFactory") public void receiveMessage(String message) { System.out.println("Received "); context.close(); FileSystemUtils.deleteRecursively(new File("activemq-data")); } }

Example.......

@SpringBootApplicationis a convenience annotation that adds all of the following:@Configurationtags the class as a source of bean definitions for the application context.

@EnableAutoConfigurationtells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings.

@ComponentScantells Spring to look for other components, configurations, and services in the thehellopackage, allowing it to find theReceiver.

@EnableJms triggers the discovery of methods annotated with @JmsListener, creating the message listener container under the covers.For clarity, we have also defined a myJmsContainerFactory bean that is referenced in the JmsListener annotation of the receiver. This creates a SimpleMessageListenerContainer, an asynchronous message receiver that is fired up when the application context starts.Spring provides a convenient template class called JmsTemplate. JmsTemplate makes it very simple to send messages to a JMS message queue. In the main runner method, after starting things up, you create a MessageCreator and use it from jmsTemplate to send a message.Two beans that you dont see defined are JmsTemplate and ActiveMQConnectionFactory. These are created automatically by Spring Boot. In this case, the ActiveMQ broker runs embedded.By default, Spring Boot creates a JmsTemplate configured to transmit to queues by having pubSubDomain set to false. The SimpleMessageListenerContainer is also configured the same. To override, set spring.jms.isPubSubDomain=true via Boots property settings (either inside application.properties or by environment variable). Then make sure the receiving container has the same setting.

Example.......

The JmsListener annotation defines the name of the Destination that this method should listen to and the reference to the JmsListenerContainerFactory to use to create the underlying message listener container.@Bean JmsListenerContainerFactory myJmsContainerFactory(ConnectionFactory connectionFactory) { SimpleJmsListenerContainerFactory factory = new SimpleJmsListenerContainerFactory(); factory.setConnectionFactory(connectionFactory); return factory; }public void sendMessage(ConfigurableApplicationContext context){ // Clean out any ActiveMQ data from a previous run FileSystemUtils.deleteRecursively(new File("activemq-data")); // Send a message MessageCreator messageCreator = new MessageCreator() { public Message createMessage(Session session) throws JMSException { return session.createTextMessage("ping!"); } }; JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class); System.out.println("Sending a new message."); jmsTemplate.send("mailbox-destination", messageCreator);}

Messaging support

Hands on!!!!

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html

Unit Testing

Integration Testing

Testing

Spring in Junit testingWhy Spring in testing?

Many things reamins untested e.g. request mapping, data binding, type conversions and validation.

Controller methods such as @InitBinder, @ModelAttribute, and @ExceptionHandler also get called as part of processing the request.

Spring in Junit testingIn Spring 3.0, @Configuration was introduced for Java based configuration. However the TestContext framework did not provide support fro this.

In 3.1 AnnotationConfigContextLoader was used and @ContextConfiguration annotation is updated to support @Configuration.

Spring in Junit testingCreating a Unit Test Class

To load ApplicationContext two annotations are used:

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = {...}): Indicates which XML files contain the ApplicationContext.

Spring in Junit testingHow it works?

Spring 3.0:

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfigurationpublic class OrderServiceTest {

@Autowired

private OrderService orderService;

}

Spring in Junit testingHow it works?

Spring 3.1 (Java Configuration Support):

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(loader=AnnotationConfigContextLoader.class)public class OrderServiceTest {

@Configuration

static class ContextConfiguration {@Bean public OrderService orderService() { OrderService orderService = new OrderServiceImpl();

Spring in Junit testingHow it works?

Spring 3.1:

// set properties, etc. return orderService; }}@Autowiredprivate OrderService orderService;}

Spring in Junit testingHow it works?

Spring 3.1 (When we want to use bean defination from other java class):

@Configurationpublic class OrderServiceConfig {@Bean public OrderService orderService() {OrderService orderService = new OrderServiceImpl(); // set properties, etc. return orderService; }

Spring in Junit testingHow it works?

Spring 3.1 (When we want to use bean defination from other java class):

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=OrderServiceConfig.class, loader=AnnotationConfigContextLoader.class)public class OrderServiceTest {@Autowired private OrderService orderService;}

Spring in Integration testingWhy use Spring for Integration testing?

Spring IoC container caching.

Dependency Injection of test fixture instances.Transaction management.Spring-specific base classes.

Spring 4 testing improvementsGroovy scripts can now be used to locad context for integration testing.

How?

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration({"/AppConfig.groovy", "/TestConfig.Groovy"})

Context loading with annotated classes.

How?

@ContextConfiguration(classes = {AppConfig.class, TestConfig.class})public class MyTest {

Spring 4 testing improvementsAnnotated class can be one of the following:

@ConfigurationA component @Component, @Service, @Repository@BeanIf no class is defined then as per the default behaviour search the static class in the test taht meets the requirement of configuration.

public class OrderServiceTest {

@Configuration

static class Config {

// this bean will be injected into the OrderServiceTest class @Bean public OrderService orderService() { OrderService orderService = new OrderServiceImpl(); // set properties, etc. return orderService; } }

Spring 4 testing improvementsTest-managed transactions can be triggered and rolled back per testcase bases. TestTrduced with static methods like start(), end() and isActive().TransactionalTestExecutionListener supports the @BeforeTransaction and @AfterTransaction annotations to execute certain code before or after a transactional test.@Before and @After are executed as part of transaction in each testcase but @BeforeTransaction and @AfterTransaction are excluded from the transactional scope.

Spring 4 testing improvementsSQL scripts execution with @sql before or after the integration test case. This annotation can be used at class as well as method level.How to declare?@Test @Sql({"/test-schema.sql", "/test-user-data.sql"}) public void userTest { // execute code that uses the test schema and test data }

Spring 4 testing improvementsSQL scripts execution can be restricted at transactional level or at the execution phase level.How to declare?@Sql( scripts = "delete-test-data.sql", config = @SqlConfig(transactionMode = ISOLATED), executionPhase = AFTER_TEST_METHOD)public void userTest {}

Spring 4 testing improvementsTest property sources override application property sources using the annotation @TestPropertySource.How to declare?Option 1:@TestPropertySource("/test.properties")public class MyIntegrationTests { // class body...}

Spring 4 testing improvementsTest property sources can have inligned properties in the form of key value pair using the properties attribute.How to declare?Option 2:@TestPropertySource(properties = {"timezone = GMT", "port: 4242"})public class MyIntegrationTests { // class body...}

Testing Improvement

Hands on!!!!