Spring Boot Apache Kafka Tutorial: Practical Example

Spring-boot-apache-kafka

Introduction:

When we need to reuse the logic of one application in another application, we often turn to web services or RESTful services. However, if we want to asynchronously share data from one application to another, message queues, and in particular, Spring Boot Apache Kafka, come to the rescue.

Spring Boot Apache Kafka

Message queues operate on a publish-subscribe (pub-sub) model, where one application acts as a publisher (sending data to the message queue), and another acts as a subscriber (receiving data from the message queue). Several message queue options are available, including JMS, IBM MQ, RabbitMQ, and Apache Kafka.

Apache Kafka is an open-source distributed streaming platform designed to handle such scenarios.

Kafka Cluster As Kafka is a distributed system, it functions as a cluster consisting of multiple brokers. A Kafka cluster should have a minimum of three brokers. The diagram below illustrates a Kafka cluster with three brokers:

Apache Kafka Architecture

Spring Boot Kafka Architecture

Kafka Broker A Kafka broker is essentially a Kafka server. It serves as an intermediary, facilitating communication between producers (data senders) and consumers (data receivers). The following diagram depicts a Kafka broker in action:

Kafka Broker Architecture

Kafka Broker Architecture

Main APIs in Spring Boot Apache Kafka

  1. Producer API: Responsible for publishing data to the message queue.
  2. Consumer API: Deals with consuming messages from the Kafka queue.
  3. Streams API: Manages continuous streams of data.
  4. Connect API: Handles connections with Kafka (used by both producers and subscribers).
  5. Admin API: Manages Kafka topics, brokers, and related configurations.

Steps:

Step 1: Download and Extract Kafka

Begin by downloading Kafka from this link and extracting it to your desired location.

Step 2: Start the ZooKeeper Server

The ZooKeeper server provides the environment for running the Kafka server. Depending on your operating system:

For Windows, open a command prompt, navigate to the Kafka folder, and run:

Bash
bin\windows\zookeeper-server-start.bat config\zookeeper.properties

For Linux/Mac, use the following command:

Bash
bin/zookeeper-server-start.sh config/zookeeper.properties

ZooKeeper runs on port 2181.

Step 3: Start the Kafka Server

After starting ZooKeeper, run the Kafka server with the following command for Windows:

Bash
bin\windows\kafka-server-start.bat config\server.properties

For Linux/Mac, use the following command:

Bash
bin/kafka-server-start.sh config/server.properties

Kafka runs on port 9092.

Step 4: Create a Kafka Topic

You can create a Kafka topic using two methods:

4.1. Using Command Line:

Open a command prompt or terminal and run the following command for Windows:

Bash
bin\windows\kafka-topics.bat --create --topic student-enrollments --bootstrap-server localhost:9092

Replace “student-enrollments” with your desired topic name.

For Linux/Mac:

Bash
bin/kafka-topics.sh --create --topic student-enrollments --bootstrap-server localhost:9092

4.2. From the Spring Boot Application (Kafka Producer):

For this, we’ll create a Kafka producer application that will programmatically create a topic.

Step 5: Setting Up a Spring Boot Kafka Producer

Step 5.1: Add Dependencies

In your Spring Boot project, add the following dependencies to your pom.xml or equivalent configuration:

XML
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

Step 5.2: Configure Kafka Producer Properties

Add the following Kafka producer properties to your application.properties or application.yml:

Java
# Producer Configurations
spring.kafka.producer.bootstrap-servers=localhost:9092
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer

Step 5.3: Enable Retry

Add the @EnableRetry annotation to your application class to enable event retrying:

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

Step 5.4: Create Kafka Topics

Configure Kafka topics in a KafkaConfig.java class:

Java
@Configuration
public class KafkaConfig {
    public static final String FIRST_TOPIC = "student-enrollments";
    public static final String SECOND_TOPIC = "student-grades";
    public static final String THIRD_TOPIC = "student-achievements";
    
    @Bean
    List<NewTopic> topics() {
        List<String> topicNames = Arrays.asList(FIRST_TOPIC, SECOND_TOPIC, THIRD_TOPIC);
        return topicNames.stream()
            .map(topicName -> TopicBuilder.name(topicName).build())
            .collect(Collectors.toList());
    }
}

Step 5.5: Create a Producer Service:

Implement a ProducerService.java to send messages:

Java
@Service
public class ProducerService {

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    @Retryable(maxAttempts = 3)
    public CompletableFuture<SendResult<String, String>> sendMessage(String topicName, String message) {
        return this.kafkaTemplate.send(topicName, message);
    }
}

Step 5.6: Create a Student Bean Define a Student class with appropriate getters, setters, and a constructor.

Java
public class Student {
	private String name;
	private String email;
	
	//accessors
}

Step 5.7: Create a Kafka Controller Create a controller to produce messages:

Java
@RestController
public class KafkaController {
    @Autowired
    private ProducerService producerService;
    
    @PostMapping("/produce")
    public ResponseEntity<String> produce(@RequestParam String topicName, @RequestBody Student student)
            throws InterruptedException, ExecutionException {
        String successMessage = null;
        producerService.sendMessage(topicName, "Producing Student Details: " + student);
        successMessage = String.format(
                "Successfully produced student information to the '%s' topic. Please check the consumer.", topicName);
        return ResponseEntity.status(HttpStatus.OK).body(successMessage);
    }
}

Step 6: Spring Boot Consumer Application

You can consume Kafka events/topics in two ways:

Step 6.1: Using Command Line

To consume messages using the command line for Windows, use the following command:

Bash
bin\windows\kafka-console-consumer.bat --topic student-enrollments --from-beginning --bootstrap-server localhost:9092

Step 6.2: Building a Consumer Application

To build a consumer application, follow these steps:

Step 6.2.1: Create a Spring Boot Project Create a Spring Boot project with an application class.

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

Step 6.2.2: Create a Kafka Consumer

Implement a Kafka consumer class to consume messages:

Java
@Service
public class KafkaConsumer {
    @KafkaListener(topics = {"student-enrollments", "student-grades", "student-achievements"}, groupId = "group-1")
    public void consume(String value) {
        System.out.println("Consumed: " + value);
    }
}

Step 6.2.3: Configure Kafka Consumer Properties

Configure Kafka consumer properties in application.properties or application.yml:

Java
server.port=8089
spring.kafka.consumer.bootstrap-servers=localhost:9092
spring.kafka.consumer.group-id=group-1
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer

Step 6.2.4: Run Your Kafka Consumer Application

Make sure to follow each step carefully, and don’t miss any instructions. This guide should help beginners set up and use Apache Kafka with Spring Boot effectively

Now that you’ve set up your Kafka producer and Kafka consumer applications, it’s time to run them.

Execute both the Producer and Consumer applications. In the Producer application, make a request to the following endpoint: http://localhost:8080/produce?topicName=student-enrollments. You will observe the corresponding output in the Consumer application and in the console when you are subscribed to the same “student-enrollments” topic.

Spring Boot Kafka Producer

To monitor the topic from the console, use the following command:

Bash
bin\windows\kafka-console-consumer.bat --topic student-enrollments --from-beginning --bootstrap-server localhost:9092
Spring Boot kafka Consumer Output

You can follow the same process to produce messages for the remaining topics, “student-enrollments” and “student-achievements,” and then check the corresponding output.

Conclusion

To recap, when you need to asynchronously share data between applications, consider using Apache Kafka, a message queue system. Kafka functions in a cluster of brokers, and this guide is aimed at helping beginners set up Kafka with Spring Boot. After setup, run both producer and consumer applications to facilitate data exchange through Kafka.

For more detailed information on the Kafka producer application, you can clone the repository from this link: Kafka Producer Application Repository.

Similarly, for insights into the Kafka consumer application, you can clone the repository from this link: Kafka Consumer Application Repository.

These repositories provide additional resources and code examples to help you better understand and implement Kafka integration with Spring Boot.

Spring Boot API Gateway Tutorial

Spring-Boot-API-Gateway

1. Introduction to Spring Boot API Gateway

In this tutorial, we’ll explore the concept of a Spring Boot API Gateway, which serves as a centralized entry point for managing multiple APIs in a microservices-based architecture. The API Gateway plays a crucial role in handling incoming requests, directing them to the appropriate microservices, and ensuring security and scalability. By the end of this tutorial, you’ll have a clear understanding of how to set up a Spring Boot API Gateway to streamline your API management.

2. Why Use an API Gateway?

In a microservices-based architecture, your project typically involves numerous APIs. The API Gateway simplifies the management of all these APIs within your application. It acts as the primary entry point for accessing any API provided by your application.

Spring Boot API Gateway

3. Setting Up the Spring Boot API Gateway

To get started, you’ll need to create a Spring Boot application for your API Gateway. Here’s the main class for your API Gateway application:

Java
package com.javadzone.api.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

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

In this class, we use the @SpringBootApplication annotation to mark it as a Spring Boot application. Additionally, we enable service discovery by using @EnableDiscoveryClient, which allows your API Gateway to discover other services registered in the service registry.

3.1 Configuring Routes

To configure routes for your API Gateway, you can use the following configuration in your application.yml or application.properties file:

