How to scale Spring Boot applications with NCache Java Edition

Introduction

In the dynamic realm of software development, efficiency, scalability, and rapid deployment are paramount. As businesses strive to stay ahead in the digital landscape, the need for robust, agile, and easily maintainable applications becomes increasingly critical. Enter Spring Boot, a game-changer in the Java ecosystem, offering a streamlined and convention-over-configuration approach to building powerful and scalable applications. With Spring Boot, developers can focus on building business logic rather than wrestling with complex configurations, accelerating the development process.

Moreover, Spring Boot seamlessly integrates with a wide array of third-party libraries and frameworks, fostering interoperability and enhancing overall project flexibility. The framework's built-in support for embedded servers simplifies deployment, while its auto-configuration feature intelligently adapts to the project's dependencies, ensuring a smoother development experience. Additionally, Spring Boot embraces a modular architecture, promoting code reusability and maintainability. It is the framework of choice for crafting applications ranging from high-traffic, smaller-scale projects to enterprise-level solutions. Its popularity among developers stems from its ability to seamlessly scale, ensuring optimal performance across various application sizes and complexities.

However, high-traffic Spring applications encounter a significant scalability challenge. While expanding the application server farm can address some scalability issues, the database server faces limitations in scaling at the same rate to manage the increasing transaction load. In such scenarios, turning to a Java-distributed cache emerges as the optimal solution. By alleviating the database burden through a reduction in costly database trips, a Java-distributed cache not only enhances application performance but also offers an effective strategy for handling growing transaction loads.

NCache with Spring Boot Application

NCache, a distributed, in-memory caching solution, has integrated the Spring Caching provider by introducing a versatile Java cache mechanism. This facilitates the effortless caching of results from resource-intensive tasks, such as CPU-intensive processes, time-consuming operations, and database-bound methods within Spring applications. This strategic implementation not only alleviates the database load but also minimizes the frequency of method executions, ultimately enhancing the overall performance of the application. In the upcoming sections of this blog, we will delve deeper into the configuration process of Spring Caching with NCache, exploring the steps to harness these benefits seamlessly.

NCache Java Edition

NCache Java Edition

Scaling up the performance of Java Spring application with NCache

The main objective

Integrating NCache with a Java Spring application offers significant advantages, particularly in enhancing application scaling by minimizing database trips. NCache acts as a distributed caching solution, intelligently storing frequently accessed data in memory. This strategic caching mechanism substantially reduces the need for repeated queries to the database, resulting in notable improvements in application responsiveness and reduced latency. By efficiently caching and serving frequently requested data locally, NCache diminishes the workload on the underlying database, contributing to optimized resource utilization.

This reduction in database trips not only accelerates data retrieval but also minimizes the risk of database bottlenecks, making the Java Spring application more scalable and better equipped to handle increased user loads. In essence, integrating NCache with a Java Spring application streamlines and optimizes database interactions, fostering improved scalability and overall performance.

Configure Sprint boot application with NCache

There are two configurations to integrate the NCache with the spring boot application.

  1. Using a Generic Spring Caching provider
  2. JCache Caching provider

NCache offers Spring caching support through two distinct avenues: the Generic Spring Caching Provider, where NCache serves as the designated cache manager for your Spring application, and the JCache Caching Provider, leveraging the supported features of JCache.

Upon configuring your Spring application, which involves tasks like adding Maven packages and ensuring bean definitions, the next step is to associate these caching behaviors by employing the caching declarations outlined in this section.

1. Configure Generic Spring Caching Provider

After activating caching, the subsequent action involves associating the caching behavior with methods and employing NCache as the designated Caching Provider for Spring.

Following the configuration of your Spring application and the activation of caching, the subsequent phase is to pinpoint the methods requiring caching and define their respective policies.

You can link caching behaviors to the methods through.

  • Caching Annotations
  • Declarative XML-based Caching
  • Download and install NCache Java edition
  • The minimum required Java version is 17.0.
  • The Spring Framework version should be 6.0.12 or higher.

Caching Annotations

Add Maven Package

To integrate NCache with Spring, include the following Maven <dependency> in your pom.xml file.

