14 October 2018

Caching with Spring Boot

What-Why Cache?
Cache is a memory between an application and database to reduce the number of
Database hits.It improves performance of applications by reducing expensive
operations(Ex:DB hits), if it is stored with frequently accessed data.
Data which changes less frequently(static master data) and frequently accessed
data can be stored in cache.


Spring boot Cache:
Spring framework provides cache
api to integrate with different cache providers.
Spring boot provides @EnableCaching annotation to enable cache management.
When @Cacheable annotation is used at method level, Spring manages the request and response in cache.@Cacheable annotation has "key" attribute to decide a request to be cached.

Example:
Check code at https://github.com/java9pro/java9pro-cache
Project structure look like


pom.xml
Add dependency spring-boot-starter-cache for enabling cache management.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"         
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>java9pro</groupId>
    <artifactId>java9pro.springboot.cache</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.13.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.codehaus.plexus</groupId>
            <artifactId>plexus-archiver</artifactId>
            <version>3.4</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.9</source>
                    <target>1.9</target>
                    <jdkToolchain>
                        <version>9</version>
                    </jdkToolchain>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.0.2</version>
            </plugin>
        </plugins>
    </build>

</project>
ProductController
It has request mapping with url path parameter as "id" and calls service method.
package com.cache.java9pro;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestControllerpublic class ProductController {
    @Autowired    MobileService mobileService;

    @GetMapping("/mobile/{id}")
    public   Mobile findMobileDetailById(@PathVariable String id)
    {
       return mobileService.getMobileDetailByID(id);
    }
}
Mobile
It is a simple POJO with required attribute id
package com.cache.java9pro;

public class Mobile {
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public String getRam() {
        return ram;
    }

    public void setRam(String ram) {
        this.ram = ram;
    }

    String id;
    String model;
    String ram;
    public Mobile(String id, String model, String ram) {
        this.id=id;
        this.model=model;
        this.ram=ram;
    }
}
MobileService
It has @Cacheable annotation enabled method  getMobileDetailByID 
which call DAO method if and only if the request/response are not available in cache. 
package com.cache.java9pro;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Servicepublic class MobileService {

    @Autowired    MobileDAO  mobileDAO;

    @Cacheable(value="mobile", key="#id")
    public Mobile getMobileDetailByID(String id)
    {
        Mobile mobile=null;
        try {
            System.out.println("Getting from database");
            Thread.sleep(5000);
            mobile = mobileDAO.getMobileInfo(id);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return mobile;
    }
}

MobileDAO
To simulate database access, provided switch-case implementation for different ids
package com.cache.java9pro;

import org.springframework.stereotype.Component;

@Componentpublic class MobileDAO {

    public Mobile getMobileInfo(String id) {
        switch (id){
            case "1" : return new Mobile(id,"Samsung","4GB");
            case "2" : return new Mobile(id,"Apple","6GB");
            case "3" : return new Mobile(id,"Motorola","2GB");
            case "4" : return new Mobile(id,"Lenovo","3GB");

        }
        return null;
    }
}
CacheApplication

It is Spring boot application method with annotation @EnableCaching

package com.cache.java9pro;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication@EnableCachingpublic class CacheApplication {
    public static void main(String[] args) {
        SpringApplication.run(CacheApplication.class, args);
    }
}

application.properties
application.port=8080
Upon running main method application starts on port 8080.
To test the application execute the following URLs
  1. http://localhost:8080/mobile/1
  2. http://localhost:8080/mobile/2
  3. http://localhost:8080/mobile/3
  4. http://localhost:8080/mobile/4
  5. http://localhost:8080/mobile/1
  6. http://localhost:8080/mobile/2
  7. http://localhost:8080/mobile/3
  8. http://localhost:8080/mobile/4
First 4 URLs will access DAO method.
Last 4 URLs (5,6,7,8) will not access DAO method and
will provide response from cache.
Sample output looks like







28 April 2018

LinkedList with Side nodes


LinkedList with side nodes



class SidelyLinkedList  {
    static Node head;
    static class Node {
        int item;
        Node next;
        Node side;
        Node(int item) {
            this.item =item;
            next = null;
            side = null;
        }
    }
    public static void main(String[] args) {
        SidelyLinkedList list = new SidelyLinkedList();
        list.head = new Node(51);
        list.head.next = new Node(10);
        list.head.next.next = new Node(15);
        list.head.next.next.next = new Node(18);
        list.head.next.next.next.next= new Node(21);
        list.head.side = new Node(34);
        list.head.side.side = new Node(48);
        list.head.next.side = new Node(23);
        list.head.next.side.side = new Node(67);
        list.head.next.next.side = new Node(12);
        list.head.next.next.side.side = new Node(89);
        list.head.next.next.next.side = new Node(67);
        list.head.next.next.next.side.side = new Node(92);
        list.head.next.next.next.next.side = new Node(56);
        list.head.next.next.next.next.side.side = new Node(97);
        Node res1 = list.singleList(head);
        list.printSidelyLinkedList(res1);
       }

    private Node singleList(Node node) {
        if(node.next==null){
            return node;
        }
        else{
            Node temp = node;
            Node temp1= node.next;
            while(temp.side!= null){
                temp= temp.side;
            }
            temp.side= temp1;
            node.next=temp1.next;
            return singleList(node);
        }
    }

    private void printSidelyLinkedList(Node head) {
        if(head==null){
            return;
        }
        else            {
            System.out.println(head.item +"->");
                printSidelyLinkedList(head.side);
        }
    }


}

Output:
51->
34->
48->
10->
23->
67->
15->
12->
89->
18->
67->
92->
21->
56->
97->