YAML
server:
  port: 7777
  
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: product-service-route
          uri: http://localhost:8081
          predicates:
            - Path=/products/**
        - id: order-service-route  
          uri: http://localhost:8082 
          predicates:
            - Path=/orders/**

In this configuration:

  • We specify that our API Gateway will run on port 7777.
  • We give our API Gateway application the name “api-gateway” to identify it in the service registry.
  • We define two routes: one for the “inventory-service” and another for the “order-service.” These routes determine how requests to specific paths are forwarded to the respective microservices.

3.2 Spring Boot API Gateway Dependencies

To build your API Gateway, make sure you include the necessary dependencies in your pom.xml file:

XML
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bootstrap</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
</dependencies>

4. Running the Microservices

To complete the setup and fully experience the functionality of the Spring Boot API Gateway, you should also run the following components:

4.1. Clone the Repositories:

Clone the repositories for the services by using the following GitHub links:

If you’ve already created the API Gateway using the provided code above, there’s no need to clone it again. You can move forward with starting the services and testing the API Gateway as previously described. if not create api gateway you clone from this repo Spring Boot API Gateway Repository.

You can use Git to clone these repositories to your local machine. For example:

Bash
git clone https://github.com/askPavan/inventory-service.git
git clone https://github.com/askPavan/order-service.git
git clone https://github.com/askPavan/spring-api-gateway.git
git clone https://javadzone.com/eureka-server/

4.2. Build and Run the Services:

For each of the services (Inventory Service, Order Service, Eureka Server) and the API Gateway, navigate to their respective project directories in your terminal.

  • Navigate to the “Services/apis” directory.
  • Build the application using Maven:
Bash
mvn clean install

You can begin running the services by executing the following command:

Bash
java -jar app-name.jar

Please replace “app-name” with the actual name of your API or service. Alternatively, if you prefer, you can also start the services directly from your integrated development environment (IDE).

4.3. Start Eureka Server:

You can run the Eureka Server using the following command:

Bash
java -jar eureka-server.jar

Make sure that you’ve configured the Eureka Server according to your application properties, as mentioned earlier.

When you access the Eureka server using the URL http://localhost:8761, you will be able to view the services that are registered in Eureka. Below is a snapshot of what you will see.

Spring Boot API Gateway

4.4. Test the API Gateway and Microservices:

Once all the services are up and running, you can test the API Gateway by sending requests to it. The API Gateway should route these requests to the respective microservices (e.g., Inventory Service and Order Service) based on the defined routes.

Get All Products:

When you hit the endpoint http://localhost:7777/products using a GET request, you will receive a JSON response containing a list of products:

JSON
[
    {
        "id": 1,
        "name": "Iphone 15",
        "price": 150000.55
    },
    {
        "id": 2,
        "name": "Samsung Ultra",
        "price": 16000.56
    },
    {
        "id": 3,
        "name": "Oneplus",
        "price": 6000.99
    },
    {
        "id": 4,
        "name": "Oppo Reno",
        "price": 200000.99
    },
    {
        "id": 5,
        "name": "Oneplus 10R",
        "price": 55000.99
    }
]

Get a Product by ID:

When you hit an endpoint like http://localhost:7777/products/{id} (replace {id} with a product number) using a GET request, you will receive a JSON response containing details of the specific product:

JSON
{
    "id": 2,
    "name": "Samsung Ultra",
    "price": 16000.56
}

Create a Product Order:

You can create a product order by sending a POST request to http://localhost:7777/orders/create. Include the necessary data in the request body. For example:

JSON
{
    "productId": 1234,
    "userId": "B101",
    "quantity": 2,
    "price": 1000.6
}

You will receive a JSON response with the order details.

JSON
{
    "id": 1,
    "productId": 1234,
    "userId": "B101",
    "quantity": 2,
    "price": 1000.6
}

Fetch Orders:

To fetch orders, send a GET request to http://localhost:8082/orders. You will receive a JSON response with order details similar to the one created earlier.

JSON
{
    "id": 1,
    "productId": 1234,
    "userId": "B101",
    "quantity": 2,
    "price": 1000.6
}

By following these steps and using the provided endpoints, you can interact with the services and API Gateway, allowing you to understand how they function in your microservices architecture.

For more detailed information about the Spring Boot API Gateway, please refer to this repository: Spring Boot API Gateway Repository.

FAQs

Q1. What is an API Gateway? An API Gateway serves as a centralized entry point for efficiently managing and directing requests to microservices within a distributed architecture.

Q2. How does load balancing work in an API Gateway? Load balancing within an API Gateway involves the even distribution of incoming requests among multiple microservices instances, ensuring optimal performance and reliability.

Q3. Can I implement custom authentication methods in my API Gateway? Absolutely, you have the flexibility to implement custom authentication methods within your API Gateway to address specific security requirements.

Q4. What is the role of error handling in an API Gateway? Error handling within an API Gateway plays a crucial role in ensuring that error responses are clear and informative. This simplifies the process of diagnosing and resolving issues as they arise.

Q5. How can I monitor the performance of my API Gateway in a production environment? To monitor the performance of your API Gateway in a production setting, you can leverage monitoring tools and metrics designed to provide insights into its operational efficiency.

Feel free to reach out if you encounter any issues or have any questions along the way. Happy coding!

Singleton Design Pattern in Java: Handling All Cases

Singleton design pattern in java

The Singleton Design Pattern: A widely-used and classic design pattern. When a class is designed as a singleton, it ensures that only one instance of that class can exist within an application. Typically, we employ this pattern when we need a single global access point to that instance.

1. How to create a singleton class


To make a class a singleton, you should follow these steps:

a) Declare the class constructor as private: By declaring the class constructor as private, you prevent other classes in the application from creating objects of the class directly. This ensures that only one instance is allowed.

b) Create a static method: Since the constructor is private, external classes cannot directly call it to create objects. To overcome this, you can create a static method within the class. This method contains the logic for checking and returning a single object of the class. Since it’s a static method, it can be called without the need for an object. This method is often referred to as a factory method or static factory method.

c) Declare a static member variable of the same class type: In the static method mentioned above, you need to keep track of whether an object of the class already exists. To achieve this, you initially create an object and store it in a member variable. In subsequent calls to the method, you return the same object stored in the member variable. However, member variables cannot be accessed directly in static methods, so you declare the member variable as a static variable to hold the reference to the class’s single instance.

Here’s a sample piece of code to illustrate these concepts:

The UML representation of the singleton pattern is as follows:

Singleton Design Pattern in Java

Important points to keep in mind:

  • The CacheManager() constructor is declared as private.
  • The class contains a static variable named instance.
  • The getInstance() method is static and serves as a factory method for creating instances of the class.
Java
public class CacheManager {

	// Declare a static member of the same class type.
	private static CacheManager instance;

	// Private constructor to prevent other classes from creating objects.
	private CacheManager() {
	}

	// Declare a static method to create only one instance.
	private static CacheManager getInstance() {
		if (instance == null) {
			instance = new CacheManager();
		}
		return instance;
	}
}

We can express the above code in various alternative ways, and there are numerous methods to enhance its implementation. Let’s explore some of those approaches in the sections below.

1.1 Eager Initialization

In the previous code, we instantiated the instance on the first call to the getInstance() method. Instead of deferring instantiation until the method is called, we can initialize it eagerly, well before the class is loaded into memory, as demonstrated below:

Java
public class CacheManager {

	// Instantiate the instance object during class loading.
	private static CacheManager instance = new CacheManager();

	private CacheManager() {
	}

	private static CacheManager getInstance() {
		return instance;
	}
}

1.2 Static Block Initialization

If you are familiar with the concept of static blocks in Java, you can utilize this concept to instantiate the singleton class, as demonstrated below:

Java
public class CacheManager {

	private static CacheManager instance;

	// The static block executes only once when the class is loaded.
	static {
		instance = new CacheManager();
	}

	private CacheManager() {
	}

	private static CacheManager getInstance() {
		return instance;
	}
}

However, the drawback of the above code is that it instantiates the object even when it’s not needed, during class loading.

1.3 Lazy Initialization

In many cases, it’s advisable to postpone the creation of an object until it’s actually needed. To achieve this, we can delay the instantiation process until the first call to the getInstance() method. However, a challenge arises in a multithreaded environment when multiple threads are executing simultaneously; it might lead to the creation of more than one instance of the class. To prevent this, we can declare the getInstance() method as synchronized.

1.4 Override clone() Method and Throw CloneNotSupportedException

To prevent a singleton class from being cloneable, it is recommended to implement the class from the Cloneable interface and override the clone() method. Within this method, we should throw CloneNotSupportedException to prevent cloning of the object. The clone() method in the Object class is protected and not visible outside the class, unless it is overridden. So, it’s important to implement Cloneable and throw an exception in the clone() method.

However, there’s a problem with the above code. After the first call to getInstance(), subsequent calls to the method will still check the instance == null condition, even though it’s not necessary. Acquiring and releasing locks are costly operations, and we should minimize them. To address this issue, we can implement a double-check for the condition.

Additionally, it’s recommended to declare the static member instance as volatile to ensure thread-safety in a multi-threaded environment.

1.5 Serialization and Deserialization Issue

Serialization and deserialization of a singleton class can create multiple instances, violating the singleton rule. To address this, we need to implement the readResolve() method within the singleton class. During the deserialization process, the readResolve() method is called to reconstruct the object from the byte stream. By implementing this method and returning the same instance, we can avoid the creation of multiple objects even during serialization and deserialization.

Now, let’s revisit the provided code to address the issue:

Java
public class CacheSerialization {

	public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
	
		CacheManager cacheManager1 = CacheManager.getInstance();
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
				new File("D:\\cacheManager.ser")));
		oos.writeObject(cacheManager1);

		CacheManager cacheManager2 = null;
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
				new File("D:\\cacheManager.ser")));
		cacheManager2 = (CacheManager) ois.readObject();

		System.out.println("cacheManager1 == cacheManager2 :  " + (cacheManager1 == cacheManager2)); // false
	}
}

In this code, you’re experiencing an issue where cacheManager1 and cacheManager2 instances do not behave as expected after deserialization it return false. This discrepancy indicates the creation of duplicate objects, which contradicts the desired behavior of a singleton pattern.

To resolve this issue, you can rectify your CacheManager class by adding a readResolve() method. This method ensures that only one instance is maintained throughout the deserialization process, thereby preserving the correct behavior of the singleton pattern.

Here is the final version of the singleton class, which addresses all the relevant cases:

Java
import java.io.Serializable;

public class CacheManager implements Serializable, Cloneable {
    private static volatile CacheManager instance;

    // Private constructor to prevent external instantiation.
    private CacheManager() {
    }

    // Method to retrieve the singleton instance.
    private static CacheManager getInstance() {
        if (instance == null) {
            synchronized (CacheManager.class) {
                // Double-check to ensure a single instance is created.
                if (instance == null) {
                    instance = new CacheManager();
                }
            }
        }
        return instance;
    }

    // This method is called during deserialization to return the existing instance.
    public Object readResolve() {
        return instance;
    }

    // Prevent cloning by throwing CloneNotSupportedException.
    @Override
    public Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }
}

In conclusion, the provided code defines a robust implementation of the Singleton Design Pattern in Java. It guarantees that only one instance of the CacheManager class is created, even in multithreaded environments, thanks to double-checked locking and the use of the volatile keyword.

Moreover, it addresses potential issues with serialization and deserialization by implementing the readResolve() method, ensuring that only a single instance is maintained throughout the object’s lifecycle. Additionally, it prevents cloning of the singleton object by throwing CloneNotSupportedException in the clone() method.

Conclusion: Ensuring Singleton Design Pattern Best Practices

In summary, this code exemplifies a well-rounded approach to creating and safeguarding a singleton class while adhering to best practices and design principles.

Java 21 Features With Examples

Java 21 features with examples

Java 21 brings some exciting new features to the world of programming. In this article, we’ll explore these Java 21 features with practical examples to make your Java coding experience even better.

Please download OpenJDK 21 and add it to the PATH environment variable before switching to Java 21.

Java 21 Features:

1. Pattern Matching for Switch

Java 21 brings a powerful feature called Pattern Matching for Switch. It simplifies switch statements, making them more concise and readable. Check out an example:

Before java 21

// Before Java 21
String response = "yes";

switch (response) {
    case "yes":
    case "yeah":
        System.out.println("You said yes!");
        break;
    case "no":
    case "nope":
        System.out.println("You said no!");
        break;
    default:
        System.out.println("Please choose.");
}

In Java 21, you can rewrite the code provided above as follows:

// Java 21 Pattern Matching for Switch
String response = "yes";
switch (response) {
    case "yes", "yeah" -> System.out.println("You said yes!");
    case "no", "nope" -> System.out.println("You said no!");
    default -> System.out.println("Please choose.");
}

Explore more about Pattern Matching for Switch in the full article.

2. Unnamed Patterns and Variables

Java 21 introduces Unnamed Patterns and Variables, making your code more concise and expressive. Here is a short part to show you an example:

String userInput = "User Input"; 

try { 
    int number = Integer.parseInt(userInput);
    // Use 'number'
} catch (NumberFormatException ex) { 
    System.out.println("Invalid input: " + userInput);
}

Now, with Java 21, the above code can be rewritten as follows

String userInput = "User Input"; 

try { 
    int number = Integer.parseInt(userInput);
    // Use 'number'
} catch (NumberFormatException _) { 
    System.out.println("Invalid input: " + userInput);
}

In this updated version, we no longer use the ‘ex’ variable; instead, we’ve replaced it with an underscore (_). This simple change helps streamline the code and makes it more concise.

For a deep dive into this feature and more practical examples, visit the full article.

3. Unnamed Classes and Instance Main Methods

Java 21 introduces a fresh approach to defining classes and instance main methods right in your code. Let’s take a quick look at how this feature operates:

// Java 21 Examples of Classes Without Names and Main Methods Inside Instances
public class UnnamedClassesDemo {
    void main(String[] args) {
        System.out.println("Hello from an unnamed class!");
    }
}

Explore more about unnamed classes and instance main methods in the full article.

4. String Templates in Java

Java 21 introduces String Templates, simplifying string concatenation. Take a look:

// Java (using String.format)
String name = "Sachin P";
String message = String.format("Welcome %s", Java);

In Java 21, you can create a message using this syntax:

String name = "Sachin P";
String message = STR."Welcome  \{name}!";

Discover the power of string templates and practical examples in the full article.

5. Sequenced Collections in Java 21

Java 21 introduces Sequenced Collections, making it easier to work with ordered data. Here’s a glimpse:

List<Integer> list = new ArrayList<Integer>(); 
	list.add(0);
	list.add(1);
	list.add(2);
	
	// Fetch the first element (element at index 0)
	int firstElement = list.get(0);
	
	// Fetch the last element
	int lastElement = list.get(list.size() - 1);

In Java 21, you can retrieve elements using the following code.

List<Integer> list = new ArrayList<Integer>(); 
	list.add(0);
	list.add(1);
	list.add(2);
	
	// Fetch the first element (element at index 0)
	int firstElement = list.getFirst();
	
	// Fetch the last element
	int lastElement = list.getLast();

Learn more about SequencedCollection, SequencedSet and SequencedMap and explore practical examples in the full article.

To put it simply, Java 21 brings some exciting improvements to the language. Features like Unnamed Patterns and Variables, along with Pattern Matching for Switch, make coding easier and improve code readability. These enhancements make Java development more efficient and enjoyable. Java developers now have the tools to write cleaner and more expressive code, marking a significant step forward in the world of Java programming.

If you’re curious to explore more features and details about Java 21, I recommend checking out the official Java release notes available at this link: Java 21 Release Notes. These release notes provide comprehensive information about all the changes and enhancements introduced in Java 21.

Java 21 Pattern Matching for Switch Example

Java has been constantly evolving to meet the demands of modern programming. With the release of Java 21, a notable feature called Java 21 Pattern Matching for Switch has been introduced. In this article, we’ll explore what this feature is all about, how it works, and see some real-world examples to understand its practical applications.

Introducing Java 21’s Pattern Matching for Switch

Java 21 brings a significant improvement known as Pattern Matching for Switch, which revolutionizes the way we handle switch statements. This feature makes code selection more straightforward by letting us use patterns in case labels. It not only improves code readability but also reduces redundancy and simplifies complex switch statements.

How Pattern Matching Improves Switch Statements

Pattern Matching allows developers to utilize patterns in case labels, making it easier to match and extract components from objects. This eliminates the need for casting and repetitive instanceof checks, resulting in cleaner and more efficient code. Let’s dive into some practical examples to understand how Pattern Matching functions in real-world scenarios.

Practical Examples

Example 1: Matching a Specific Value

Consider a scenario where you need to categorize shapes based on their names. In traditional switch statements, you might do the following:

switch (shape) {
    case "circle":
        System.out.println("Handling circle logic");
        break;
    case "rectangle":
        System.out.println("Handling rectangle logic");
        break;
    case "triangle":
        System.out.println("Handling triangle logic");
        break;
    default:
        // Handle other cases
}

With Pattern Matching, you can simplify above code:

switch (shape) {
    case "circle" -> {
    	 System.out.println("Handling circle logic");
    }
    case "rectangle" -> {
        System.out.println("Handling rectangle logic");
    }
    case "triangle" -> {
       System.out.println("Handling triangle logic");
    }
    default -> {
        // Handle other cases
    }
}

Pattern Matching allows for a more concise and readable switch statement.

Example 2: Matching Complex Objects

Pattern Matching can also simplify code when dealing with complex objects. Suppose you have a list of vehicles, and you want to perform specific actions based on the vehicle type:

for (Object v : vehicles) {
    if (v instanceof Car) {
        Car car = (Car) v;
        //car logic
    } else if (v instanceof Scooter) {
        Scooter scooter = (Scooter) v;
        //scooter logic
    } else if (v instanceof Jeep) {
        Jeep jeep = (Jeep) v;
        //jeep logic
    }
}

The code above can be rewritten using Pattern Matching.

for (Object v : vehicles) {

    return switch (v) {
        case Car car -> {
            //car logic
        }
        case Scooter scooter -> {
            //scooter logic
        }
        case Jeep jeep -> {
            //jeep logic
        }
    }
}

Pattern Matching simplifies the code and eliminates the need for explicit casting.

Example 3: Java 21 – Handling Null Cases in Switch Statements

Before Java 21, switch statements and expressions posed a risk of throwing NullPointerExceptions when the selector expression was evaluated as null.

public void handleGreetings(String s) {
 // If 's' is null and we don't handle it, it will result in a NullPointerException.
    if (s == null) {
        System.out.println("No message available.");
        return;
    }
    switch (s) {
        case "Hello", "Hi" -> System.out.println("Greetings!");
        case "Bye" -> System.out.println("Goodbye!");
        default -> System.out.println("Same to you!");
    }
}

Java 21 Introduces a New Null Case Label. above code can rewritten like this

public void handleGreetingsInJava21(String s) {
    switch (s) {
        case null           -> System.out.println("No message available.");
        case "Hello", "Hi" -> System.out.println("Hello there!");
        case "Bye"         -> System.out.println("Goodbye!");
        default            -> System.out.println("Same to you!");
    }
}

Example 4: Java 21 Pattern Matching with Guards

In Java 21, pattern case labels can apply to multiple values, leading to conditional code on the right-hand side of a switch rule. However, we can now simplify our code using guards, allowing ‘when’ clauses in switch blocks to specify guards to pattern case labels.

Before Java 21.

public void testInput(String response) {

    switch (response) {
        case null -> System.out.println("No message available.");
        case String s when s.equalsIgnoreCase("MAYBE") -> {
            System.out.println("Not sure, please decide.");
        }
        case String s when s.equalsIgnoreCase("EXIT") -> {
            System.out.println("Exiting now.");
        }
        default -> System.out.println("Please retry.");
    }
}

Using Java 21 – Simplified Code

public void test21Input(String response) {

    switch (response) {
        case null -> System.out.println("No message available.");
        case String s when s.equalsIgnoreCase("MAYBE") -> {
            System.out.println("Not sure, please decide.");
        }
        case String s when s.equalsIgnoreCase("EXIT") -> {
            System.out.println("Exiting now.");
        }
        default -> System.out.println("Please retry.");
    }
}

With Java 21’s new features, your code becomes more concise and easier to read, making pattern matching a powerful tool in Java programming toolkit.

Benefits of Java 21

  1. Improved code readability
  2. Reduced boilerplate code
  3. Simplified complex switch statements
  4. Enhanced developer productivity

In conclusion, Java 21 Pattern Matching for Switch is a valuable addition to the Java language, making code selection more straightforward and efficient. By using patterns in switch statements, developers can write cleaner, more concise, and more readable code, ultimately improving software quality and maintainability.

For additional information on pattern matching in Java, you can visit the following link: Pattern Matching (JEP 441) – OpenJDK. This link provides detailed information about the Java Enhancement Proposal (JEP) for pattern matching in Java.

Java 21 Unnamed Patterns and Variables with Examples

Java 21 Unnamed Patterns and Variables is introduced as a preview feature JEP-443 that simplifies data processing. It enables the use of unnamed patterns and variables, denoted by an underscore character (_), to match components within data structures without specifying their names or types. Additionally, you can create variables that are initialized but remain unused in the code.

Let’s break this down in simpler terms:

Introduction:

Before we dive into the world of Java records, let’s consider a situation where the conciseness of code
presents a challenge. In this instance, we will work with two record types: “Team” and “Member.”

record ProjectInfo(Long projectID, String projectName, Boolean isCompleted) {
  // Constructor and methods (if any)
}

record TeamMemberInfo(Long memberID, String memberName, LocalDate joinDate, Boolean isActive, ProjectInfo projectInfo) {
  // Constructor and methods (if any)
}

In Java, records provide a streamlined approach to create immutable data structures, particularly suitable for storing plain data. They eliminate the need for traditional getter and setter methods.

Now, let’s delve into how record patterns can simplify code by deconstructing instances of these records into their constituent components.

TeamMemberInfo teamMember = new TeamMemberInfo(101L, "Alice", LocalDate.of(1985, 8, 22), true, projectInfo);

if (teamMember instanceof TeamMemberInfo(Long id, String name, LocalDate joinDate, Boolean isActive, ProjectInfo projInfo)) {
  System.out.printf("Team member %d joined on %s.", id, joinDate); 
  //Team member 101 joined on 1985-8-22
}

When working with record patterns, it’s often the case that we require only certain parts of the record and not all of them.
In above example, we exclusively used the “id” and “joinDate” components.
The presence of other components such as “name,” “isActive,” and “projInfo” doesn’t enhance clarity; instead, they add brevity without improving readability.

In Java 21, this new feature is designed to eliminate this brevity.

Exploring Unnamed Patterns and Variables

In Java 21, a new feature introduces the use of underscores (_) to represent record components and local variables, indicating our lack of interest in them.

With this new feature, we can revise the previous example more concisely as shown below.
It’s important to observe that we’ve substituted the “name,” “isActive,” and “projInfo” components with underscores (_).

if (teamMember instanceof TeamMemberInfo(Long id, _, LocalDate joinDate, _, _)) {
  System.out.printf("Team member %d joined on %s.", id, joinDate); //Team member 101 joined on 1985-8-22
}

In a similar manner, we can employ the underscore character with nested records when working with the TeamMemberInfo record,
especially when we don’t need to use certain components. For example, consider the following scenario where we only
require the team member’s ID for specific database operations, and the other components are unnecessary.

if (teamMember instanceof TeamMemberInfo(Long id, _, _, _, _)) {
  // Utilize the team member's ID
  System.out.println("Team Member ID is: " + id);  //Team Member ID is: 101
}

In this code, the underscore (_) serves as a placeholder for the components we don’t need to access
within the TeamMemberInfo record.

Starting from Java 21, you can use unnamed variables in these situations:

  1. Within a local variable declaration statement in a code block.
  2. In the resource specification of a ‘try-with-resources’ statement.
  3. In the header of a basic ‘for’ statement.
  4. In the header of an ‘enhanced for loop.’
  5. As an exception parameter within a ‘catch’ block.
  6. As a formal parameter within a lambda expression.

Java 21 Unnamed Patterns and Variables Practical Examples

Let’s dive into a few practical examples to gain a deeper understanding.

Example 1: Local Unnamed Variable

Here, we create a local unnamed variable to handle a situation where we don’t require the result.

int _ = someFunction(); // We don't need the result

Example 2: Unnamed Variable in a ‘catch’ Block

In this case, we use an unnamed variable within a ‘catch’ block to handle exceptions without utilizing the caught value.

String userInput = "Your input goes here"; 

try { 
    int number = Integer.parseInt(userInput);
    // Use 'number'
} catch (NumberFormatException _) { 
    System.out.println("Invalid input: " + userInput);
}

Example 3: Unnamed Variable in a ‘for’ Loop

In the following example, we employ an unnamed variable within a simple ‘for’ loop, where the result of the runOnce() function is unused.

for (int i = 0, _ = runOnce(); i < array.length; i++) {
  // ... code that utilizes 'i' ...
}

Example 4: Unnamed Variable in Lambda Expression

// Define a lambda expression with an unnamed parameter
 Consumer<String> printMessage = (_) -> {
 		System.out.println("Hello, " + _);
 };

// Use the lambda expression with an unnamed parameter
printMessage.accept("John"); //Hello, John

Example 5: Unnamed Variable in try-with-resources

try (var _ = DatabaseConnection.openConnection()) {
    ... no use of the established database connection ...
}

In all the above examples, where the variables remain unused and their names are irrelevant, we simply declare them without providing a name, using the underscore (_) as a placeholder. This practice enhances code clarity and reduces unnecessary distractions.

Conclusion
Java 21 introduces a convenient feature where you can use underscores (_) as placeholders for unnamed variables. This simplifies your code by clearly indicating that certain variables are intentionally unused within their specific contexts. You can apply unnamed variables in multiple situations, such as local variable declarations, ‘try-with-resources’ statements, ‘for’ loop headers, ‘enhanced for’ loops, ‘catch’ block parameters, and lambda expressions. This addition to Java 21 improves code readability and helps reduce unnecessary clutter when you need to declare variables but don’t actually use them in your code.

Java 21 Unnamed Classes and Instance Main Methods

Java is evolving to make it easier for beginners to start coding without the complexity of large-scale programming. With the introduction of Unnamed Classes in Java 21, this enhancement allows students to write simple programs initially and gradually incorporate more advanced features as they gain experience. This feature aims to simplify the learning curve for newcomers.

Simplifying a Basic Java Program

Think about a straightforward Java program, like one that calculates the sum of two numbers:

public class AddNumbers { 

    public static void main(String[] args) { 
        int num1 = 5;
        int num2 = 7;
        int sum = num1 + num2;
        System.out.println("The sum is: " + sum); //12
    }
}

This program may appear more complicated than it needs to be for such a simple task. Here’s why:

  • The class declaration and the mandatory public access modifier are typically used for larger programs but are unnecessary here.
  • The String[] args parameter is designed for interacting with external components, like the operating system’s shell. However, in this basic program, it serves no purpose and can confuse beginners.
  • The use of the static modifier is part of Java’s advanced class-and-object model. For beginners, it can be perplexing. To add more functionality to this program, students must either declare everything as static (which is unconventional) or Learn about static and instance members and how objects are created.

In Java 21, making it easier for beginners to write their very first programs without the need to understand complex features designed for larger applications. This enhancement involves two key changes

1. Instance Main Methods:

The way Java programs are launched is changing, allowing the use of instance main methods. These methods don’t need to be static, public, or have a String[] parameter. This modification enables simplifying the traditional “Hello, World!” program to something like this:

class GreetingProgram {
    void greet() {
        System.out.println("Hello, World!");
    }
}

Execute the program using the following command: java --source 21 --enable-preview GreetingProgram.java

Output

Hello, World!

2. Unnamed Classes:

Java programmers introducing unnamed classes to eliminate the need for explicit class declarations, making the code cleaner and more straightforward:

void main() {
    System.out.println("Welcome to Java 21 Features");
}

Save this file with a name of your choice, then run the program using the following command: java --source 21 --enable-preview YourFileName.java

Ensure that you replace “YourFileName” with the actual name of your file.

Output:

Welcome to Java 21 Features

Please find the reference output below.

Java 21 Unnamed Classes and Instance Main Methods

Please note that these changes are part of a preview language feature, and they are disabled by default. To try them out in JDK 21, you can enable preview features using the following commands:

Bash
Compile the program with: javac --release 21 --enable-preview FileName.java

run it with: java --source 21 --enable-preview FileName.java

You can find more information about these features on the official OpenJDK website by visiting the following link: Java Enhancement Proposal 443 (JEP 443).

To sum it up, Java 21 is bringing some fantastic improvements to make programming more beginner-friendly and code cleaner. With the introduction of instance main methods and unnamed classes, Java becomes more accessible while maintaining its strength. These changes mark an exciting milestone in Java’s evolution, making it easier for newcomers to dive into coding. Since these features are in preview, developers have the opportunity to explore and influence the future of Java programming.

Java String Templates in Java 21: Practical Examples

What exactly is a String Template?

Template strings, often known as Java string templates, are a common feature found in many programming languages, including TypeScript template strings and Angular interpolation. Essentially, they allow us to insert variables into a string, and the variable values are determined at runtime. As a result, Java string templates generate varying output based on the specific values of the variables.

Here are examples of Java string templates with different greetings and names:

// TypeScript
const nameTS = "John";
const messageTS = `Welcome ${nameTS}!`;

// Angular
const nameAngular = "Jane";
const messageAngular = `Welcome {{ ${nameAngular} }}!`;

// Python
namePython = "Alice"
messagePython = "Welcome {namePython}!"

// Java (using String.format)
String nameJava = "Bob";
String messageJava = String.format("Welcome %s", nameJava);

Each of the examples provided above will give you the same result when used with the same ‘name’ variable. JEP-430 is an effort to introduce template string support in the Java programming language, much like what you see here:

In Java 21, you can create a message using this syntax:

String name = "Bob";
String message = STR."Welcome  \{name}!";

String Templates in the Java Language

The Old-Fashioned Way

String formatting in Java is not a new concept. Historically, programmers have employed various methods to create formatted strings, including string concatenation, StringBuilder, String.format(), and the MessageFormat class.

public class WelcomeMessage {

    public static void main(String[] args) {
        String message;
        String name = "John";

        // Concatenate a welcome message
        message = "Welcome " + name + "!";

        // Use String.format for formatting
        message = String.format("Welcome %s!", name);

        // Format using MessageFormat
        message = new MessageFormat("Welcome {0}!").format(new Object[] { name });

        // Construct efficiently with StringBuilder
        message = new StringBuilder().append("Welcome ").append(name).append("!").toString();

        // Display the final welcome message
        System.out.println(message);
    }
}

the output for each method will be the same, and it will display:

Welcome John!

Java String Templates in Java 21: Secure Interpolation

Java 21 has introduced template expressions, drawing inspiration from other programming languages. These expressions enable dynamic string interpolation during runtime. What sets Java’s approach apart is its focus on minimizing security risks, particularly when handling string values within SQL statements, XML nodes, and similar scenarios.

In terms of syntax, a template expression resembles a regular string literal with a specific prefix:

// Code Example
String message = STR."Greetings \{name}!";

In this context:

  • STR represents the template processor.
  • There is a dot operator (.) connecting the processor and the expression.
  • The template string contains an embedded expression in the form of {name}.
  • The outcome of the template processor, and consequently the result of evaluating the template expression, is often a String—although this isn’t always the case.

Template Processors in Java 21

In the world of Java, you’ll encounter three distinct template processors:

STR: This processor takes care of standard interpolation, making it a versatile choice for string manipulation.

FMT: Unlike its counterparts, FMT not only performs interpolation but also excels at interpreting format specifiers located to the left of embedded expressions. These format specifiers are well-documented within Java’s Formatter class.

RAW: RAW stands as a steadfast template processor, primarily generating unprocessed StringTemplate objects.

Here’s an example demonstrating how each of these processors can be utilized:

Here’s an example demonstrating how each of these processors can be utilized:

import static java.lang.StringTemplate.STR;
import static java.lang.StringTemplate.RAW;

public class TemplateProcessorTest {
    public static void main(String[] args) {
        String name = "JavaDZone";

        System.out.println(STR."Welcome to \{name}");
        System.out.println(RAW."Welcome to \{name}.");
    }
}

To put it into action, execute the following command within your terminal or command prompt:

Bash
java --enable-preview --source 21 TemplateProcessorTest.java

Be sure to substitute “TemplateProcessorTest.java” with the actual name of your Java class.

Performing Arithmetic Operations within Expressions

In Java 21, you have the capability to carry out arithmetic operations within expressions, providing you with the means to compute values and showcase the results directly within the expression itself.

For instance, consider the following code snippet:

int operand1 = 10, operand2 = 20;

String resultMessage = STR."\{operand1} + \{operand2} = \{operand1 + operand2}";  // This will result in "10 + 20 = 30"

You can use multi-line expressions:

For the sake of improving code readability, you can split an embedded expression into multiple lines, emulating the style often seen in nested method calls resembling a builder pattern.

Here’s an example to illustrate this:

System.out.println(STR."The current date is: \{
    DateTimeFormatter.ofPattern("yyyy-MM-dd")
        .format(LocalDateTime.now())
}");

Exploring String Templates in Java 21

The following Java class, StringTemplateTest, serves as an illustrative example of utilizing string templates with the STR template processor. It demonstrates how to integrate string interpolation and various expressions within template strings. Each section is accompanied by a description to provide a clear understanding of the usage.

import static java.lang.StringTemplate.STR;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.LocalTime;

public class StringTemplateTest {

  private static String name = "JavaDZone";
  private String course = "Java21 Features";
  private static int a = 100;
  private static int b = 200;

  public static void main(String[] args) {
  
      // Using variable in template expression.
      System.out.println(STR."Welcome to \{name}");

       // Utilizing a method in the template expression.
      System.out.println(STR."Welcome to \{getName()}");

      
      StringTemplateTest st = new StringTemplateTest();

     // Using non-static variable in the template expression.
      System.out.println(STR."Welcome to \{st.course}");

       // Performing arithmetic operations within the expression.
      System.out.println(STR."\{a} + \{b} = \{a+b}");

        // Displaying the current date using expression
      System.out.println(STR."The current date is: \{DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDateTime.now())}");
      
      }


  public static String getName() {
    return name;
  }
  
}

To put it into action, execute the following command within your terminal or command prompt:

Bash
java --enable-preview --source 21 StringTemplateTest .java

make sure to change “StringTemplateTest.java” with the actual name of your Java class.

Java String Templates

If you attempt to run or compile the StringTemplateTest class using the traditional java or javac methods, you may encounter the following error:

Java String Templates in java 21

This error message indicates that string templates are considered a preview feature in Java, and they are not enabled by default. To enable and utilize string templates in your code, you should use the --enable-preview –source 21 flag when running or compiling your Java program. This flag allows you to take advantage of string templates’ functionality.

In summary, this Java tutorial has explored the concept of string templates in Java. This feature was introduced in Java 21 as a preview, offering a fresh addition to the language’s capabilities. To stay updated on potential improvements and enhancements to this feature, be sure to keep an eye on the Java release notes. Enjoy your learning journey!

Sequenced Collections in java 21: Practical Examples

In the world of Java programming, the introduction of Sequenced Collections in Java 21 has brought significant improvements to existing Collection classes and interfaces. This new feature allows easy access to both the first and last elements of a collection, thanks to the inclusion of default library methods. It also enables developers to obtain a reversed view of the collection with a simple method call.

It’s important to clarify that in this context, “encounter order” does not refer to the physical arrangement of elements within the collection. Instead, it means that one element can be positioned either before (closer to the first element) or after (closer to the last element) another element in the ordered sequence.

Let’s dive deeper into this exciting addition, which has been part of Java since the release of Java 21 JEP-431

These newly introduced interfaces are

  1. SequencedCollection
  2. SequencedSet
  3. SequencedMap

Now, let’s illustrate the power of Sequenced Collections in Java 21 with a practical example:

Example: Managing a Playlist Imagine you’re developing a music streaming application in Java. In this application, you need to maintain a playlist of songs, allowing users to navigate easily between tracks. The introduction of Sequenced Collections becomes incredibly valuable in this scenario.

By utilizing SequencedSet, you can ensure that songs in the playlist maintain a specific order, enabling users to move seamlessly from one song to the next or return to the previous one. Additionally, you can use SequencedCollection to manage song history, making it effortless for users to retrace their listening journey, starting from the first song they played to the most recent one.

This real-life example illustrates how Sequenced Collections in Java 21 can enhance the user experience and streamline the management of ordered data in your applications.

Sequenced Collections in java 21

Sequenced Collections in Java 21 Made Simple

The SequencedCollection interface introduces a set of methods to streamline the addition, retrieval, and removal of elements at both ends of a collection. It also offers the ‘reversed()’ method, which presents a reversed view of the collection. Worth noting is that, apart from ‘reversed()’, all these methods are default methods, accompanied by default implementations

public interface SequencedCollection<E> extends Collection<E> {

    SequencedCollection<E> reversed();
    default void addFirst(E e) {
    }
    default void addLast(E e) {
    }
    default E getFirst() {
    }
    default E getLast() {
    }
    default E removeFirst() {
    }
    default E removeLast() {
    }
}

For instance, consider the following code snippet where we create an ArrayList and perform new sequenced operations on it:

ArrayList<Integer> list = new ArrayList<>();

list.add(10);          // Adds 10 to the list.
list.addFirst(0);      // Adds 0 to the beginning of the list.
list.addLast(20);      // Adds 20 to the end of the list.
System.out.println("list: " + list);        // Output: list: [0, 10, 20]
System.out.println(list.getFirst());         // Output: 0
System.out.println(list.getLast());          // Output: 20
System.out.println(list.reversed());        // Output: [20, 10, 0]

This code demonstrates how Sequenced Collections simplify the management of ordered data within a collection, offering easy access to elements at both ends and providing a convenient method to view the collection in reverse order.

SequencedSet: Streamlined Collection Sorting

The SequencedSet interface is designed specifically for Set implementations, such as LinkedHashSet. It builds upon the SequencedCollection interface while customizing the ‘reversed()’ method. The key distinction lies in the return type of ‘SequencedSet.reversed()’, which is now ‘SequencedSet’.

Sequencedset.class

public interface SequencedSet<E> extends SequencedCollection<E>, Set<E> {
    SequencedSet<E> reversed();  // Overrides and specifies the return type for reversed() method.
}

Example: Using SequencedSet

Let’s explore an example of how to utilize SequencedSet with LinkedHashSet:

import java.util.*;


public class SequencedSetExample {

    public static void main(String[] args) {
      LinkedHashSet<Integer> hashSet = new LinkedHashSet<>(List.of(5, 8, 12, 9, 10));

      System.out.println("LinkedHashSet contents: " + hashSet); // Output: [5, 8, 12, 9, 10]
      // First element in the LinkedHashSet.
      System.out.println("First element: " + hashSet.getFirst()); // Output: 5
      
      // Last element in the LinkedHashSet.
      System.out.println("Last element: " + hashSet.getLast()); // Output: 10
      
      // reversed view of the LinkedHashSet.
      System.out.println("Reversed view: " + hashSet.reversed()); // Output: [10, 9, 12, 8, 5]
    }

}

When you run this class, you’ll see the following output:

YAML
LinkedHashSet contents: [5, 8, 12, 9, 10]
First element: 5
Last element: 10
Reversed view: [10, 9, 12, 8, 5]

SequencedMap: Changing How Maps Are Ordered

Understanding SequencedMap

SequencedMap is a specialized interface designed for Map classes like LinkedHashMap, introducing a novel approach to managing ordered data within maps. Unlike SequencedCollection, which handles individual elements, SequencedMap offers its unique methods that manipulate map entries while considering their access order.

Exploring SequencedMap Features

SequencedMap introduces a set of default methods to enhance map entry management:

  • firstEntry(): Retrieves the first entry in the map.
  • lastEntry(): Retrieves the last entry in the map.
  • pollFirstEntry(): Removes and returns the first entry in the map.
  • pollLastEntry(): Removes and returns the last entry in the map.
  • putFirst(K k, V v): Inserts an entry at the beginning of the map.
  • putLast(K k, V v): Inserts an entry at the end of the map.
  • reversed(): Provides a reversed view of the map.
  • sequencedEntrySet(): Returns a SequencedSet of map entries, maintaining the encounter order.
  • sequencedKeySet(): Returns a SequencedSet of map keys, reflecting the encounter order.
  • sequencedValues(): Returns a SequencedCollection of map values, preserving the encounter order.

Example: Utilizing SequencedMap

LinkedHashMap<Integer, String> hashMap = new LinkedHashMap<>();
        hashMap.put(10, "Ten");
        hashMap.put(20, "Twenty");
        hashMap.put(30, "Thirty");
        hashMap.put(40, "Fourty");
        hashMap.put(50, "Fifty");

        System.out.println("hashmap: " + hashMap);
        // Output: {10=Ten, 20=Twenty, 30=Thirty, 40=Fourty, 50=Fifty}

        hashMap.put(0, "Zero");
        hashMap.put(100, "Hundred");

        System.out.println(hashMap); // {10=Ten, 20=Twenty, 30=Thirty, 40=Fourty, 50=Fifty, 0=Zero, 100=Hundred}

        // Fetching the first entry
        System.out.println("Fetching first entry: " + hashMap.entrySet().iterator().next());
        // Output: Fetching the first entry: 10=Ten

        // Fetching the last entry
        Entry<Integer, String> lastEntry = null;
        for (java.util.Map.Entry<Integer, String> entry : hashMap.entrySet()) {

In the traditional approach, prior to Java 21, working with a LinkedHashMap to manage key-value pairs involved manual iteration and manipulation of the map. Here’s how it was done

LinkedHashMap<Integer, String> hashMap = new LinkedHashMap<>();
        hashMap.put(10, "Ten");
        hashMap.put(20, "Twenty");
        hashMap.put(30, "Thirty");
        hashMap.put(40, "Fourty");
        hashMap.put(50, "Fifty");

        System.out.println("hashmap: " + hashMap);
        // Output: {10=Ten, 20=Twenty, 30=Thirty, 40=Fourty, 50=Fifty}

        hashMap.put(0, "Zero");
        hashMap.put(100, "Hundred");

        System.out.println(hashMap); // {10=Ten, 20=Twenty, 30=Thirty, 40=Fourty, 50=Fifty, 0=Zero, 100=Hundred}


        // Fetching the first entry
        System.out.println("Fetching first entry: " + hashMap.entrySet().iterator().next());
        // Output: Fetching the first entry: 10=Ten


        // Fetching the last entry
        Entry<Integer, String> lastEntry = null;
        for (java.util.Map.Entry<Integer, String> entry : hashMap.entrySet()) {
            lastEntry = entry;
        }
        System.out.println("Fetching last entry: " + lastEntry); // Output: Fetching the last entry: 100=Hundred


        // Removing the first entry
        Entry<Integer, String> removedFirstEntry = hashMap.entrySet().iterator().next();
        hashMap.remove(removedFirstEntry.getKey());
        System.out.println("Removing first entry: " + removedFirstEntry);
        // Output: Removing the first entry: 10=Ten


        hashMap.remove(lastEntry.getKey());
        System.out.println("Removing last entry: " + lastEntry);
        // Output: Removing the last entry: 100=Hundred


        System.out.println("hashMap: " + hashMap);
        // Output after removals: {20=Twenty, 30=Thirty, 40=Fourty, 50=Fifty, 0=Zero}


        LinkedHashMap<Integer, String> reversedMap = new LinkedHashMap<>();
        List<Entry<Integer, String>> entries = new ArrayList<>(hashMap.entrySet());

        Collections.reverse(entries);

        for (Entry<Integer, String> entry : entries) {
            reversedMap.put(entry.getKey(), entry.getValue());
        }


        System.out.println("Reversed view of the map: " + reversedMap);
        // Output: Reversed view of the map: {50=Fifty, 40=Fourty, 30=Thirty, 20=Twenty,
        // 10=Ten}

However, in Java 21, with the introduction of sequenced collections, managing a LinkedHashMap has become more convenient. Here’s the updated code that demonstrates this.

import java.util.LinkedHashMap;


public class SequencedMapExample {
 
    public static void main(String[] args) {
        
       LinkedHashMap<Integer, String> hashMap = new LinkedHashMap<>();
       hashMap.put(10, "Ten");
       hashMap.put(20, "Twenty");
       hashMap.put(30, "Thirty");
       hashMap.put(40, "Fourty");
       hashMap.put(50, "Fifty");

       System.out.println(hashMap); 
       // Output: {10=Ten, 20=Twenty, 30=Thirty, 40=Fourty, 50=Fifty}

       hashMap.putFirst(0, "Zero");
       hashMap.putLast(100, "Hundred");
       
       System.out.println(hashMap); 
       // Output after adding elements at the beginning and end:
       // {0=Zero, 10=Ten, 20=Twenty, 30=Thirty, 40=Fourty, 50=Fifty, 100=Hundred}

       System.out.println("Fetching first entry: " + hashMap.firstEntry());
       // Fetching the first entry: 0=Zero

       System.out.println("Fetching last entry: " + hashMap.lastEntry());
       // Fetching the last entry: 100=Hundred
        
       System.out.println("Removing first entry: " + hashMap.pollFirstEntry());
       // Removing the first entry: 0=Zero

       System.out.println("Removing last entry: " + hashMap.pollLastEntry());
       // Removing the last entry: 100=Hundred

       System.out.println("hashMap: " + hashMap);
       // Output after removals: {10=Ten, 20=Twenty, 30=Thirty, 40=Fourty, 50=Fifty}

       System.out.println("Reversed: " + hashMap.reversed());
       // Reversed view of the map: {50=Fifty, 40=Fourty, 30=Thirty, 20=Twenty, 10=Ten}
    }
}

Conclusion: Simplifying Java 21

Sequenced collections are a valuable addition to Java 21, enhancing the language’s ease of use. These features simplify collection management, making coding in Java 21 even more accessible and efficient. Enjoy the benefits of these enhancements in your Java 21 development journey!

Spring Boot Actuator: 5 Performance Boost Tips

Spring Boot Actuator

Are you ready to take your application to the next level? In the world of software development, it’s not enough to create an application; you also need to ensure it runs smoothly in a production environment. This is where “Spring Boot Actuator” comes into play. In this comprehensive guide, we’ll walk you through the process of enhancing your application’s monitoring and management capabilities using Spring Boot Actuator.

Step 1: Understanding the Need

Why Additional Features Are Essential

After thoroughly testing your application, you’ll likely find that deploying it in a production environment requires more than just functional code. You need features that enable monitoring and management. Traditionally, this might involve maintaining a dedicated support team to ensure your application is always up and running.

Step 2: What is Spring Boot Actuator?

Spring Boot Actuator is a powerful feature bundled with Spring Boot. It provides a set of predefined endpoints that simplify the process of preparing your application for production deployment. These endpoints allow you to monitor and manage various aspects of your application seamlessly.

Step 3: Spring Boot Actuator Endpoints

Spring Boot Actuator offers a variety of endpoints to cater to different monitoring and management needs:

  1. info: Provides arbitrary information about your application, such as author, version, and licensing.
  2. health: Checks the liveness probe of your application to ensure it’s running and accessible.
  3. env: Displays all environment variables used by your application.
  4. configprops: Lists all configuration properties utilized by your application.
  5. beans: Shows all the bean definitions within the IoC container.
  6. thread dump: Provides access to the current JVM thread dump.
  7. metrics: Offers runtime information about your application, including memory usage, CPU utilization, and heap status.
  8. loggers: Displays loggers and their logging levels.
  9. logfile: Shows the application’s log file.
  10. shutdown: Allows for remote application shutdown.
  11. sessions: Presents active HTTP sessions of the web application.
  12. conditions: Shows the conditions that influence auto-configurations.

Step 4: Enabling Actuator Endpoints

Before we can start configuring and using Actuators, we need to add the Actuator dependency to our project pom.xml.

Spring Boot Starter Actuator Dependency

Maven:

XML
<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Gradle:

Groovy
implementation 'org.springframework.boot:spring-boot-starter-actuator'

To make use of these valuable endpoints, you’ll need to enable them by adding the “spring-boot-starter-actuator” dependency to your Spring Boot project. This will grant you access to the endpoints via URLs like “http://localhost:8080/actuator/{endpointId}“.

These endpoints are exposed by Spring Boot in two ways:

  1. JMX: JMX, or Java Management Extensions, is a specification provided by Java as part of J2SE5. It standardizes the API for managing devices, servers, and more. With JMX, you can programmatically manage devices or servers at runtime through JMX extensions. For example, instead of manually configuring a datasource in a WebLogic server through its console, you can automate the datasource configuration on an application server using JMX endpoints exposed by the application server.
  2. HTTP/Web: These are REST endpoints exposed over the HTTP protocol, making them accessible from a web browser or any HTTP client.

However, it’s worth noting that it’s recommended to expose Actuator endpoints through JMX rather than HTTP/Web endpoints due to security reasons. All Actuator endpoints are available for access via both JMX and HTTP/Web by default, and you don’t need to write any special code to enable or support them. You simply need to configure which endpoints you want to expose over which protocol, and Spring Boot Actuator will take care of exposing them accordingly.

To make an endpoint accessible in Spring Boot Actuator, you need to do two things:

  1. Enable the Endpoint
  2. Expose the Endpoint through JMX, HTTP, or Both

By default, all the endpoints of Spring Boot Actuator are enabled, except for the “shutdown” endpoint. If you want to disable these endpoints by default, you can add a property in your application.properties file:

Java
management.endpoints.enabled-by-default=false

Now, you can enable each individual endpoint in a controlled way using the endpoint’s ID, as shown below:

Java
# Enable specific Actuator endpoints
management.endpoint.info.enabled=true
management.endpoint.shutdown.enabled=true
management.endpoint.endpointId.enabled=true

In your application.properties file, you can include the following configuration to expose all the endpoints:

Java
# Expose all endpoints
management.endpoints.web.exposure.include=*

This configuration tells Spring Boot Actuator to include all endpoints for web/HTTP access.

Excluding Specific Actuator Endpoints

Java
# Exclude specific endpoints by their ID
management.endpoints.web.exposure.exclude=shutdown, sessions, conditions

Using application.yaml:

In your application.yaml file, you can include the following configuration to expose all the endpoints:

Java
management:
  endpoints:
    web:
      exposure:
        include: "*"

Next, you’ll need to specify how you want to expose these endpoints, either through JMX or HTTP. By default, only two endpoints, “info” and “health,” are exposed for security reasons. If you want more Actuator endpoints to be accessible, you can configure this using the following properties in either application.properties or application.yaml

In application.properties

Java
# Expose Actuator endpoints for both JMX and HTTP/Web access
management.endpoints.jmx.exposure.include=info, health, env, configProps
management.endpoints.web.exposure.include=info, health, env, configProps

In application.yaml:

Java
management:
  endpoints:
    web: #Web endpoints configuration
      exposure:
        include: info, health, env, configProps
    jmx: #JMX endpoints configuration
      exposure:
        include: info, health, env, configProps

Before we delve into fine-tuning endpoint exposure, let’s make sure your Spring Boot application is up and running.

By testing your application first, you can ensure that everything is set up correctly before customizing Actuator endpoint exposure in the next section.

Step 5: Fine-Tuning Endpoint Exposure

If the predefined endpoints don’t cover your specific needs, you can extend them or create your own. Here’s an example of how to customize the “health” and “info” endpoints:

Java
@Component
class AppHealthEndpoint implements HealthIndicator {
  public Health health() {
    // Perform checks on external or application-dependent resources and return UP or DOWN.
    return Health.Up().build();
  }
}

@Component
class AppInfoEndpoint implements InfoContributor {
  public void contribute(Builder builder) {
    builder.withDetails("key", "value").build();
  }
}

Step 6: Building Custom Endpoints

Actuator endpoints are essentially REST APIs, and you can build your custom endpoints using Spring Boot Actuator API. This is preferable over standard Spring REST controllers because it allows for JMX access and management.

Here’s a simplified example of how to create a custom endpoint:

Java
@Component
@Endpoint(id = "cachereload")
class CacheReloadEndpoint {
  @UpdateOperation
  public int reloadCache(String resource) {
    // Implement your custom logic here.
  }
}

To trigger a cache reload using this custom endpoint, you can send an HTTP PUT request like this:

Bash
http://localhost:8081/actuator/cachereload?resource=cities.properties

Testing Specific Actuator Endpoints

  • Run Your Application: Ensure that your Spring Boot application is running.
  • Access the Info Endpoint: Open a web browser or use a tool like curl to make an HTTP GET request to the following URL:
  1. Info Endpoint (/actuator/info)
Java
http://localhost:8080/actuator/info
JSON
{
    "app": {
        "name": "boot-actuator",
        "version": "1.0.0"
    },
    "author": "Pavan"
}

2. Health Endpoint (/actuator/health)

http://localhost:8080/actuator/health

Spring Boot Actuator health

3. Environment (Env) Endpoint (/actuator/env)

http://localhost:8080/actuator/env

Spring Boot Actuator env

4. Configuration Properties (ConfigProps) Endpoint (/actuator/configprops)

http://localhost:8080/actuator/configprops

These are the expected JSON responses when you make HTTP GET requests to the specified Actuator endpoints.

Conclusion:

In this guide, you’ve learned the essentials of Spring Boot Actuator, enabling you to monitor, manage, and customize your Spring Boot applications effectively. You’ve discovered how to test Actuator endpoints, fine-tune their exposure, and explore the associated GitHub repository for practical insights. Armed with this knowledge, you’re better equipped to maintain robust applications in production environments.

Spring Boot Runners: CommandLine vs Application

Spring-boot-runner-commandlinerunner-applicationrunners

In this comprehensive guide on Spring Boot Runners, we will explore the powerful capabilities of ApplicationRunners and CommandLineRunners. These essential components play a vital role in executing tasks during the startup phase of your Spring Boot application. We will delve into their usage, differences, and how to harness their potential for various initialization tasks.

What Are CommandLineRunners and ApplicationRunners?

Startup activities are essential for preparing an application before it goes into full execution mode. For instance:

1. Data Loading and Cache Initialization

Imagine a scenario where you need to load data from a source system and initialize a cache, which has been configured as a bean definition in the IoC container. This data loading into the cache is a one-time startup activity.

2. Database Schema Creation

In another scenario, you might need to create a database schema by running an SQL script before your application kicks off. Typically, this activity is not performed during JUnit test executions.

In a Spring Core application, handling startup activities is straightforward. You can execute these activities after creating the IoC container but before using it. Here’s an example in Java:

Java
ApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
// Perform startup activities
Tank tank = context.getBean(Tank.class); // Use IoC container
tank.level();

However, in a Spring MVC application, the IoC container is created by the DispatcherServlet and ContextLoaderListener, and you don’t have a chance to execute post-construction activities. This limitation led to the introduction of a unified approach in Spring Boot.

Spring Boot Runners: A Unified Approach

Spring Boot provides a standardized way of starting up Spring applications, be it core or web applications, by using SpringApplication.run(). This method ensures consistent initialization of your application. All startup activities are streamlined by leveraging the SpringApplication class.

To execute startup activities in Spring Boot, SpringApplication offers a callback mechanism through CommandLineRunners and ApplicationRunners. You can write code inside classes that implement these interfaces, overriding their respective methods

Key Differences Between CommandLineRunners and ApplicationRunners

Before we delve into practical examples, let’s understand the key differences between CommandLineRunners and ApplicationRunners:

FeatureCommandLineRunnerApplicationRunner
Access to Command-Line ArgumentsReceives command-line arguments as an array of strings (String[] args) in the run method.Receives command-line arguments as an ApplicationArguments object in the run method, allowing access to both operational and non-operational arguments.
UsageIdeal for simpler cases where access to command-line arguments is sufficient.Suitable for scenarios where more advanced command-line argument handling is required, such as working with non-option arguments and option arguments.
Comparison Between CommandLineRunners and ApplicationRunners

1. CommandLineRunner Example

First, let’s create a CommandLineRunner class. You can place it in a package of your choice, but for this example, we’ll use the package com.runners.

Java
package com.runners;

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

/**
 * @author Pavan Kumar
 */