<dependency>
    <groupId>com.alachisoft.ncache</groupId>
    <artifactId>ncache-spring</artifactId>
    <version>x.x.x</version>
</dependency>

I’m using version 5.3.2.1

<dependency>
    <groupId>com.alachisoft.ncache</groupId>
    <artifactId>ncache-spring</artifactId>
    <version>5.3.2.1</version>
</dependency>

Upon incorporating the necessary Maven dependencies, proceed to articulate beans within your Spring application by opting for either the Java-based Bean Definition or the XML-based Bean Definition.

Java-based Bean Definition

To establish beans using the Java-based approach, incorporate the @Bean annotation within the CachingConfiguration class. In this class, utilize the setConfigFile() method to indicate the path to your ncache-spring.xml file, as given below.

package com.alachisoft.ncache.springbootsample;

import com.alachisoft.ncache.spring.NCacheCacheManager;
import com.alachisoft.ncache.spring.configuration.SpringConfigurationManager;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.URL;

@Configuration
public class CachingConfiguration
{
    @Bean
    public CacheManager cacheManager()
    {
        SpringConfigurationManager springConfigurationManager = new SpringConfigurationManager();
        URL resource = getClass().getClassLoader().getResource("ncache-spring.xml");
        springConfigurationManager.setConfigFile(resource.getPath());
        NCacheCacheManager cacheManager = new NCacheCacheManager();
        cacheManager.setSpringConfigurationManager(springConfigurationManager);
        return cacheManager;
    }
}

Declarative XML-based Caching

When annotations are not available as an option, such as in cases with limited source access or the absence of external code, XML can be employed for declarative caching. This involves specifying the target method and caching directives externally.

In the provided configuration, the employeeService is configured to be cacheable. The caching behavior is defined within the cache:advice section, which directs the get method to store data in the cache. These configurations operate on the demoCache.

<!-- the service we want to make cacheable -->
<bean id="employeeService" class="x.y.service.EmployeeService"/>
<!--cache definitions -->
<cache:advice id="booksCacheAdvice" cache-manager="cacheManager">
    <cache:caching cache="demoCache">
        <cache:cacheable method="get" key="#id"/>
    </cache:caching>
</cache: advice>

To implement a Custom Key Generator for cache key generation using XML-based caching, the beans responsible for the key generator must be defined, as exemplified in the class CustomerKeyGenerator below.

<bean id="customerKeyGenerator" class="cachekeygenerator.CustomerKeyGenerator">

In this context, the customerKeyGenerator is responsible for creating a cache key each time a customer is added to the customersCache. To utilize this generator, it is necessary to indicate the keygenerator bean within your cache:advice tag.

<cache:advice id="customerCacheAdvice" key-generator="customerKeyGenerator">
    <cache:caching cache="customersCache">
        <cache:cacheable method="findCustomerByID"/>
    </cache:caching>
</cache: advice>

Upon making the specified modifications to these configurations, your application is now prepared to leverage NCache as a Spring Caching Provider.

Note. Opting for Java-based bean definition is superior to XML-based definition since it ensures type safety and captures all type errors during the compile time.

Configure Caches

The ncache-spring.xml file, utilized by the NCache Management Center, configures caches based on the cacheManager bean. To customize caches, it's essential to add individual caches with distinct properties, such as expiration and item eviction settings.

  • default-cache-name: This attribute enables you to specify a default cache for the Spring application. In scenarios where the configuration file is missing the necessary cache settings, the system will automatically fall back to the designated default cache.
  • caches: Within this tag, you have the flexibility to define numerous caches, each accompanied by its distinct set of properties.
  • ncache-instance: Each Spring cache is associated with a particular cache instance, and it's possible for multiple Spring caches to utilize the same cache instance. The NCache cacheManager for Spring diligently manages the data for each Spring cache within the cache.
  • priority: This attribute establishes the relative priority of items within the cache. In the presence of priority-based eviction, the cache systematically eliminates items starting with the lowest priority when removal is necessary.
  • expiration-type: This attribute allows for the choice between Absolute or Sliding expiration for cache items.
  • expiration-period: Indicates the duration, measured in seconds, after which the cache triggers the expiration process.