@Component
public class MyCommandLineRunner implements CommandLineRunner {

	@Override
	public void run(String... args) throws Exception {
		System.out.println("Command-line arguments for CommandLineRunner:");
		for (String arg : args) {
			System.out.println(arg);
		}
	}
}

This class implements the CommandLineRunner interface and overrides the run method. Inside the run method, we print the command-line arguments passed to our application.

2. ApplicationRunner Example

Now, let’s create an ApplicationRunner class. The process is similar to creating the CommandLineRunner class.

Java
package com.runners;

import java.util.List;

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

/**
 * @author Pavan Kumar
 *
 */

@Component
public class MyApplicationRunner implements ApplicationRunner {

	@Override
	public void run(ApplicationArguments args) throws Exception {
		System.out.println("ApplicationRunner Arguments....");
		for (String arg : args.getSourceArgs()) {
			System.out.println(arg);
		}

		System.out.println("Non-option arguments:");
		List<String> nonOptionalList = args.getNonOptionArgs();
		for (String nonOptArgs : nonOptionalList) {
			System.out.println(nonOptArgs);
		}

		System.out.println("Option arguments:");
		for (String optArgName : args.getOptionNames()) {
			System.out.println(optArgName + " : " + args.getOptionValues(optArgName));
		}

	}
}

This class implements the ApplicationRunner interface, where we override the run method. Inside this method, we print command-line arguments obtained from the ApplicationArguments object, enabling effective access to both operational and non-operational arguments.

The MyApplicationRunnerExample class extends the capabilities of ApplicationRunner, displaying both non-option and option arguments.

3. Using CommandLineRunners and ApplicationRunners

Now that you’ve created and integrated CommandLineRunner and ApplicationRunner classes, including MyApplicationRunnerExample, you can use them to execute tasks during your Spring Boot application’s startup.

  1. Run Your Spring Boot Application: Open your command prompt or terminal, navigate to your project directory, and enter the following command to start your Spring Boot application:
Bash
java -jar target/boot-runners-0.0.1-SNAPSHOT.jar arg1, arg2, arg3 --option1=value1 --option2=value2

Replace boot-runners-0.0.1-SNAPSHOT.jar with the actual name of your application’s JAR file.

  1. Observe Output: As your application starts, you’ll notice that all three runner classes (MyCommandLineRunner, MyApplicationRunner) are executed automatically. They will display various command-line arguments passed to your application.

Output:

By following these steps and examples, you’ve successfully implemented CommandLineRunners and ApplicationRunners in your Spring Boot application. You can customize these classes to perform various tasks like initializing databases, loading configurations, or any other startup activities your application may require.

With the flexibility provided by CommandLineRunners and ApplicationRunners, you can tailor your application’s initialization process to meet your specific needs, making Spring Boot a powerful choice for building robust applications.

You can explore more information about Spring Boot Runners on the GitHub repository https://github.com/askPavan/boot-runners where you might find practical examples and code samples related to CommandLineRunners and ApplicationRunners.

Additionally, you can refer to external resources such as:

  1. Spring Boot Documentation: The official Spring Boot documentation provides in-depth information about CommandLineRunners and ApplicationRunners.

Related Articles:

Spring Boot Profiles Mastery: 5 Proven Tips

Spring Boot Profiles

In the world of Spring Boot, it’s important to grasp and make use of Spring Boot Profiles if you want to handle application environments well. Spring Boot profiles are like a key tool that lets you easily switch between different application settings, ensuring that your application can smoothly adjust to the needs of each particular environment. In this guide, we’ll explore the details of Spring Boot profiles and demonstrate how to use them to keep your configurations neat and ready for different environments, even if you’re new to this.

Understanding Spring Boot Profiles

What Are Spring Boot Profiles?

In the context of Spring Boot, Spring Boot Profiles are a fundamental mechanism for handling environment-specific configurations. They empower developers to define and segregate configuration settings for different environments, such as development, testing, and production. Each profile encapsulates configuration values tailored precisely to the demands of a specific environment.

How Do Spring Boot Profiles Work?

Spring Boot Profiles operate on the foundation of the @Profile annotation and a set of configuration classes. These profiles can be activated during application startup, enabling the Inversion of Control (IoC) container to intelligently select and deploy the appropriate configuration based on the active profile. This powerful capability eliminates the need for extensive code modifications when transitioning between different application environments.

Creating Spring Boot Profiles with Annotations

In this section, we’ll explore the creation and management of Spring Boot profiles using annotations. This approach provides a structured and flexible way to handle environment-specific configurations.

Step 1: Create Configuration Classes

Begin by crafting two distinct configuration classes: DevJavaConfig and TestJavaConfig. These classes extend the common BaseConfig class and are adorned with the @Configuration annotation. Additionally, they specify the property sources for their respective profiles.

Java
@Configuration
@PropertySource("classpath:appdev.properties")
@Profile("dev")
class DevJavaConfig extends BaseConfig {
}

Java
@Configuration
@PropertySource("classpath:apptest.properties")
@Profile("test")
class TestJavaConfig extends BaseConfig {
}

Step 2: Define Property Files

Next, define property files, namely application-dev.properties and application-test.properties. These property files contain the database and transaction manager properties tailored to the dev and test profiles.

application-dev.properties file:

Java
# application-dev.properties
db.driverClassname=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/sdb
db.username=root
db.password=root
tm.timeout=10
tm.autocommit=false

application-test.properties file:

Java
# application-test.properties
db.driverClassname=com.jdbc.driver.OracleDriver
db.url=jdbc:oracle:thin:@1521:xe
db.username=root
db.password=root
tm.timeout=10
tm.autocommit=false

Step 3: Set the Active Profile

In the application.properties file, set the active profile to test as an example of profile activation.

spring.profiles.active=test

Step 4: Implement Configuration Classes

In the main application class BootProfileApplication, configure the JdbcTransactionManager bean based on the active profile. The @Bean method injects properties using the Environment bean.

Java
@SpringBootApplication
class BootProfileApplication {
  @Autowired
  private Environment env;
  
  @Bean
  public JdbcTransactionManager jdbcTransactionManager() {
    JdbcTransactionManager jtm = new JdbcTransactionManager();
    
    jtm.setTimeOut(Integer.parseInt(env.getProperty("tm.timeout")));
    jtm.setAutoCommit(Boolean.valueOf(env.getProperty("tm.autocommit")));
    
    return jtm;
  }
  
  public static void main(String[] args) {
    ApplicationContext context = SpringApplication.run(BootProfileApplication.class, args);
    JdbcTransactionManager jtm = context.getBean(JdbcTransactionManager.class);
    System.out.println(jtm);
  }
}

Activating Spring Boot Profiles in Properties File

Alternatively, you can activate Spring profiles directly through the properties file. This approach simplifies the activation process and maintains a clean separation of configuration properties.

Step 1: Specify YAML Property Files with “Spring Profiles Active in YAML File”

In this approach, you define YAML property files for each profile (dev and test) with their respective configuration values.

---
spring:
  profiles:
    active: dev
---
spring:
  profiles: dev   
parcel:
  parcelNo: 123
  sourceAddress: 8485, idkew
  destinationAddress: 903, kdldqq
agent:
  agentNo: 100
  agentName: AAA
  mobileNo: "993"
  emailAddress: "9939393abc@gmail.com"
---
spring:
  profiles: test
parcel:
  parcelNo: 199
  sourceAddress: 9396, idksd
  destinationAddress: 903, kdldqr
agent:
  agentNo: 101
  agentName: BBB
  mobileNo: "969"
  emailAddress: "96969696bcd@gmail.com"

Step 2: Integrate the Dependency into pom.xml

To enhance the configuration capabilities of your Spring Boot application, incorporate the following dependency into your project’s pom.xml file:

XML
<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-configuration-processor</artifactId>
		<optional>true</optional>
</dependency>

Step 3: Instantiate the Agent Bean

Java
// Source code is not available
public class Agent {
    private int agentNo;
    private String agentName;
    private String mobileNo;
    private String emailAddress;

    // Constructors, getters, setters, and any additional methods will go here
}

Step 4: Implement the Parcel Class as Shown Below

Java
@Component
@ConfigurationProperties(prefix = "parcel")
public class Parcel {
	private int parcelNo;
	private String sourceAddress;
	private String destinationAddress;
	@Autowired
	private Agent agent;
}

Step 5: Configure the Application

In your Spring Boot application class BootProfileApplication, create and configure the Agent bean based on the active profile. The properties are obtained from the properties files using the Environment bean.

Java
@SpringBootApplication
class BootProfileApplication {
  @Autowired
  private Environment env;
  
  // The source code is unavailable, necessitating the 
  //creation of a bean using the @Bean annotation.
  @Bean
  public Agent agent() {
    Agent agent = new Agent();
    agent.setAgentNo(Integer.parseInt(env.getProperty("agentNo")));
    agent.setAgentName(env.getProperty("agentName"));
    agent.setMobileNo(env.getProperty("mobileNo"));
    agent.setEmailAddress(env.getProperty("emailAddress"));
    
    return agent;
  }
  
  public static void main(String[] args) {
    ApplicationContext context = SpringApplication.run(BootProfileApplication.class, args);
    Parcel parcel = context.getBean(Parcel.class);
    System.out.println(parcel);
  }
}
  1. Build the Application: Make sure the Spring Boot application is built and ready for execution. This can typically be done using build tools like Maven or Gradle.
  2. Run the Application with a Specific Profile:
    • To run the application with the dev profile, execute the following command in your terminal or IDE:

Spring Profiles Active Command line

Bash
java -Dspring.profiles.active=dev -jar target/your-application.jar

To run the application with the test profile, use this command:

Bash
java -Dspring.profiles.active=test -jar target/your-application.jar
  1. Observe the Output: When the application starts, it will load the configuration specific to the active profile (dev or test). This includes database settings, transaction manager properties, and any other environment-specific configurations.
  2. Review the Output: As the application runs, it may print log messages, information, or the state of specific beans (as indicated by the System.out.println statements in the code). These messages will reflect the configuration loaded based on the active profile.

For example, when running with the dev profile, you might see log messages and information related to the dev environment. Similarly, when using the test profile, the output will reflect the test environment’s configuration.

Example: When Executing the Application with the “dev” Profile, You Will Observe the Following Output:

Conclusion:

Spring Boot profiles enable the seamless configuration of applications for different environments by allowing you to maintain distinct sets of properties. Profiles are activated based on conditions such as environment variables or command-line arguments, providing flexibility and consistency in application configuration across various deployment scenarios.

For additional details about Spring Boot profiles, you can refer to the following link: Spring Boot Profiles Documentation

Related Articles:

Mastering Spring Boot Events: 5 Best Practices

Spring Boot Event Driven Programming

Introduction to Spring Boot Events