<application-config default-cache-name="demoCache">
    <caches>
        <cache name="demoCache" ncacheid-instance="democache" priority="normal" expiration-type="absolute" expiration-period="300"/>
    </caches>
</application-config>
    @SpringBootApplication
@EnableCaching
@RestController
public class SpringbootAzuresqlApplication 
{
    @Autowired
    private EmployeeRepository repository;
     @Autowired
    private EmployeeService service;
   
     @PostMapping("/employee")
     public Employee addEmployee(@RequestBody Employee employee) {
         return service.save(employee);
     }

    @GetMapping("/employees")
    public List<Employee> getEmployees() {
        return repository.findAll();
    }
    public static void main(String[] args) {
        SpringApplication.run(SpringbootAzuresqlApplication.class, args);
    }
      @GetMapping("/employees/id")
    public Employee getEmployeesById(@RequestParam int id) {     
        return  service.get(id);
    }

}

@Service
class EmployeeService {
    @Autowired
    private EmployeeRepository repo;

    public List<Employee> listAll() 
    {
        return repo.findAll();
    }
    
    @CachePut(value = "employee", key = "#employee.id")
    public Employee save(Employee employee) {
        repo.save(employee);
        return employee;
    }

    @Cacheable(value = "employee", key = "#id")
    public Employee get(int id) 
    {
        return repo.findById(id).get();
    }

Make sure you added @EnabelCaching annotation to enable the caching

From the above example, both save and get services are integrated with our NCache using the annotations @Cacheable and @CachePut, read more about the caching annotation here. With cache enabled, whenever the GET employee service is called, it will fetch the data from the cache server by avoiding unnecessary database trips. This is one of the basic samples of scaling up the application with NCache integration, there are many use cases where NCache with a distributed cache mechanism will help to scale up the application.

2. JCache Spring Caching Provider

Prerequisites

For the NCache Client, the minimum required Java version is 17.0.

Maven Packages

Add maven packages as we did for the generic spring caching provider.

<dependency>
    <groupId>com.alachisoft.ncache</groupId>
    <!--for NCache Enterprise-->
    <artifactId>ncache-client</artifactId>
    <!--for NCache Professional-->
    <!--artifactId>ncache-professional-client</artifactId-->
    <version>x.x.x</version>
</dependency>

Cache Configurations

The initialization of JCache occurs through the javax.cache.spi.CachingProvider, which is a JSR-107 compliant caching library present on the classpath.

In case there are multiple JCache providers in your .classpath, it is necessary to explicitly include the tags spring.cache.jcache.provider and spring.cache.type in the application.properties file.

spring.cache.jcache.provider=com.alachisoft.ncache.jsr107.spi.NCacheCachingProvider
spring.cache.type=jcache

To set up your cache for the JCache Spring application and initialize it during application startup, you should include the spring.cache.cache-names tag in the application.properties file. Ensure that the cache name matches the configuration in the NCache Management Center.

spring.cache.cache-names=demoCache,employeeCache

Additionally, you have the option to modify the JCacheManagerCustomizer class to configure the cache and initialize it with these configurations dynamically during runtime.

@Configuration
public class CacheConfiguration implements JCacheManagerCustomizer
{
    @Override
    public void customize(CacheManager cacheManager)
    {
        MutableConfiguration mutableConfiguration = new MutableConfiguration();
        mutableConfiguration.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.ONE_MINUTE));
        cacheManager.createCache("employeeCache", mutableConfiguration);
    }
}

Once you have enabled caching, bind the caching behavior to the methods to use NCache as a Caching Provider for Spring.

Summary

This provides a comprehensive guide on optimizing the scalability of Spring Boot applications through the integration of NCache Java Edition. The content delves into the various features and strategies offered by NCache, emphasizing its role as a distributed caching solution. The article highlights the benefits of reducing database trips, improving application responsiveness, and achieving dynamic scalability by seamlessly incorporating NCache into Spring Boot projects.

It navigates readers through essential configurations, such as cache initialization and custom key generation, while emphasizing the advantages of a Java-based bean definition over XML. Overall, the article serves as a valuable resource for developers seeking to enhance the scalability and performance of their Spring Boot applications using NCache Java Edition.

You can download the sample here.  Experiment with the NCache integration with Java using NCache playground.


Similar Articles