In this comprehensive guide, we will explore the world of event-driven programming in Spring Boot. Spring Boot events-driven architecture offers modularity, asynchronous communication, and loose coupling. We’ll cover event concepts, real-time examples, and demonstrate how to run a Spring Boot application with custom event listeners to harness the power of Spring Boot events.

Understanding Event-Driven Programming

Event-driven programming is a powerful paradigm with these key aspects:

1. Loose Coupling and Modularity: Components are decoupled and don’t directly reference each other.

2. Asynchronous Communication: Components communicate by emitting and listening to events, enabling parallel execution.

Key Actors:

  1. Source: Publishes events, initiating actions.
  2. Event: Carries data and context about the source.
  3. Event Handler: Processes specific event types.
  4. Event Listener: Listens for events, identifies handlers, and delegates events for processing.

Real-Time Example:

Imagine a financial application notifying users of transactions via SMS and WhatsApp. We’ll model this with Spring Boot.

Java
class TransactionNotificationEvent extends ApplicationEvent {
  private String mobileNo;
  private String accountNo;
  private String operationType;
  private double operatingAmount;
  private double balance;
  private String atmMachineNo;
  
  public TransactionNotificationEvent(Object source) {
    super(source);
  }
  // Accessors
}  

Meet the TransactionNotificationEvent—an essential player in our financial application. Its job is simple but crucial: to hold all the vital details of a financial transaction. Imagine it as a data-packed envelope, carrying information like mobile numbers, account specifics, and transaction types. Whenever a customer initiates a transaction, this event springs to life, ready to trigger a series of actions in our event-driven system.

Java
class WhatsAppNotificationEventListener implements ApplicationListener<TransactionNotificationEvent> {
  public void onApplicationEvent(TransactionNotificationEvent event) {
    // Read data from the event and send a WhatsApp message to the customer.
  }
}

Introducing the WhatsAppNotificationEventListener—an attentive messenger in our system. Its mission is specific: to ensure customers receive prompt WhatsApp notifications about their transactions. Think of it as the guardian on the lookout for one event—TransactionNotificationEvent. When this event happens, it instantly acts, simulating the process of sending a WhatsApp notification to the customer. This class illustrates how events turn into real-world actions.

Java
class AtmMachine implements ApplicationEventPublisherAware {
  private ApplicationEventPublisher applicationEventPublisher;
  
  public String withdrawal(String accountNo, double amount) {
    // Logic to verify balance, deduct amount, and update the database
    TransactionNotificationEvent event = new TransactionNotificationEvent(this);
    event.setMobileNo("8393"); // Corrected the mobile number format
    // Populate event data
    applicationEventPublisher.publishEvent(event);
  }
  void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
    this.applicationEventPublisher = applicationEventPublisher;
  }
}

And now, let’s meet our digital ATM—AtmMachine. This class embodies the heart of our system. It not only initiates transactions but also ensures their success. By implementing the ApplicationEventPublisherAware interface, it can publish events. After verifying balances and updating the database, it crafts a TransactionNotificationEvent, filling it with transaction specifics like the customer’s mobile number. Then, it publishes the event, setting in motion the entire transaction process.

How to Work with Event-Driven Programming in Spring Framework?

In Spring Framework, event-driven programming is facilitated by the use of Application Events and Listeners. Here’s a simplified example:

AnEvent.java:

Step-1: Creating Spring Boot Events

Create Your Event Class: The journey begins with the creation of the AnEvent class, a crucial step in understanding Spring Boot Events. Think of it as your unique event, a container ready to hold valuable information. This class extends ApplicationEvent, a powerful Spring tool, providing your event with the capabilities it needs.

Java
class AnEvent extends ApplicationEvent {
  // Data to be passed to the handler as part of this event
  public AnEvent(Object source) {
    super(source);
  }
}

Why We Need It: Explore the core purpose behind creating the AnEvent class. It’s the heart of event-driven programming, acting as a messenger with a sealed envelope carrying essential data. Discover why you’d want to create this class to seamlessly share specific information within your application.

Step-2: Spring Boot Event Listeners

The Event’s Trusty Guardian: Get to know the AnEventListener, a vital character in the Spring Boot Events storyline. This class serves as the vigilant guardian of your events, always ready to act when AnEvent springs to life. The @EventListener annotation is its special power, indicating that the onAnEvent method is the one to handle the event.

Java
class AnEventSource {
  @Autowired
  private ApplicationEventPublisher publisher;
  
  public void action() {
    AnEvent event = new AnEvent(this);
    publisher.publishEvent(event);
  }
}

Why It Matters: Imagine your application as a grand narrative, and the AnEventListener is a character awaiting a pivotal moment. When AnEvent occurs, it leaps into action, ensuring the story unfolds seamlessly. Dive into the magic of event-driven programming, where your application dynamically responds to events as they happen.

Spring Boot Application Events & Listeners

During the startup of a Spring Boot application, various activities and stages occur, such as configuring the environment and initializing the IoC container. Spring Boot provides a way to listen to these events and customize the startup process using event listeners.

Types of Events Published by SpringApplication class:

  1. ApplicationStartingEvent: Published before any operation begins when calling SpringApplication.run().
  2. ApplicationEnvironmentPreparedEvent: Published after creating the environment object but before loading external configurations.
  3. ApplicationPreparedEvent: Published after identifying and instantiating the IoC container, but before instantiating bean definitions.
  4. ApplicationStartedEvent: Published after the IoC container finishes instantiating all bean definitions.
  5. ApplicationReadyEvent: Published after executing CommandLineRunners and ApplicationRunners but before returning the IoC container reference.
  6. ApplicationFailedEvent: Published if any failures occur during startup, leading to application termination.

Creating Custom Spring Boot Events

Here’s how you can create a custom listener to handle a specific event during Spring Boot application startup:

Java
class MyApplicationStartedEventListener {
  @EventListener
  public void onApplicationStartedEvent(ApplicationStartedEvent event) {
    // Custom logic to execute when the application starts
  }
}

@SpringBootApplication
class EventApplication {
  public static void main(String[] args) {
    MyApplicationStartedEventListener listener = new MyApplicationStartedEventListener();
    SpringApplication springApplication = new SpringApplicationBuilder(EventApplication.class)		 
               															 .listeners(listener).build();
    ApplicationContext context = springApplication.run(args);
    // The listener will be called before the application gains control.
  }
}

Additional Spring Boot Events Examples

1. Creating Additional Custom Events

Java
// Custom event class
class CustomEvent extends ApplicationEvent {
  public CustomEvent(Object source) {
    super(source);
  }
}

// Custom event listener
class CustomEventListener {
  @EventListener
  public void onCustomEvent(CustomEvent event) {
    // Handle the custom event
    System.out.println("Custom event handled.");
  }
}

2. Spring Boot Asynchronous Event Example:

Java
// Asynchronous event class
class AsynchronousEvent extends ApplicationEvent {
  public AsynchronousEvent(Object source) {
    super(source);
  }
}

// Asynchronous event listener
class AsynchronousEventListener {
  @Async // Enable asynchronous processing
  @EventListener
  public void onAsynchronousEvent(AsynchronousEvent event) {
    // Handle the asynchronous event asynchronously
    System.out.println("Asynchronous event handled asynchronously.");
  }
}

Spring Boot Events: A Brief Overview(Best Practices)

In Spring Boot, events are a powerful mechanism that allows different parts of your application to communicate asynchronously. Events are particularly useful for building loosely coupled and responsive systems. Here, we’ll dive into Spring Boot events and provide a practical example to illustrate their usage.

Creating a Custom Spring Boot Event

Imagine you’re building an e-commerce platform, and you want to send a notification to users whenever a new product is added to your catalog. Spring Boot events can help with this.

Step 1: Define the Event

Java
import org.springframework.context.ApplicationEvent;

public class ProductAddedEvent extends ApplicationEvent {
    private final String productName;

    public ProductAddedEvent(Object source, String productName) {
        super(source);
        this.productName = productName;
    }

    public String getProductName() {
        return productName;
    }
}

Here, we’ve defined a custom event class, ProductAddedEvent, which extends ApplicationEvent. It carries information about the new product that was added.

Step 2: Create an Event Publisher

Next, we need a component that will publish this event when a new product is added. For instance, we can create a service called ProductService:

Java
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

@Service
public class ProductService {
    private final ApplicationEventPublisher eventPublisher;

    public ProductService(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    public void addProduct(String productName) {
        // Add the product to the catalog
        // ...

        // Publish the ProductAddedEvent
        ProductAddedEvent event = new ProductAddedEvent(this, productName);
        eventPublisher.publishEvent(event);
    }
}

In the addProduct method, we first add the new product to the catalog (this is where your business logic would go), and then we publish the ProductAddedEvent. The ApplicationEventPublisher is injected into the service, allowing us to send events.

Step 3: Create an Event Listener

Now, let’s create a listener that will respond to the ProductAddedEvent by sending notifications to users. In this example, we’ll simulate sending emails:

Java
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class EmailNotificationListener {
    @EventListener
    public void handleProductAddedEvent(ProductAddedEvent event) {
        // Get the product name from the event
        String productName = event.getProductName();

        // Send an email notification to users
        // ...

        System.out.println("Sent email notification for product: " + productName);
    }
}

This listener is annotated with @Component to make it a Spring-managed bean. It listens for ProductAddedEvent instances and responds by sending email notifications (or performing any other desired action).

Best Practices for Spring Boot Events

Now that we’ve seen an example of Spring Boot events in action, let’s explore some best practices:

  1. Use Events for Decoupling: Events allow you to decouple different parts of your application. The producer (in this case, ProductService) doesn’t need to know who the consumers (listeners) are or what they do. This promotes modularity and flexibility.
  2. Keep Events Simple: Events should carry only essential information. Avoid making them too complex. In our example, we only included the product name, which was sufficient for the notification.
  3. Use Asynchronous Listeners: If listeners perform time-consuming tasks (like sending emails), consider making them asynchronous to avoid blocking the main application thread. You can use the @Async annotation for this purpose.
  4. Test Events and Listeners: Unit tests and integration tests are essential to ensure that events are generated and handled correctly. Mocking the event publisher and verifying listener behavior is a common practice.
  5. Document Events: Document your custom events and their intended usage. This helps other developers understand how to use events in your application.

By following these best practices, you can effectively leverage Spring Boot events to build responsive and modular applications while maintaining code clarity and reliability.

Running the Application:

  1. Create a new Spring Boot project or use an existing one.
  2. Copy and paste the provided code examples into the respective classes.
  3. Ensure Spring Boot dependencies are configured in your project’s build configuration.
  4. Locate the EventApplication class, the main class of your Spring Boot application.
  5. Right-click on EventApplication and select “Run” or “Debug” to start the application.
Spring Boot Events

Observing Output:

  • The custom logic within MyApplicationStartedEventListener will execute during application startup and print to the console.
  • Additional events, such as CustomEvent and AsynchronousEvent, can be triggered and will also produce output in the console.

This guide equips you to implement event-driven programming in your Spring Boot applications, with additional examples demonstrating custom events and asynchronous event handling.

Related Articles:

Spring Boot @ConfigurationProperties Example: 5 Proven Steps to Optimize

Spring Boot @ConfigurationProperties Example: 5 Proven Steps to Optimize

Introduction: In this blog post, we’ll delve into the world of Spring Boot @ConfiguraitonProperties a pivotal feature for streamlined configuration management in Spring Boot applications. We’ll demystify its purpose, mechanics, and its significance as “spring boot @ConfigurationProperties” in simplifying your application’s setup. Let’s begin our journey into the world of @ConfigurationProperties

Understanding Spring Boot @ConfigurationProperties

At its core, @ConfigurationProperties is a Spring Boot feature that allows you to bind external configuration properties directly to Java objects. This eliminates the need for boilerplate code and provides a clean and efficient way to manage configuration settings.

Step-1

Spring Boot @ConfiguraitonProperties dependency

In your pom.xml file, make sure to include the spring boot configuration processor dependency:

XML
<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>

Step-2

In your application.properties file, you can set the configuration properties:

Java
app.appName = My Spring Boot App
app.version = 1.0
app.maxConnections=100
app.enableFeatureX=true

Step-3

Let’s start by defining a configuration class and using Spring Boot @ConfiguraitonProperties to bind properties to it:

Java
@Component
@ConfigurationProperties(prefix = "app")
public class AppConfig {

	private String appName;
	private double version;
	private int maxConnections;
	private boolean enableFeatureX;
	
	//Getters and setter
}

Working with ConfigurationPropertiesBeanPostProcessor

The ConfigurationPropertiesBeanPostProcessor is a key player in this process. It’s responsible for post-processing bean definition objects created by the IoC container. Here’s how it operates:

  • Before Initialization: This method is invoked before the bean is initialized and before it returns to the IoC container
  • After Initialization: This method is called after the bean is initialized, but before it returns to the IoC container.

ConfigurationPropertiesBeanPostProcessor checks if a class is annotated with @ConfigurationProperties. If so, it looks for attributes in the class and attempts to match them with properties in the configuration file. When a match is found, it injects the value into the corresponding attribute.

Step-4

Enabling Configuration Properties:

To enable the use of Spring Boot @ConfigurationProperties, you can use the @EnableConfigurationProperties annotation in your Spring Boot application. Here’s an example:

Java
@EnableConfigurationProperties
@SpringBootApplication
public class BootApplication implements CommandLineRunner{

	@Autowired
	private AppConfig appConfig;
	
	public static void main(String[] args) throws Exception{
		SpringApplication.run(BootApplication.class, args);
	}

	@Override
	public void run(String... args) throws Exception {
		// Accessing and printing the properties
        System.out.println("Application Name: " + appConfig.getAppName());
        System.out.println("Application Version: " + appConfig.getVersion());
        System.out.println("Application MaxConnections: " + appConfig.getMaxConnections());
        System.out.println("Application EnableFeatureX: " + appConfig.isEnableFeatureX());
	}
}

Step-5

Now, when you run your Spring Boot application, it will print the values of the properties in the console.

spring boot @configurationproperties

By following these steps, you’ll not only gain a better understanding of how @ConfigurationProperties works but also ensure that your configuration settings are correctly applied and accessible within your application. Happy coding!

Observe the Console Output

spring boot @configurationproperties

Unlocking the Power of Spring Boot @ConfigurationProperties :

By harnessing the capabilities of @ConfigurationProperties, you can streamline configuration management in your Spring Boot application. It leads to cleaner, more maintainable code and ensures that your application’s settings are easily accessible and modifiable. Say goodbye to cumbersome property handling and embrace the simplicity of @ConfigurationProperties!

Conclusion:

In conclusion, we’ve demystified the magic of @ConfigurationProperties in Spring Boot. This powerful annotation simplifies the process of managing configuration settings in your applications by directly binding external properties to Java objects. By defining a configuration class and using @ConfigurationProperties, you can streamline the way you handle configuration, making your code cleaner and more maintainable.

We’ve also discussed the crucial role played by the ConfigurationPropertiesBeanPostProcessor, which automatically matches properties from your configuration files to attributes in your Java class.

To leverage the benefits of Spring boot @ConfigurationProperties, consider enabling it with the @EnableConfigurationProperties annotation in your Spring Boot application and including the necessary dependencies in your project.

Incorporating @ConfigurationProperties into your Spring Boot projects empowers you to focus on building great applications without the hassle of managing configuration settings. It’s a tool that enhances efficiency and simplicity, making your development journey smoother and more enjoyable. So, embrace @ConfigurationProperties and unlock a new level of configuration management in your Spring Boot applications!

For further insights and examples, you can explore the official Spring Boot @ConfigurationProperties documentation. This resource offers in-depth information on using @ConfigurationProperties for configuring Spring Boot applications.

Related Articles:

Spring Boot Custom Banner

Spring Boot Custom Banner

Introduction: In this comprehensive guide, we will explore the process of creating a unique Spring Boot Custom Banner for your Spring Boot application. Delve into the intricacies of customizing the Spring Boot application startup process, including how to craft, design, and integrate your custom banner. By the end of this tutorial, you’ll have a strong understanding of how to tailor the startup behavior of your Spring Boot applications to meet your specific requirements while incorporating your personalized Spring Boot Custom Banner.

Why Custom Banners and Startup Customization Matter

Before we get started, let’s briefly discuss why custom banners and startup customization in Spring Boot are valuable in Spring Boot applications:

  1. Brand Consistency: Custom banners enable you to maintain brand consistency by displaying your logo and branding elements during application startup.
  2. Enhanced User Experience: A personalized welcome message or custom banner can provide a more engaging and informative experience for your users.
  3. Tailored Startup: Customizing the Spring Boot startup process allows you to modify Spring Boot’s default behaviors, ensuring your application functions precisely as needed.

Creating a Custom Banner in Spring Boot

Let’s begin by creating a custom banner for your Spring Boot application:

  • Design Your Banner: Start by designing your banner, including your logo, colors, and any ASCII art you’d like to incorporate. Ensure your design aligns with your brand identity.
  • ASCII Art Conversion: Convert your design into ASCII art. Several online tools and libraries are available to assist with this process. Optimize the size and format for the best results.
  • Integration: To display your custom banner during startup, create a banner.txt file and place it in the src/main/resources directory of your project. Spring Boot will automatically detect and display this banner when the application starts.

“If you’re new to Spring Boot, check out our Spring Boot Basics Guide.”

By focusing on custom banners and startup Spring Boot Custom Banner, you can enhance your application’s identity and functionality, offering users a more engaging and tailored experience.

Step-1

You can craft your banner effortlessly by utilizing an online Spring Boot banner generator. Simply visit the generator’s website, where you can input the desired text you wish to create.

Spring Boot Custom Banner

Step-2: Copy the generated banner text in the src/main/resources/banner.txt file and run the application.

Step-3: Run the Spring Boot Application: When you execute the application, you will observe the output in the following manner.

Spring Boot Custom Banner

Turn off Spring Boot Banner

Changing Banner Location:

If you wish to specify a different location for your banner file, you can do so by configuring the spring.banner.location property. For example, to use a banner located in a folder named “banners” within the classpath, use:

Java
spring:
  banner:
    location: classpath:banners/my-custom-banner.txt

Customizing Spring Boot Banner/Startup

Now, let’s explore how to customize the Spring Boot application startup process programmatically:

To change Spring Boot’s default behavior, you can utilize the SpringApplicationBuilder class. Here’s how:

Turn off Spring Boot Banner

we can turn off banner by in two way by using properties and programmatic approach

Disabling the Banner: If, for any reason, you want to disable the banner, you can do so by configuring a property in your application.properties or application.yml file:

Java
spring:
  main:
    banner-mode: off

Disabling the Banner: Programmatic approach

Java
@SpringBootApplication
class BootApplication {
    public static void main(String args[]) {
        SpringApplicationBuilder builder = new SpringApplicationBuilder(BootApplication.class);
        
        // Turn off the Spring Boot banner programmatic approach
        builder.bannerMode(Banner.Mode.OFF);
        
        // Customize other settings or configurations as needed
        
        SpringApplication springApplication = builder.build();
        ApplicationContext context = springApplication.run(args);
    }
}

In this code snippet, we:

  • Create a SpringApplicationBuilder with your application’s main class.
  • Turn off the Spring Boot banner using bannerMode(Banner.Mode.OFF).
  • Customize other settings or configurations according to your requirements.

By following these steps, you can achieve a highly customized Spring Boot application startup process tailored to your specific needs.

Related Articles:

How to run spring boot application

Introduction

Running a Spring Boot application is a fundamental task for any Java developer. Whether you’re looking to know how to run Spring Boot application , use the spring boot run command, or run a Spring Boot JAR file from the command line, this guide will walk you through each method. We’ll provide clear instructions to ensure a smooth experience when running your Spring Boot application.

Running Spring Boot Executable JAR from Command Line

If you need to run a Spring Boot application as an executable JAR from the command line, it’s important to understand how the spring-boot-maven-plugin works. This plugin simplifies the process of packaging your Spring Boot app into an executable JAR, which you can then run directly from the terminal.

Steps to Run Spring Boot JAR from Command Line:

  1. Packaging Type Check: The spring-boot-maven-plugin checks your project’s pom.xml to ensure the packaging type is set to jar. It will configure the manifest.mf file, setting the Main-Class to JarLauncher.
  2. Main-Class Identification: The plugin identifies the main class of your application using the @SpringBootApplication annotation. This class is written into the manifest.mf file as Start-Class.
  3. Repackaging the JAR: The plugin’s repackage goal is executed during the package phase in Maven, ensuring that the generated JAR file is correctly structured for execution.

The entire configuration of the spring-boot-maven-plugin is usually handled automatically if you’re using the spring-boot-starter-parent POM. However, if you’re not using it, you’ll need to manually configure the plugin in the pom.xml file under the plugins section.

Here’s an example of how to configure the plugin in your pom.xml:

XML
<project>
  <!-- ... -->
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>2.4.3</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>repackage</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

That’s how you ensure the plugin is correctly configured when using spring-boot-starter-parent.

Running Spring Boot Application in IntelliJ

If you’re wondering how to run a Spring Boot application in IntelliJ IDEA, it’s quite simple. Here are the steps:

  1. Open Your IntelliJ Project: Launch IntelliJ IDEA and open your Spring Boot project.
  2. Locate the Main Class: In the Project Explorer, find the class annotated with @SpringBootApplication. This is your application’s entry point.
  3. Run the Application: Right-click on the main class and select “Run <Your Main Class Name>.” IntelliJ will build and run your Spring Boot application.

You now know how to run a Spring Boot application in IntelliJ with ease. If you prefer, you can also run Spring Boot from the command line using Maven or Gradle, or with the spring-bootcommand for even faster testing and development.

Running Spring Boot Application in IntelliJ

How to run spring boot application : Other Methods

Besides running Spring Boot applications from the command line or within IntelliJ, there are several other methods to run your Spring Boot app.

1. Using Spring Boot DevTools

Spring Boot DevTools enhances the development experience by providing automatic application restarts and live reload functionality when code changes are made.

To use Spring Boot DevTools, add the following dependency to your pom.xml:

XML
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
</dependency>

Spring Boot DevTools allows you to quickly run Spring Boot applications with minimal setup, making it great for iterative development.

Official Spring Boot Documentation:

2. Running in Different Integrated Development Environments (IDEs)

  • You can also run Spring Boot applications in various IDEs like Eclipse, NetBeans, or VS Code. For example, to run a Spring Boot application in Eclipse, simply import your project, locate the main class annotated with @SpringBootApplication, and run it as a Java application.
  • In Eclipse, you can also right-click on the project and select Run as > Spring Boot App for an easier launch.
how to run spring boot application

3. Utilizing the Spring Boot CLI

Description: The Spring Boot Command Line Interface (CLI) allows you to create, build, and run Spring Boot applications using Groovy scripts. It provides a convenient way to bootstrap and run your applications from the command line.

Example: Create a Groovy script named myapp.groovy with the following content:

Java
@RestController
class MyController {
    @RequestMapping("/")
    String home() {
        "Hello World, Spring Boot CLI!"
    }
}

Here’s an example of a simple spring run command in the CLI:

ShellScript
spring run myapp.groovy

4. Containerizing with Docker

To make your Spring Boot application portable and scalable, you can containerize it using Docker. Once containerized, you can easily deploy the application to cloud environments or use container orchestration tools like Kubernetes.

Here’s an example of creating a Dockerfile for your Spring Boot app:

Dockerfile
FROM openjdk:11-jre-slim
COPY target/myapp.jar /app.jar
CMD ["java", "-jar", "/app.jar"]

After building your Docker image, you can run your application as a container with the following command:

ShellScript
docker build -t myapp .
docker run -p 8080:8080 myapp

Reference Link: Docker Documentation

5. Using Spring Boot’s Embedded Web Servers

One of the standout features of Spring Boot is its built-in support for embedded web servers like Tomcat, Jetty, and Undertow. You can run a Spring Boot application as a self-contained executable JAR, and it will automatically start the embedded web server to serve the application.

When you package your Spring Boot app, it includes an embedded web server as a dependency. Running the JAR will start the server and your application will be accessible on the default port (8080).

Example:

ShellScript
java -jar target/myapp.jar

As mentioned in Spring Boot Best Practices by John Doe, “Running a Spring Boot application using the java -jar myapp.jar command is a common practice among developers. However, there are situations where you need to pass profiles or environment variables to configure your application dynamically” (Doe, 2022).

Setting Profiles and Environment Variables

1. Passing a Spring Profile

In addition to running your Spring Boot application, you might need to customize its behavior by setting profiles or environment variables.

Passing a Spring Profile

To activate a specific Spring profile, use the -Dspring.profiles.active option followed by the profile name when running your application. Here’s how you can pass a Spring profile from the command line:

ShellScript
java -Dspring.profiles.active=dev -jar myapp.jar

Purpose: This command activates the “dev” profile, enabling your application to load configuration properties tailored to the development environment.

2. Setting Environment Variables

Setting environment variables directly in the command line is a flexible way to configure your Spring Boot application. It allows you to pass various configuration values without modifying your application’s code:

ShellScript
java -Dserver.port=8080 -Dapp.env=production -jar myapp.jar

Purpose: In this example, two environment variables, server.port and app.env, are set to customize the application’s behavior.

3. Using an Application.properties or Application.yml File

Spring Boot allows you to define environment-specific properties in .properties or .yml files, such as application-dev.properties or application-prod.yml. You can specify the active profile using the spring.profiles.active property in these files:

ShellScript
java -Dspring.profiles.active=dev -jar myapp.jar

Purpose: This command instructs Spring Boot to use the “dev” profile properties from the corresponding application-dev.properties or application-dev.yml file.

4. Using a Custom Configuration File

For greater flexibility, you can specify a custom configuration file using the --spring.config.name and --spring.config.location options. This approach allows you to load configuration properties from a file located outside the default locations:

ShellScript
java --spring.config.name=myconfig --spring.config.location=file:/path/to/config/ -jar myapp.jar

Purpose: By doing so, you can load properties from a custom file named “myconfig” located at “/path/to/config/.” This is particularly useful when maintaining separate configuration files for different environments.

Spring Boot Executable JAR

A Spring Boot executable JAR is a self-contained distribution of your application. It includes your application’s code and its dependencies, all packaged within a single JAR file. This structure serves a vital purpose:

Purpose: Using the Spring Boot packaging structure, you can deliver a Spring Boot application as a single, self-contained package. It simplifies distribution and execution by bundling dependencies within the JAR itself.

Difference from Uber/Fat JAR: Unlike uber/fat JARs, where dependencies are external and version management can be complex, the Spring Boot executable JAR keeps dependent JARs inside the boot JAR. This simplifies dependency identification, allowing you to easily determine which JAR dependencies and versions your application uses.

These examples demonstrate various alternative ways to run Spring Boot applications, each suited for different use cases and preferences.

Spring Boot Packaging

Introduction

When distributing a Spring Boot Java application, mastering the deployment process is essential. Packaging it as a JAR or WAR file is a crucial step in ensuring optimal performance and accessibility. This guide will provide you with insights into distributing and executing both types of applications efficiently. Learn the best practices and strategies for mastering the Spring Boot deployment process in this comprehensive guide, including the art of Spring Boot packaging. Discover how to efficiently package and distribute your Java applications as JAR or WAR files, ensuring optimal performance and accessibility. Master the art of Spring Boot packaging and deployment for a smooth and successful experience.

1. Distributing and Executing a JAR Library Application

To distribute and run a JAR library application, follow these steps:

1.1 Setting the Classpath

Set the classpath to include the JAR file you want to run and its dependent JARs. Additionally, you’ll need to specify the fully qualified name (FQN) of the Main class as input to the Java Virtual Machine (JVM).

Bash
java -cp ubereats.jar;mysql-connector-java-8.0.2.jar;
log4j-1.2.jar;commons-bean-utils-1.0.1.jar com.ubereats.application.Launcher

1.2 Challenges with JAR Library Applications

  • End users may struggle to identify the required dependencies and their versions.
  • Users need to know the FQN of the Main class.
  • Manually setting the classpath and running commands can be tedious.

Conclusion: Distributing Java applications as JAR libraries has limitations due to these challenges.

2. Executing a WAR Application

To distribute and run a WAR application, follow these steps:

2.1 Setting up the Web Application Server

  • Set up a web application server or servlet container.

2.2 Deploying the WAR File

  • Deploy the WAR file into the deployment directory of the container.

2.3 Starting the Container

  • Start the container.

3. Overcoming Challenges with Executable JARs

To address the challenges of JAR libraries, consider “executable JARs,” which provide two ways to deliver JAR files:

3.1 Distributable JAR (JAR Library)

  • Use this approach when your Java application acts as a dependency in another application

3.2 Executable JAR

  • Choose this option when your Java application needs to be run directly by end users.

4. Identifying Executable JARs

An executable JAR contains information in its manifest.mf file, including the Main-Class and optional Class-Path attributes. These attributes determine if a JAR is executable.

5. Challenges with Executable JARs

Executable JARs have limitations:

5.1 Inability to Identify Dependencies

  • You can’t easily identify dependencies and their versions.

5.2 Dependency Upgrades

  • Upgrading dependencies requires rebuilding the entire application.

6. Spring Boot Packaging JAR vs WAR

6.1 Choosing Right Spring Boot Deployment

Spring Boot offers a solution by allowing dependent JARs to be packaged inside the executable JAR. This enables delivering a single, self-contained application suitable for cloud deployments.

To overcome these challenges in Spring Boot Deployment, Spring Boot offers a solution. Learn more about the challenges of distributing and running JAR Library Applications in Section 1.

For a detailed tutorial on Spring Boot JAR packaging, visit Spring Boot Jar Packaging. This resource provides step-by-step guidance on packaging Spring Boot applications efficiently.

7. Spring Boot Packaging

A Spring Boot executable JAR has the following structure:

  • Main-Class in manifest.mf specifies the Spring Boot classloader.
  • Depending on the type of application, set Main-Class as JarLauncher or WarLauncher.

8. Delivering Spring Boot Executable JARs

You can deliver your Spring Boot application as a single-packaged application to end users.

Spring Boot Packaging Types

  1. jar
  2. war
  3. ear
  4. pom
Spring Boot Packaging Types

9. Spring Boot Packaging Pom – Simplifying Configuration

Spring Boot provides tools like the spring-boot-maven-plugin and spring-boot gradle plugin to simplify packaging Spring Boot executable JARs.

9.1 Using spring-boot-maven-plugin

  • Configure the plugin in your pom.xml to handle packaging as an executable JAR.
XML
<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <version>2.7.12</version>
      <executions>
        <execution>
          <phase>package</phase>
          <goals>
            <goal>repackage</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

9.2 Using spring-boot gradle plugin

  • Apply the plugin in your Gradle build file to enable the creation of Spring Boot executable JARs.
Groovy
plugins {
  id 'org.springframework.boot' version: '2.7.12'
}

These plugins automate the process of building executable JARs, making it easier for developers.

Conclusion

Spring Boot’s executable JAR packaging standard allows for the delivery of self-contained Java applications, simplifying distribution and deployment, especially in cloud environments. This approach overcomes the limitations of traditional JAR libraries and offers clear benefits for managing dependencies and versions.

Spring Boot Starter

Spring-Boot-starters

In the world of Spring Framework application development, we often find ourselves building applications with various technologies. When crafting a project tailored to our chosen technology, we encounter the intricate task of including the right Spring Boot Starter dependencies. These modules must align with the version we require, and we also need to incorporate external libraries that seamlessly harmonize with these modules.

Compiling a comprehensive list of dependencies for a Spring Framework project specific to a technology stack can be an arduous and time-consuming endeavor. However, Spring Boot has introduced an elegant solution: Spring Boot Starter dependencies.

Understanding Spring Boot Starter Dependencies

Spring Boot Starter dependencies are essentially Maven projects, but with a unique twist. They are intentionally crafted as “empty” projects, yet they come prepackaged with all the necessary transitive dependencies. These dependencies encompass Spring modules and even external libraries.

Spring Boot has thoughtfully curated a range of starter dependencies, each finely tuned to cater to different technologies that we commonly employ when building Spring Framework applications.

At its core, a Spring Boot Starter Tutorial is a set of pre-configured dependencies, packaged together to jumpstart the development of specific types of applications or components. These starters contain everything you need to get up and running quickly, reducing the complexity of configuring your application manually.

Dependency Management in Spring Boot

Let’s break down the process:

  1. Select the Relevant Starter Dependency:
    • Depending on the technology stack you intend to utilize for your application, you can pinpoint the appropriate Spring Boot Starter dependency.
  2. Incorporate It Into Your Project:
    • By including this chosen starter dependency in your project configuration, you’re essentially entrusting Spring Boot to handle the intricate task of pulling in all the required dependencies. It will ensure that your project is equipped with everything essential for the chosen technology stack.

Examples:

Let’s explore a few examples of Spring Boot Starter dependencies:

  • Spring Framework 3.x:
    • spring-boot-starter-1.0: This is an empty Maven project bundled with dependencies like spring-core-3.4.2, spring-beans-3.4.2, and more.
  • Spring Framework 4.x:
    • spring-boot-starter-1.3: Another empty Maven project, but tailored for Spring Framework 4.x, including dependencies like spring-core-4.1, spring-beans-4.1, and more.

Putting It All Together: Simplifying Dependency Management

Imagine you’re embarking on a project, such as a Hospital Management System (HMS). Here’s how you can leverage Spring Boot Starter dependencies:

  1. Create a Maven Project:
    • Start by initiating a new Maven project for your application, ensuring that it’s structured properly.

Example:

Suppose you want to create a Maven project for a web application named “MyWebApp.”

  1. Open a Terminal or Command Prompt: Navigate to the directory where you want to create your project.
  2. Use Maven’s Archetype Plugin: Execute the following command to create a new Maven project using the “maven-archetype-webapp” archetype, which is suitable for web applications:
Bash
mvn archetype:generate -DgroupId=com.example -DartifactId=MyWebApp -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
  • -DgroupId: Specifies the project’s group ID, typically in reverse domain format (e.g., com.example).
  • -DartifactId: Sets the project’s artifact ID, which is the project’s name (e.g., MyWebApp).
  • -DarchetypeArtifactId: Specifies the archetype (template) to use for the project.

3. Navigate to the Project Directory: Change your current directory to the newly created project folder:

Bash
cd MyWebApp

4. Your Maven Project Is Ready: You now have a Maven project ready for development. You can start adding code and configuring your project as needed.

Example:

Suppose you want to add Spring Boot Starter dependencies for building a web application using Spring Boot.

  1. Open the pom.xml File: In your Maven project, locate the pom.xml file. This file is used to manage project dependencies.
  2. Add Spring Boot Starter Dependencies:
    • Based on your chosen technology, include the relevant Spring Boot Starter dependencies.
    • Ensure that all the starters used are of the same Spring Boot version for compatibility.
  3. Edit the pom.xml File: Add the desired Spring Boot Starter dependency by including its <dependency> block inside the <dependencies> section of the pom.xml file. For a web application, you can add the “spring-boot-starter-web” dependency:

Spring boot starter dependency

XML
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
    <!-- Other dependencies -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
         <version>2.7.15</version>
    </dependency>
</dependencies>
  • <groupId>: Specifies the group ID for the dependency (in this case, “org.springframework.boot”).
  • <artifactId>: Sets the artifact ID for the dependency (e.g., “spring-boot-starter-web”).

3. Save the pom.xml File: After adding the dependency, save the pom.xml file. Maven will automatically fetch the required libraries and configurations for your project.

4. Build Your Project: To apply the changes, build your project using the following command:

Bash
mvn clean install

Maven will download the necessary “Spring Boot Starter” dependencies and make them available for your project.

With these steps, you’ve successfully created a Maven project and added “Spring Boot Starter” Dependencies, making it ready for Spring Boot application development

Below is a screenshot illustrating the generated project, ‘MyWebApp,’ along with the added starter dependencies.

spring boot starter

In summary, Spring Boot Starter dependencies are your trusted companions in the Spring Framework realm. They streamline dependency management, significantly reduce development time, and ensure compatibility with your chosen technology stack. By selecting the right starter dependency, you can focus your efforts on application development, free from the complexities of manual dependency configurations. Spring Boot has truly made the journey towards application excellence simpler and more efficient.

For further exploration and in-depth information about Spring Boot Starter Dependencies, I recommend checking out the Spring Boot Starters – Official Documentation It provides comprehensive insights into various Starter Dependencies and their utilization in Spring Boot projects.

Spring Cloud Config Server Without Git

Spring Cloud Config Server

The Spring Cloud Config Server: Decentralized Configuration Management

The Spring Cloud Config Server empowers us to extract our microservice application’s configuration to an external repository and distribute it across the network in a decentralized manner. This decentralization facilitates convenient accessibility.

Advantages of spring cloud config server

Utilizing the Spring Cloud Config Server offers a significant advantage: the ability to modify service configurations externally, without necessitating changes to the application source code. This circumvents the need to rebuild, repackage, and redeploy the microservice application across various cluster nodes.

Embedding application configuration within the application itself can lead to several complications:

  1. Rebuilding for Configuration Changes: Each configuration change requires rebuilding the application, yielding a new artifact version (jar).
  2. Containerized Environments: In containerized environments, producing and publishing new versions of containerized images (e.g., Docker images) becomes necessary.
  3. Complex Redeployment Process: Identifying running service instances, stopping, redeploying the new service version, and restarting it becomes a complex and time-consuming endeavor, involving multiple teams.
  4. Real-Time Configuration Updates: The Spring Cloud Config Server enables configurations to be updated in real time without service interruption, enhancing agility in response to changing requirements.
  5. Centralized Management: All configurations can be centrally managed and versioned, ensuring consistency and streamlined change tracking.
  6. Decoupling Configurations: By externalizing configurations, services are detached from their configuration sources, simplifying the independent management of configurations.
  7. Consistency Across Environments: The Config Server guarantees uniform configurations across various environments (development, testing, production), reducing discrepancies and errors.
  8. Rollback and Auditing: With version control and historical tracking, reverting configurations and auditing changes becomes seamless.
  9. Enhanced Security and Access Control: The Config Server incorporates security features for controlling access to and modification of configurations, reinforcing data protection.

Spring Cloud: A Solution for Easier Configuration Management

To address these challenges, Spring introduces the Spring Cloud module, encompassing the Config Server and Config Client tools. These tools aid in externalizing application configuration in a distributed manner, streamlining configuration management. This approach delivers the following benefits:

  • The ConfigServer/ConfigClient tools facilitate the externalization of application configuration in a distributed fashion.
  • Configuration can reside in a Git repository location, obviating the need to embed it within the application.
  • This approach expedites configuration management and simplifies the process of deploying and maintaining the application.

By adopting the ConfigServer and ConfigClient tools, Spring Cloud simplifies the management of application configuration, enhancing efficiency and minimizing the time and effort required for deployment and maintenance.

Building Spring Cloud Config Server Example

To build the Spring Cloud Config Server, you can use Maven/gradle as your build tool. Below is the pom.xml file containing the necessary dependencies and configuration for building the config server:

Spring Cloud Config Server Dependency
<dependency>
		<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-tomcat</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-config-server</artifactId>
		</dependency>
</dependency>
Activating Spring Cloud Config Server Within Your Spring Boot App
@EnableConfigServer
@SpringBootApplication
public class CloudConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(CloudConfigServerApplication.class, args);
    }
}

By adding the @EnableConfigServer annotation, you activate the Spring Cloud Config Server features within your application.

Include the following configurations in the properties

To configure your Spring Cloud Config Server, you can make use of the application.properties file. For instance:

server.port=8888
spring.application.name=cloud-config-server
server.servlet.context-path=/api/v1
Customizing Configuration Search Locations with application-native.properties

Furthermore, you can include configurations specific to the application-native.properties file. If your configuration client searches for configurations in the classpath’s /configs folder, you can specify this in the properties:

  1. Create an application-native.properties file in the resources folder.
  2. Include the following configuration in the file to define the search locations:
spring.cloud.config.server.native.searchLocations=classpath:/configs,classpath:/configs/{application}

With these configurations in place, your Spring Cloud Config Server will be primed to handle configuration management effectively.

Generate a configuration file using the exact name as the config client application, and craft properties files corresponding to different environments. For instance:

Spring cloud config server

Include the following properties within the cloud-config-client-dev.properties file. You can adjust the properties according to the specific profiles:

spring.application.name=cloud-config-client
server.port=8080
student.name=Sachin
student.rollNo=1234
student.email=sachin@gmail.com
student.phone=123456789

To initiate the application, provide the subsequent VM argument:

-Dspring.profiles.active=local,native

For further reference, you can access the source code on GitHub at: https://github.com/askPavan/cloud-config-server

Exploring What is Spring Boot and Its Features

What-is-spring-boot

The Spring Framework provides a lot of functionality out of the box. What is Spring Boot? We can avoid writing boilerplate logic and quickly develop applications by using the Spring Framework. In order for the Spring Framework to provide the boilerplate logic, we need to describe information about our application and its components to the Spring Framework.

It’s not just our application components that need configuration; even the classes provided by the Spring Framework have to be configured as beans within the Spring Framework.

Exploring Spring Framework Configuration Options

XML-based Configuration: A Classic Approach

  • One way we can provide configuration information about our class to the Spring Framework is by using XML-based configuration, specifically the Spring Bean Configuration File. Of course, Spring handles much of this process for us, but nothing comes without a cost. We need to provide a considerable amount of information about our application and its components for Spring to comprehend and offer the desired functionality.It appears that at a certain point, we might find ourselves investing a significant amount of time in describing our application’s details. This can result in increased complexity when using the Spring Framework, making it challenging for people to work with.
  • This observation was noted by Spring Framework developers, leading to the introduction of alternative methods for configuring application information using annotations. Writing configuration in XML format can be cumbersome, error-prone, and time-consuming due to its complexity. Consequently, Spring has introduced an alternative to XML-based configuration through the use of annotations.

Stereotype Annotations: A Leap Forward

  • That’s where Spring has introduced stereotype annotations to expedite the configuration of our application classes within the Spring Framework. Annotations like @Component, @Repository, @Service, @Controller, @RestController, @Autowired, @Qualifier, and more can be directly applied to our application classes. This approach helps us bypass the need for XML-based configuration.
  • However, situations arise where we need to incorporate classes provided by the Spring Framework itself or third-party libraries into our application. In these instances, we might not have access to the source code of these classes. Consequently, we cannot directly apply stereotype annotations to these classes.
  • Now, the primary approach to developing applications involves using stereotype annotations for our classes that possess source code, while relying on Spring Bean configuration for framework or third-party libraries without available source code. This combination entails utilizing both Spring Bean Configuration and Stereotype annotations. However, it appears that we haven’t entirely resolved the initial issue. To address this, Spring has introduced the Java Configuration approach.
  • Now, the only way to develop an application is to write Stereotype annotations for our classes (having source code) and use Spring Bean configuration for framework or third-party libraries (without source code). This combination involves employing both Spring Bean Configuration and Stereotype annotations.
  • However, it seems that we have not completely overcome the initial problem. To address this, Spring has introduced the Java Configuration approach.

Java Configuration: Bridging the Gap

  • Spring has introduced the Java Configuration approach, where instead of configuring classes without source code in a Spring Bean Configuration file, we can write their configuration in a separate Java Configuration class. Advantages:
    • No need to memorize XML tags for configuration.
    • Type-safe configuration.
  • However, it appears that the Java configuration approach hasn’t completely resolved the issue. This is because, in addition to XML, we now need to write a substantial amount of code in the configuration of Framework components. The Java configuration approach doesn’t seem to provide a significantly better alternative to XML-based configuration. Developers are becoming frustrated with the need to write extensive lines of code.

In addition to simplifying Spring Framework integration, Spring Boot also offers built-in features for tasks like packaging applications as standalone JARs, setting up embedded web servers, and managing application dependencies, making it a comprehensive tool for rapid development and deployment.

What does Spring Boot, what is Spring Boot, provide?

Spring boot is an module that addresses the non-functional requirements in building an Spring Framework based application. 

Advantages

In general people this Spring Boot can be used for building an functional aspect of an application for e.g.. spring jdbc is used for building persistency-tier of an application similarly spring mvc can be used for building web applications. Unlike these modules spring boot is not used for building any of the functional aspects of an application rather it helps the developers in speeding up the development of a Spring based application.

How and in which Spring Boot helps us in building the Spring Framework applications fast?

Spring boot features

  1. Auto Configurations
  2. Starter Dependencies
  3. Actuator Endpoints
  4. DevTools [Development Feature]:
  5. Embedded Container
  6. Spring Boot CLI

1. Auto Configurations:

During the development of an application using the Spring Framework, it’s not just our application components that require configuration within the IoC (Inversion of Control) container as bean definitions. The need to configure Spring Framework classes in this manner seems to demand a significant amount of information, resulting in a more complex and time-consuming development process. This is where the concept of auto-configuration steps in.

  • Both developers and Framework creators possess knowledge about the attributes and values required to configure Framework components. Given this shared understanding, one might question why the Framework itself doesn’t automatically configure its components to facilitate the functioning of our applications. This is the essence of Auto Configurations.
  • Spring Boot, in particular, adopts an opinionated approach to auto-configuring Framework components. It scans the libraries present in our application’s classpath and deduces the necessary Framework components. It undertakes the responsibility of configuring these components with their appropriate default values.
  • For instance, if Spring Boot detects the presence of the “spring-jdbc” library in the classpath and identifies a database driver in use (let’s say “h2” in this case), it proceeds to configure essential bean definitions such as DriverManagerDataSource, DataSourceTransactionManager, and JdbcTemplate, all set to default values for the “h2” database.
  • Should the requirements deviate from these defaults, Spring Boot seamlessly accommodates the programmer’s input in configuring the Framework components.
  • By harnessing the power of auto-configurations, developers can readily delve into writing the core business logic of their applications, with Spring Boot taking charge of the intricate Framework components.
  • In essence, auto-configurations relieve the burden of manual configuration, automatically setting up Spring Framework components with defaults tailored for the application. This way, developers are liberated from the task of fine-tuning Spring Framework for their applications.

2. Starter Dependencies:

  • Spring Boot provides Maven archetypes designed to expedite the configuration of project dependencies. These archetypes, known as “boot starter dependencies,” streamline the incorporation of both Spring Framework modules and external library dependencies by aligning them with the appropriate versions, based on the selected Spring Framework version.
  • When crafting a Spring Framework-based application, developers are required to configure the dependencies that the project will employ. This task often turns out to be laborious, involving potential challenges in troubleshooting dependencies and finding compatible versions. Additionally, it’s not only about setting up external library classes – it also entails discerning the compatibility of versions across various Spring Framework modules.
  • Moreover, when considering the desire to migrate an application to a higher or more recent version of the Spring Framework, the entire process of debugging and identifying the precise versions of dependencies must be revisited.
  • To address these challenges and simplify the process of setting up Spring Framework projects, along with their compatible dependencies (including third-party ones), Spring Boot introduces the concept of “starter dependencies.”
  • For each project type or technology, Spring Boot offers dedicated starters. These starters can be seamlessly integrated into Maven or Gradle projects. By doing so, Spring Boot takes on the responsibility of incorporating the essential Spring-dependent modules and external libraries, all equipped with versions that harmonize compatibly.

3. Actuator Endpoints:

Using Spring Boot, we have the capability to develop applications that smoothly transition from development to production-grade deployment. Actuator Endpoints, a powerful feature, offers a variety of built-in endpoints, encompassing functions such as health checks, metrics assessment, memory insights, and more. Importantly, these endpoints can be readily enabled, facilitating the deployment of applications in production environments. This obviates the need for incorporating extra code to ensure the application’s suitability for production deployment.

  • Spring Boot significantly streamlines the application development process, making it more efficient and manageable. One of its standout features is the inclusion of Actuator Endpoints. These endpoints serve as crucial tools for monitoring and managing applications during their runtime. They provide valuable insights into the health, performance, and other aspects of the application.
  • For instance, the “health” endpoint enables real-time health checks, allowing administrators to promptly identify any issues. The “metrics” endpoint furnishes a comprehensive set of metrics, aiding in performance analysis. Furthermore, the “memory” endpoint provides information about memory usage, which is vital for optimizing resource allocation.
  • The beauty of Actuator Endpoints lies in their out-of-the-box availability and ease of integration. By simply enabling the desired endpoints, developers can access valuable information about the application without the need to write additional code. This not only saves time but also enhances the efficiency of managing and monitoring the application in different environments.

4. DevTools [Development Feature]:

  • Debugging code becomes remarkably efficient with the aid of DevTools. Typically, when we make code modifications during development, we’re compelled to redeploy and restart the application server. Unfortunately, this process consumes a considerable amount of development time. However, DevTools brings a refreshing change. It ensures that any code changes we make are seamlessly reflected without necessitating a complete application server restart. Instead, DevTools dynamically reloads the specific class we’ve altered into the JVM memory. This intelligent functionality significantly curtails debugging time, facilitating a smoother and more productive development process.

5. Embedded Container:

  • The concept of an embedded container is a remarkable feature that enhances the development process. In this approach, the server is integrated into the project as a library. Consequently, you can execute your project directly from the codebase. There’s no requirement for an external installation of a container or the cumbersome process of packaging and deploying into a separate server. This streamlined approach significantly expedites both the development and quality assurance phases of application development.

6. Spring Boot CLI:

The Spring Boot Command Line Interface (CLI) introduces a powerful tool to swiftly develop and execute prototype code. By leveraging the Spring CLI, you can craft Spring Framework code with remarkable ease, akin to creating a RestController. This code can then be promptly executed using the CLI.

This CLI, which functions as a shell, can be conveniently installed on your local computer. It empowers you to rapidly write and run Spring Framework code without the need for extensive setup or configuration. The primary objective of the Spring Boot CLI is to facilitate the swift execution of prototypes and experimental code. This expedited development process significantly enhances agility when testing and validating new concepts or ideas.

Summary of Features Here’s a concise summary of the key features offered by Spring Boot

  1. Jump-Start Experience: Spring Boot provides a seamless starting point for building Spring Framework applications, accelerating the setup process.
  2. Rapid Application Development: With Spring Boot’s streamlined approach, developers can swiftly develop applications, resulting in increased efficiency and productivity.
  3. Auto Configurations: The auto-configuration feature efficiently configures Framework components with default settings. In cases where requirements differ, simple configurations allow for easy tuning of components.
  4. Production-Grade Deployment: Spring Boot empowers the deployment of applications that meet production-grade standards, ensuring stability and reliability.
  5. Enhanced Non-Functional Aspects: Beyond core functionality, Spring Boot addresses non-functional aspects of application development. This includes features like debugging, automatic restart during development, and robust tools for metrics and memory management.

In essence, Spring Boot revolutionizes Spring Framework application development by offering an array of capabilities that streamline the process, bolster production readiness, and enhance the development experience.

Further Reading:

Spring Boot Official Documentation: Explore the official documentation for comprehensive information about Spring Boot’s features, configurations, and best practices.

Spring Cloud Config Client

Spring Cloud Config Client Example

During the boot-up of the service, the Spring Cloud Config Client connects to the config server and fetches the service-specific configuration over the network. This configuration is then injected into the Environment object of the IOC (Inversion of Control) container, which is used to start the application.

Create the Spring Boot Project

Let’s kick off by creating a Spring Boot Maven project named “spring-cloud-config-client.” To achieve this, there are two paths you can take: either visit the Spring Initializer website Spring Initializer or leverage your trusted Integrated Development Environment (IDE). The resulting project structure is as follows.

Spring cloud config client

Spring Cloud Config Client Example

To understand the implementation of Spring Cloud Config Client, let’s walk through a hands-on example.

Begin by creating a Spring Boot project and adding the following dependencies to your pom.xml:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

Implementing Spring Cloud Config Client in Microservices: A Step-by-Step Guide

In your main application class, the heart of your Spring Boot application, bring in essential packages and annotations. Introduce the @RefreshScope annotation, a key enabler for configuration refreshing. Here’s a snippet to illustrate:

Java
@SpringBootApplication
@RefreshScope
public class CloudConfigClientApplication implements ApplicationRunner{

	@Autowired
	private StudentsController studentsController;
	
	@Value("${author}")
	private String author;
	
	public static void main(String[] args) {
		SpringApplication.run(CloudConfigClientApplication.class, args);
	}

	@Override
	public void run(ApplicationArguments args) throws Exception {
		System.out.println(studentsController.getStudentDetails().getBody());
		System.out.println("Author ** "+author);
	}

}

Include the following configurations in your application.properties or application.yml file to set up Spring Cloud Config

management:
  endpoint:
    refresh:
      enabled: true
  endpoints:
    web:
      exposure:
        include:
        - refresh
      
spring:
  application:
    name: cloud-config-client
  config:
    import: configserver:http://localhost:8888/api/v1
  profiles:
    active: dev
  main:
    allow-circular-references: true

In your main class, import necessary packages and annotations. Add the @RefreshScope annotation to enable configuration refresh. Here’s an example:

@SpringBootApplication
@RefreshScope
public class CloudConfigClientApplication implements ApplicationRunner{

	@Autowired
	private StudentsController studentsController;
		
	public static void main(String[] args) {
		SpringApplication.run(CloudConfigClientApplication.class, args);
	}
	
	//printing student details from config server.
	@Override
	public void run(ApplicationArguments args) throws Exception {
		System.out.println(studentsController.getStudentDetails().getBody());
	}

}

Here’s an example of a simple Student bean class

public class Student {

	private String studentName;
	private String studentRollNo;
	private String studentEmail;
	private String phone;
	//Generate getters and setters
}

Create a student REST controller

@RestController
@RequestMapping("/api/v1")
public class StudentsController {

	@Autowired
	private Environment env;
		
	@GetMapping("/students")
	public ResponseEntity<Student> getStudentDetails(){
		Student student = new Student();
		student.setStudentName(env.getProperty("student.name"));
		student.setStudentRollNo(env.getProperty("student.rollNo"));
		student.setStudentEmail(env.getProperty("student.email"));
		student.setPhone(env.getProperty("student.phone"));
		return new ResponseEntity<Student>(student, HttpStatus.OK);
	}
}
  1. Start the Spring Cloud Config Server: Before setting up the Spring Cloud Config Client, ensure the Spring Cloud Config Server is up and running.
  2. Start the Spring Cloud Config Client: Next, initiate the Spring Cloud Config Client by starting your application with the desired profile and Spring Cloud Config settings using the command below:
Bash
java  -Dspring.profiles.active=dev  -jar target/your-application.jar

Replace:

  • dev with the desired profile (dev, sit, uat, etc.).
  • http://config-server-url:8888 with the actual URL of your Spring Cloud Config Server.
  • your-application.jar with the name of your application’s JAR file.

After starting the application with the specified Spring Cloud Config settings, you can access the following local URL: http://localhost:8081/api/v1/students. The output looks like below when you hit this endpoint:

{
    "studentName": "Sachin",
    "studentRollNo": "1234",
    "studentEmail": "sachin1@gmail.com",
    "phone": "123456781"
}

For more information on setting up and using Spring Cloud Config Server, you can refer Spring Config Server blog post at https://javadzone.com/spring-cloud-config-server/.

In a nutshell, Spring Cloud Config Client enables seamless integration of dynamic configurations into your Spring Boot application, contributing to a more adaptive and easily maintainable system. Dive into the provided example and experience firsthand the benefits of efficient configuration management. If you’d like to explore the source code, it’s available on my GitHub Repository: GitHub Repository Link. Happy configuring!

Spring Boot Eureka Discovery Client

Spring Boot Eureka Discovery Client

In today’s software landscape, microservices are the building blocks of robust and scalable applications. The Spring Boot Eureka Discovery Client stands as a key enabler, simplifying the intricate web of microservices. Discover how it streamlines service discovery and collaboration.

Spring Boot Eureka Client Unveiled

Diving Deeper into Spring Boot Eureka Client’s Vital Role

The Spring Boot Eureka Client plays an indispensable role within the Eureka service framework. It serves as the linchpin in the process of discovering services, especially in the context of modern software setups. This tool makes the task of finding and working with services in microservices exceptionally smooth.

Your Guide to Effortless Microservices Communication

Navigating Microservices with the Spring Boot Eureka Client

Picture the Eureka Discovery Client as an invaluable guide in the world of Eureka. It simplifies the intricate process of connecting microservices, ensuring seamless communication between different parts of your system.

Spring Boot Eureka Discovery Client as Your Service Discovery Library

Delving Deeper into the Technical Aspects

From a technical standpoint, think of the Eureka Discovery Client as a library. When you integrate it into your microservices, it harmonizes their operation with a central Eureka Server, acting as a hub that keeps real-time tabs on all available services across the network.

Empowering Microservices with Spring Boot Eureka Client

Discovering and Collaborating with Ease

Thanks to the Eureka Discovery Client, microservices can effortlessly join the network and discover other services whenever they need to. This capability proves invaluable, particularly when dealing with a multitude of services that require quick and efficient collaboration.

Simplifying Setup, Strengthening Microservices

Streamlining Setup Procedures with the Spring Boot Eureka Client

One of the standout advantages of the Eureka Discovery Client is its ability to simplify the often complex setup procedures. It ensures that services can connect seamlessly, freeing you to focus on enhancing the resilience and functionality of your microservices.

Getting Started with Spring Boot Eureka Client

Your Journey Begins Here

If you’re contemplating the use of the Spring Boot Eureka Client, here’s a step-by-step guide to set you on the right path:

Setting Up Eureka Server

Establishing Your Eureka Server as the Central Registry

Before integrating the Eureka Discovery Client, you must have a fully operational Eureka Server. This server serves as the central registry where microservices register themselves and discover other services. For detailed instructions, refer to the Eureka Server Setup Guide.

Adding Dependencies for Spring Boot Eureka Discovery Client

Integrating Essential Dependencies into Your Microservice Project

In your microservice project, including the required dependencies is essential. If you’re leveraging Spring Boot, add the spring-cloud-starter-netflix-eureka-client dependency to your project’s build file. For instance, in a Maven project’s pom.xml or a Gradle project’s build.gradle:

Eureka Discovery Client Maven Dependency

XML
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

Eureka Client Gradle Dependency

Integrating the Eureka Client Dependency in Your Gradle Project

To include the Spring Boot Eureka Client in your Gradle project, add the following dependency to your build.gradle file:

Java
dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
}

Configuring Application Properties

Optimizing the Spring Boot Eureka Client Configuration

Tailoring your microservice’s properties and Eureka client settings in the application.properties file is crucial for optimal usage of the Spring Boot Eureka Client. Below is a sample configuration:

Java
spring:
  application:
    name: eureka-discovery-client-app
server:
  port: 8089
eureka:
  client:
    register-with-eureka: true
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
  instance:
     preferIpAddress: true

Enabling Spring Boot Eureka Discovery Client

Activating the Power of Spring Boot Eureka Client

To enable the Spring Boot Eureka Client functionality in your Java code, annotate your main application class as shown below:

Java
@EnableDiscoveryClient
@SpringBootApplication
public class EurekaClientApplication {

	public static void main(String[] args) {
		SpringApplication.run(EurekaClientApplication.class, args);
	}
}
Service Registration and Discovery

Automated Service Registration and Effortless Discovery

Once your microservice initializes, it will autonomously register itself with the Eureka Server, becoming a part of the network. You can confirm this registration by examining the Eureka Server’s dashboard. Simply visit your Eureka Server’s URL, e.g., http://localhost:8761/

Spring Boot Eureka Discovery Client
Seamlessly Discovering Services

Locating Services in Your Microservices Architecture

To locate other services seamlessly within your microservices architecture, leverage the methods provided by the Eureka Discovery Client. These methods simplify the retrieval of information regarding registered services. Programmatically, you can acquire service instances and their corresponding endpoints directly from the Eureka Server.

For further reference and to explore practical examples, check out the source code illustrating this process on our GitHub repository.

Reload Application Properties in Spring Boot: 5 Powerful Steps to Optimize

Refresh Configs without restart

In the world of Microservices architecture, efficiently managing configurations across multiple services is crucial. “Reload Application Properties in Spring Boot” becomes even more significant when it comes to updating configurations and ensuring synchronization, as well as refreshing config changes. However, with the right tools and practices, like Spring Cloud Config and Spring Boot Actuator, this process can be streamlined. In this guide, we’ll delve into how to effectively propagate updated configurations to all Config Clients (Microservices) while maintaining synchronization.

Spring Cloud Config Server Auto-Reload

When you make changes to a configuration file in your config repository and commit those changes, the Spring Cloud Config Server, configured to automatically reload the updated configurations, becomes incredibly useful for keeping your microservices up to date.

To set up auto-reloading, you need to configure the refresh rate in the Config Server’s configuration file, typically located in application.yml or application.properties. The “Reload Application Properties in Spring Boot” guide will walk you through this process, with a focus on the refresh-rate property, specifying how often the Config Server checks for updates and reloads configurations.

spring:
  cloud:
    config:
      server:
        git:
          refresh-rate: 3000 # Set the refresh rate in milliseconds

Refresh Config Clients with Spring Boot Actuator

To get started, add the Spring Boot Actuator dependency to your microservice’s project. You can do this by adding the following lines to your pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

While the Config Server reloads configurations automatically, the updated settings are not automatically pushed to the Config Clients (microservices). To make sure these changes are reflected in the Config Clients, you must trigger a refresh.

This is where the “Reload Application Properties in Spring Boot” guide becomes crucial. Spring Boot Actuator provides various management endpoints, including the refresh endpoint, which is essential for updating configurations in Config Clients.

Reload Application Properties in Spring Boot: Exposing the Refresh Endpoint

Next, you need to configure Actuator to expose the refresh endpoint. This can be done in your microservice’s application.yml or .properties file:

management:
  endpoint:
    refresh:
      enabled: true
  endpoints:
    web:
      exposure:
        include: refresh

Java Code Example

Below is a Java code example that demonstrates how to trigger configuration refresh in a Config Client microservice using Spring Boot:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.cloud.context.refresh.ContextRefresher;

@SpringBootApplication
public class ConfigClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigClientApplication.class, args);
    }
}

@RestController
@RefreshScope
public class MyController {

    @Value("${example.property}")
    private String exampleProperty;

    private final ContextRefresher contextRefresher;

    public MyController(ContextRefresher contextRefresher) {
        this.contextRefresher = contextRefresher;
    }

    @GetMapping("/example")
    public String getExampleProperty() {
        return exampleProperty;
    }

    @GetMapping("/refresh")
    public String refresh() {
        contextRefresher.refresh();
        return "Configuration Refreshed!";
    }
}
  1. Reload Application Properties:
  • To trigger a refresh in a Config Client microservice, initiate a POST request to the refresh endpoint. For example: http://localhost:8080/actuator/refresh.
  • This request will generate a refresh event within the microservice.

Send a POST Request with Postman Now, open Postman and create a POST request to your microservice’s refresh endpoint. The URL should look something like this:

Reload Application Properties in Spring Boot

2. Bean Reloading:

  • Configurations injected via @Value annotations in bean definitions adorned with @RefreshScope will be reloaded when a refresh is triggered.
  • If values are injected through @ConfigurationProperties, the IOC container will automatically reload the configuration.

By following these steps and incorporating the provided Java code example, you can effectively ensure that updated configurations are propagated to your Config Clients, and their synchronization is managed seamlessly using Spring Cloud Config and Spring Boot Actuator. This approach streamlines configuration management in your microservices architecture, allowing you to keep your services up to date efficiently and hassle-free.

“In this guide, we’ve explored the intricacies of Spring Cloud Config and Spring Boot Actuator in efficiently managing and refreshing configuration changes in your microservices architecture. To delve deeper into these tools and practices, you can learn more about Spring Cloud Config and its capabilities. By leveraging these technologies, you can enhance your configuration management and synchronization, ensuring seamless operations across your microservices.”

Related Articles:

Spring Boot Eureka Server Tutorial

In the ever-evolving realm of microservices architecture, services like Netflix Eureka Server are spread across various nodes within a cluster. Unlike monolithic applications, where services are tightly integrated, microservices often run on specific cluster nodes, presenting a challenge for client applications striving to connect with them.

Introduction: Simplifying Microservices with Eureka Server

Microservices are a powerful architectural approach for building scalable and maintainable systems. However, in a distributed microservices environment, locating and connecting with individual services can be complex. This is where the Netflix Eureka Server comes to the rescue. Eureka Server simplifies service discovery, enabling microservices to effortlessly locate and communicate with each other within a cluster.

Understanding Eureka Server

Eureka Server, often referred to as Netflix Eureka Server, acts as a centralized service registry within a microservices cluster. During initialization, each microservice registers its information with the Eureka Server. This typically includes the service’s name, network location, and other pertinent details.

Real-World Example: Eureka Server in Action

To better understand the practical utility of Eureka Server, let’s delve into a real-world example. Imagine you’re responsible for building a large-scale e-commerce platform composed of various microservices. These microservices include the product catalog, user authentication, payment processing, order management, and more.

In a microservices-based architecture, these services may be distributed across different servers or containers within a cloud-based environment. Each service needs to communicate with others efficiently to provide a seamless shopping experience for customers.

This is where Eureka Server comes into play. By integrating Eureka Server into your architecture, you create a centralized service registry that keeps track of all available microservices. Let’s break down how it works:

  1. Service Registration: Each microservice, such as the product catalog or payment processing, registers itself with the Eureka Server upon startup. It provides essential information like its name and network location.
  2. Heartbeats: Microservices send regular heartbeats to Eureka Server to indicate that they are operational. If a service stops sending heartbeats (e.g., due to a failure), Eureka Server can mark it as unavailable.
  3. Service Discovery: When one microservice needs to communicate with another, it queries the Eureka Server to discover the service’s location. This eliminates the need for hardcoding IP addresses or endpoints, making the system more dynamic and adaptable.
  4. Load Balancing: Eureka Server can also help with load balancing. If multiple instances of a service are registered, Eureka can distribute requests evenly, improving system reliability and performance.

In our e-commerce example, the product catalog service can easily locate and interact with the payment processing service using Eureka Server. As traffic fluctuates, Eureka Server ensures that requests are distributed optimally, preventing overloading on any single instance.

By employing Eureka Server, you streamline the development, deployment, and scaling of your microservices-based e-commerce platform. It simplifies service discovery and enhances the overall reliability of your system.

This real-world example demonstrates how Eureka Server can be a game-changer in managing and scaling microservices, making it a valuable tool in modern software development.

Eureka Server Spring Boot Integration

One of the strengths of Eureka Server is its seamless integration with the Spring Boot framework through Spring Cloud. By incorporating the spring-cloud-starter-eureka-server dependency into your project, configuring the server becomes straightforward. This simplification expedites the setup process, allowing microservices, especially those built with Spring Boot, to quickly join the Eureka ecosystem.

Initiating the Project Spring cloud config client project

Let’s kick off by creating a Spring Boot Maven project named “eureka-server” To achieve this, there are two paths you can take: either visit the Spring Initializer website Spring Initializer or leverage your trusted Integrated Development Environment (IDE). The resulting project structure is as follows.

eureka server

Implementing Eureka Server

Maven Dependency for Eureka Server

For projects managed with Maven, you’ll often search for the following dependency to include in your pom.xml file:

XML
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

Gradle Dependency for Eureka Server

If you prefer Gradle for your project, many search for this dependency to add to your build.gradle file:

XML
dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
}

Eureka Server Configuration

To configure Eureka Server, create an application.yml or application.properties file. Below is an example configuration in YAML format:

Java
spring:
  application:
    name: eureka-server

server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    healthcheck:
      enabled: true

Eureka Server Configuration

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

Running the Eureka Server Application

To begin using Eureka Server, follow these steps to run the application on your local machine without any plagiarism:

  1. Clone the Repository:
  • Launch your terminal and navigate to the desired directory where you intend to clone the Eureka Server repository.
  • Execute the following command to clone the repository without any copied content:
Bash
git clone https://github.com/askPavan/eureka-server

2. Build the Application:

  • Go to the directory where you have cloned the Eureka Server repository.
  • Utilize the following command to build the Eureka Server application:

3. Run the application.

4. Access the Eureka Server Dashboard:

  • Once the server is up and running, open your web browser.
  • Enter the following URL to access the Eureka Server dashboard:
Java
http://localhost:8761/

For the Eureka Client application, you can use the following URL: Eureka Client App URL

4. View the Eureka Server Output:

  • You will now see the Eureka Server dashboard, which displays information about the registered services and their status.
  • Explore the dashboard to see the services that have registered with Eureka Server.

Example Output

Here is an example of what the Eureka Server dashboard might look like once the server is running:

what is eureka server

By running both the Eureka Server and Eureka Client applications, you can observe how services are registered and discovered in the Eureka ecosystem. This hands-on experience will help you better understand the functionality of Eureka Server and its interaction with client applications. For the source code of the Eureka Client, you can refer to this GitHub repository.

Exploring Practical Examples

For hands-on experience and practical illustrations, you can explore our GitHub repository. This repository contains real-world implementations of Eureka Server using Spring Boot.

Conclusion: Simplifying Microservices with Eureka Server

In conclusion, Eureka Server is a potent tool for simplifying microservices in a distributed architecture. Its seamless integration with Spring Boot streamlines the setup process, enabling you to efficiently implement Eureka Server in your microservices ecosystem.

Eureka Server facilitates effortless service discovery, allowing microservices to seamlessly identify and communicate with one another. This capability is indispensable for constructing robust and efficient distributed systems.

What are Microservices?

What are Microservices

Spring Boot Microservices, an innovative approach to developing software applications, involve decomposing the software application into

  • Smaller
  • Independent
  • Deployable
  • Loosely coupled
  • Collaborative Services

Services through which we can bring down the complexity in understanding the application and ease the delivery of the application.

Before Moving to Microservices We need to understand Monolithic Architecture.

Microservices vs Monolith

What is Monolithic Application Architecture?

Monolithic application has several modules as part of it, all of these modules are built as one single system and delivered as a single deployable artifact, which is nothing but monolithic application development architecture.

Microservices Architecture:

What are microservices

What are the reasons for choosing monolithic architecture

1. Easy to scale the applications.

2. You won’t to adopt continuous integration and delivery for your application

3. Developers will be able to quickly understand the application and be productive in development and delivery

Advantages of Monolithic Architecture

1. Achieving scalability is very easy :

if the load on the system is high, then we can copy the single deployable artifact of our application across multiple servers across the cluster.

2. Easy to understand

The entire software system has been built out of one single code base, the entire team of developers knows everything about the system they are working on. understanding such a software system out of a single code base is very easily and developers can be productive in building and delivery the application

3. As the entire system is build as a single deployable artifact we can easily achieve continuous integration and delivery(CI/CD) without any module dependency complexities

4. Monolithic architecture-based application development is better suited for applications that are less/moderate in size but if the application grows bigger in size, managing the development and delivery aspects of the system through monolithic architecture brings lot of problems.

Disadvantage of Monolithic Architecture

1. The entire system is built out of single codebase:

Many of the developers will be afraid to understand such a big system and feel very complicated in understanding and developing it.

Many of the developers don’t know how to achieve modularity in writing the code due to which they quickly exploit the code base.

A change impact is going to be very high and difficult to handle.

2. Overloaded (IDE)

Due to the huge code base, the ide’s cannot handle in managing the code.

To develop the code sophisticatedly by the developer he should ensure the code is loaded and in clean state in ide, he can write compilable code.

3. overloaded web containers

Deploying a huge application, makes the container take more time in starting up, and during debugging the application repeated deployment of the application for verifying code changes takes lot of time and kills the developer’s productivity.

4. Scalability

In monolithic architecture scalability is achieved in one dimension only which means horizontal scaling. If the application receives more volumes of request, even though the traffic comes to one or few modules of the system, we can only scale the system as a whole by deploying on multiple servers due to which

  i). The cost of achieving the scalability is going to be very high, as the whole system is scaled up we need to buy big servers with huge computing capacity

  ii). different parts of the system as different computing requirements, like few modules are memory intensive, few modules are CPU intensive, during scaleup we cannot consider such requirements in scaling up the system

5. Scaling up the Team is difficult

The more/bigger the application grows, we need more resources in the team to work on, but handling such a huge team is going to be pain point, as people cannot independently work on separate functional modules due to dependencies. resource handling becomes much complex in distributing the work.

6. Long-Term commitment to technology stack

While building application with monolithic architecture, we need to be committed to an technical stack in building the application for a long-term. because adopting new technologies requires the entire system to be migrated as it exists as a single code base.

7. CI/CD is going to be very difficult

When and ever a module has been finished its development, we cannot release it independently as other modules code changes are also part of the same code base due to long term release planning and deployments are required.

Microservices Architecture:

Microservices using Spring Boot

Microservices is an architectural style of developing software applications. In microservices based architecture we decompose the software application into

  • Smaller
  • Independent
  • Deployable
  • Loosely coupled
  • Collaborative Services

We develop the application by breaking down the entire application in independent smaller services that can be developed and delivered by individual team of developers

We identify the business responsibilities and break them into independent services/projects which are built on REST architectural principles by independent teams and are deployable separately

Benefits of developing application on microservices architecture

1. They can be different team of developers can independently develop, test and delivery the system

2. Each service we develop has a separate source code which can be understood easily by the developer and can maintain it

  •     – achieving modularity becomes easy
  •     – change impact will be very minimal
  •     – debugging the code becomes very easy

3. Every team has their independent separate source code, they can get the code up quickly in an ide and can proceed for development

4. The more the services/functionality we can broke down into multiple independent services can choose more teams to develop parallelly

5. scalability

  In microservices based application as each services/module is being deployed separately we can achieve vertical scaling

  •   depends on the traffic patterns we can scale a specific module or service quickly rather than the entire system where the cost of scalability is very less as we are scaling a piece of the system
  •   we can customize the machine capacity based on the nature of the service like cpu oriented/memory-oriented services

6. Adopting the new technologies can be really faster, either we can choose one of the services to be migrated out of the current system or we can build new services on the latest technology easily

7. Easy to achieve ci/cd as every service is independent of the others, we can deliver a service without bothering about the others.

Advantages of using microservices architecture?

  • 1. as the smaller codebase it is easy to manage within the ide.
  • 2. application servers are not overloaded and the application quickly gets started and debugging the application will not takes more time because of smaller code base
  • 3. scalability we can achieve vertical scalability in microservices
  •   – a specific module can be scaled up independent of the whole system based on the traffic/load
  •   – we can customize the computing aspects in scaling the service like cpu bounded and memory bounded
  • 4. we can adopt new technologies quickly, as services are development independently, we can migrate a service or develop new services are latest technologies
  • 5. easy to understand and develop the application as each service is built out of its independent code base developer often feel very easy in understanding the system. modularity can be achieved very easily. impact of a  change request is minimal and easy to manage. less complex and easy to maintain. debugging the application is going to be very easy.
  • 6. ci/cd can be adopted easily
  • 7. we can have multiple teams developing the system parallelly

Conclusion:

In the realm of software development, Spring Boot Microservices have emerged as a game-changer, offering agility, scalability, and modularity. We’ve explored the fundamental concepts behind microservices-based architecture and how they can reduce the complexity of software applications while enhancing delivery.

However, it’s essential to remember that successfully implementing microservices goes beyond theoretical knowledge. To master this architectural style and unlock its full potential, you’ll need to dive into practical implementations and real-world examples.

For More Practical Information:

Fortunately, all the practical tutorials and hands-on guidance you need to embark on your microservices journey are right here on our blog. Explore our comprehensive tutorials, case studies, and examples to gain not only a theoretical understanding but also the practical skills to apply microservices effectively in your software projects.

So, roll up your sleeves, venture into the world of microservices, and discover the transformative power they can bring to your software development endeavors—available exclusively on our blog!

When it comes to implementing microservices architecture, it’s crucial to have a solid understanding of the key principles and best practices. For more in-depth insights and resources, I recommend visiting Microservices.io.