Vertx-web – Sample Application


Vert.x-Web is a set of building blocks for building web applications with Vert.x. Vert.x-Web can be used to create classic server-side web applications, RESTful web applications, ‘real-time’ (server push) web applications, or any other kind of web application. Vert.x-Web is a great fit for writing RESTful HTTP micro-services. In this post, we will discuss about writing a developing a basic rest api using vert.x-web.

Here is the sample API using Vert.x-Web:

package com.malliktalksjava.vertx.samples;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.Router;

public class MainVerticle extends AbstractVerticle {

  @Override
  public void start(Promise<Void> startPromise) throws Exception {
    HttpServer server = vertx.createHttpServer();
    Router router = Router.router(vertx);

    router.route().handler(ctx -> {

      // This handler will be called for every request
      HttpServerResponse response = ctx.response();
      response.putHeader("content-type", "application/json");

      // Write to the response and end it
      response.end("Hello from Vert.x-Web!" );
    });

    server.requestHandler(router).listen(8888);
  }
}

Create an HTTP server as before, then create a router. Then create a simple route with no matching criteria so it will match all requests that arrive on the server.
Then specify a handler for that route. That handler will be called for all requests that arrive on the server.
The object that gets passed into the handler is a RoutingContext – this contains the standard Vert.x HttpServerRequest and HttpServerResponse but also various other useful stuff that makes working with Vert.x-Web simpler.
For every request that is routed there is a unique routing context instance, and the same instance is passed to all handlers for that request.
Once the handler is setup, set the request handler of the HTTP server to pass all incoming requests to handle.

Try to access the application on using http://localhost:8888. Here is the output:

Building Reactive Applications with Vert.x: A Comprehensive Tutorial


In today’s fast-paced, highly concurrent world, building scalable and reactive applications is a necessity. Vert.x, a powerful toolkit for building reactive applications on the Java Virtual Machine (JVM), provides developers with an excellent framework to achieve this. In this tutorial, we will explore the fundamentals of Vert.x and guide you through building a reactive application from scratch.

Table of Contents:

  1. What is Vert.x?
  2. Setting Up the Development Environment
  3. Understanding Vert.x Core Concepts
    • 3.1. Verticles
    • 3.2. Event Bus
    • 3.3. Asynchronous Programming Model
  4. Building a Simple Vert.x Application
    • 4.1. Creating a Maven Project
    • 4.2. Writing a Verticle
    • 4.3. Deploying and Running the Verticle
  5. Scaling Vert.x Applications
    • 5.1. Vert.x Clustering
    • 5.2. High Availability
  6. Integrating with Other Technologies
    • 6.1. Working with HTTP and WebSockets
    • 6.2. Integrating with Databases
    • 6.3. Reactive Messaging with Apache Kafka
  7. Unit Testing Vert.x Applications
    • 7.1. Vert.x Unit Testing Framework
    • 7.2. Mocking Dependencies
  8. Deploying Vert.x Applications
    • 8.1. Packaging Vert.x Applications
    • 8.2. Running Vert.x on Docker
    • 8.3. Deploying to the Cloud
  9. Monitoring and Debugging Vert.x Applications
    • 9.1. Logging and Metrics
    • 9.2. Distributed Tracing with OpenTelemetry
  10. Conclusion

Section 1: What is Vert.x?

Vert.x is an open-source, reactive, and polyglot toolkit designed for building scalable and high-performance applications. It provides a powerful and flexible framework for developing event-driven and non-blocking applications on the Java Virtual Machine (JVM). Vert.x enables developers to create reactive systems that can handle a large number of concurrent connections and process events efficiently.

At its core, Vert.x embraces the principles of the Reactive Manifesto, which include responsiveness, scalability, resilience, and message-driven architecture. It leverages an event-driven programming model, allowing developers to build applications that are highly responsive to incoming events and messages.

Key Features of Vert.x:

  1. Polyglot Support: Vert.x supports multiple programming languages, including Java, Kotlin, JavaScript, Groovy, Ruby, and Ceylon. This flexibility allows developers to leverage their language of choice while benefiting from Vert.x’s features.
  2. Event Bus: The Vert.x event bus enables communication and coordination between different components of an application, both within a single instance and across distributed instances. It supports publish/subscribe and point-to-point messaging patterns, making it easy to build decoupled and scalable systems.
  3. Asynchronous and Non-Blocking: Vert.x promotes non-blocking I/O operations and asynchronous programming. It utilizes a small number of threads to handle a large number of concurrent connections efficiently. This enables applications to scale and handle high loads without incurring the overhead of traditional thread-per-connection models.
  4. Reactive Streams Integration: Vert.x seamlessly integrates with Reactive Streams, a specification for asynchronous stream processing with non-blocking backpressure. This integration allows developers to build reactive applications that can handle backpressure and efficiently process streams of data.
  5. Web and API Development: Vert.x provides a rich set of APIs and tools for building web applications and RESTful APIs. It supports the creation of high-performance HTTP servers, WebSocket communication, and the integration of various web technologies.
  6. Clustering and High Availability: Vert.x offers built-in support for clustering, allowing applications to scale horizontally by running multiple instances across multiple nodes. It provides mechanisms for event bus clustering, distributed data structures, and failover, ensuring high availability and fault tolerance.
  7. Integration Ecosystem: Vert.x integrates with various technologies and frameworks, including databases, messaging systems (such as Apache Kafka and RabbitMQ), reactive streams implementations, service discovery mechanisms, and more. This enables developers to leverage existing tools and services seamlessly.

Vert.x is well-suited for developing a wide range of applications, including real-time systems, microservices, APIs, IoT applications, and reactive web applications. Its lightweight and modular architecture, combined with its reactive nature, makes it an excellent choice for building scalable and responsive applications that can handle heavy workloads and concurrent connections.

Whether you’re a Java developer or prefer other JVM-compatible languages, Vert.x offers a powerful toolkit to create reactive, event-driven applications that can meet the demands of modern distributed systems.

Section 2: Setting Up the Development Environment

Setting up the development environment for Vert.x involves a few essential steps. Here’s a step-by-step guide to getting started:

Step 1: Install Java Development Kit (JDK)

  • Ensure that you have the latest version of JDK installed on your system. Vert.x requires Java 8 or higher. You can download the JDK from the Oracle website or use OpenJDK, which is a free and open-source alternative.

Step 2: Install Apache Maven (optional)

  • While not mandatory, using Apache Maven simplifies the management of dependencies and building Vert.x projects. You can download Maven from the Apache Maven website and follow the installation instructions specific to your operating system.

Step 3: Set up a Project

  • Create a new directory for your Vert.x project. Open a terminal or command prompt and navigate to the directory you just created.

Step 4: Initialize a Maven Project (optional)

  • If you chose to use Maven, you can initialize a new Maven project by running the following
mvn archetype:generate -DgroupId=com.example -DartifactId=my-vertx-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

This command creates a basic Maven project structure with a sample Java class.

Step 5: Add Vert.x Dependencies

Open the pom.xml file in your project directory (if using Maven) and add the following dependencies:

<dependencies>
    <dependency>
        <groupId>io.vertx</groupId>
        <artifactId>vertx-core</artifactId>
        <version>4.1.1</version>
    </dependency>
</dependencies>

This configuration adds the Vert.x core dependency to your project.

Step 6: Build the Project (optional)

  • If you’re using Maven, you can build your project by running the following command:
mvn clean package

This command compiles your code, resolves dependencies, and creates a JAR file in the target directory.

Step 7: Start Coding

  • You’re now ready to start developing with Vert.x. Create your Verticle class, which represents a component in a Vert.x application, and implement the necessary logic.

Step 8: Run the Application

To run a Vert.x application, you can use the following command in your project directory (assuming you’ve already built the project with Maven):

java -jar target/my-vertx-app-1.0-SNAPSHOT.jar

Replace my-vertx-app-1.0-SNAPSHOT.jar with the actual name of your JAR file.

Congratulations! You have successfully set up your development environment for Vert.x. You can now start building reactive applications using the Vert.x toolkit. Remember to refer to the Vert.x documentation and explore its rich set of features and APIs to harness its full potential. Happy coding!

Section 3: Understanding Vert.x Core Concepts

To effectively work with Vert.x, it’s crucial to understand its core concepts. Let’s explore the key concepts of Vert.x:

  1. Verticles:
    • Verticles are the building blocks of a Vert.x application. They represent individual components or units of work that run concurrently within the Vert.x ecosystem.
    • Verticles are lightweight and can be single-threaded or multi-threaded, depending on the configuration. They communicate with each other through the event bus.
    • Verticles can handle various tasks, such as handling HTTP requests, processing messages, accessing databases, or performing background tasks.
    • Vert.x provides different types of verticles, including standard verticles, worker verticles (for CPU-intensive tasks), and periodic verticles (for scheduled tasks).
  2. Event Bus:
    • The event bus is a powerful communication mechanism provided by Vert.x that allows different verticles to exchange messages asynchronously.
    • Verticles can publish messages to the event bus, and other verticles can subscribe to receive those messages based on different patterns or addresses.
    • The event bus enables loose coupling between verticles, making it easy to build distributed and scalable systems.
    • Vert.x provides different messaging patterns, including publish/subscribe and point-to-point messaging, which can be used with the event bus.
  3. Asynchronous Programming Model:
    • Vert.x promotes an asynchronous programming model, which is fundamental to building reactive applications.
    • Asynchronous programming allows non-blocking execution of tasks, enabling applications to handle high loads and concurrency efficiently.
    • Vert.x APIs are designed to work asynchronously, allowing developers to write non-blocking code that can scale well.
    • Callbacks, futures/promises, and reactive streams are common patterns used in Vert.x to handle asynchronous operations.
  4. Reactive Streams Integration:
    • Vert.x integrates seamlessly with Reactive Streams, a standard for asynchronous stream processing with non-blocking backpressure.
    • Reactive Streams provide a set of interfaces and protocols for building reactive applications that can handle backpressure and efficiently process streams of data.
    • Vert.x includes support for Reactive Streams, enabling developers to use reactive streams implementations like RxJava, Reactor, or CompletableFuture seamlessly within Vert.x applications.

Understanding these core concepts is essential for harnessing the power of Vert.x. With Verticles, the Event Bus, Asynchronous Programming, and Reactive Streams, you can build scalable, responsive, and high-performance applications. By leveraging these concepts, you can create loosely coupled, concurrent systems that efficiently handle large workloads and enable seamless communication between components.

Section 4: Building a Simple Vert.x Application

To build a simple Vert.x application, we will go through the process of creating a basic Verticle, deploying it, and running the application. Follow these steps:

Step 1: Create a Maven Project

  • If you haven’t already set up a Maven project, follow the instructions in the “Setting Up the Development Environment” section to create a new Maven project or use an existing one.

Step 2: Add Vert.x Dependency

  • Open the pom.xml file of your Maven project and add the Vert.x dependency within the <dependencies> section:
<dependency>
    <groupId>io.vertx</groupId>
    <artifactId>vertx-core</artifactId>
    <version>4.1.1</version>
</dependency>
  • This adds the Vert.x core dependency to your project.

Step 3: Create a Verticle

  • In your project, create a new Java class representing your Verticle. For example, you can create a class named MyVerticle.
  • Make sure your class extends io.vertx.core.AbstractVerticle.
  • Override the start() method to define the behavior of your Verticle when it is deployed. For simplicity, let’s print a message to the console:
public class MyVerticle extends AbstractVerticle {

    @Override
    public void start() {
        System.out.println("MyVerticle has been deployed!");
    }
}

Step 4: Deploy and Run the Verticle

  • In your main application class (e.g., App.java), deploy the MyVerticle by creating a Vertx instance and using the deployVerticle() method:
import io.vertx.core.Vertx;

public class App {
    public static void main(String[] args) {
        Vertx vertx = Vertx.vertx();
        vertx.deployVerticle(new MyVerticle());
    }
}

Step 5: Run the Application

  • Compile and run the application using your preferred method (e.g., Maven command or an integrated development environment).
  • Once the application starts, you should see the message “MyVerticle has been deployed!” printed in the console.

Congratulations! You have successfully built a simple Vert.x application. This example demonstrates the basic structure of a Verticle and how to deploy it using the Vertx instance. You can further enhance your application by adding more Verticles, handling HTTP requests, or integrating with other technologies using the Vert.x APIs.

Section 5: Scaling Vert.x Applications

Scaling Vert.x applications is crucial to handle increased workloads and ensure high availability. Vert.x provides several mechanisms for scaling applications. Let’s explore two important aspects of scaling Vert.x applications: Vert.x Clustering and High Availability.

  1. Vert.x Clustering:
    • Vert.x clustering allows you to run multiple Vert.x instances across multiple nodes to distribute the load and handle high concurrency.
    • Clustering is achieved through a built-in event bus, which enables communication between different Vert.x instances running on different nodes.
    • When multiple Vert.x instances are clustered, they form a distributed event bus network, allowing verticles to communicate seamlessly.
    • To enable clustering, you need to configure your Vert.x instances to join the same cluster by specifying a cluster manager implementation.
    • Vert.x provides different cluster manager implementations, such as Hazelcast, Apache Ignite, Infinispan, and more, that handle the management and coordination of the clustered instances.
    • By leveraging clustering, you can horizontally scale your Vert.x application by adding more nodes to the cluster, enabling it to handle higher workloads and providing fault tolerance.
  2. High Availability:
    • High availability ensures that your Vert.x application remains operational even in the face of failures.
    • Vert.x provides features and best practices to achieve high availability in different scenarios:
      • Circuit Breaker Pattern: Vert.x offers a built-in circuit breaker pattern implementation, allowing you to protect your application from cascading failures when dealing with remote services. It helps to manage failure thresholds, timeouts, and retries.
      • Reactive Streams and Backpressure: Vert.x integrates with Reactive Streams, which enables efficient handling of streams of data with non-blocking backpressure. This helps to prevent overloading downstream systems and ensures resilience and stability in the face of varying workloads.
      • Fault Tolerance: Vert.x provides mechanisms to handle failures and recover from them. For example, when a verticle fails, Vert.x can automatically redeploy it to ensure that the system continues running smoothly. Additionally, you can leverage cluster-wide shared data structures to maintain the state and recover from failures.
      • Monitoring and Alerting: Implement monitoring and alerting mechanisms to detect and respond to any anomalies or failures in your Vert.x application. Utilize logging, metrics, and monitoring tools to gain insights into the application’s health and performance.

By leveraging Vert.x clustering and implementing high availability practices, you can ensure that your application scales effectively and remains resilient to failures. These mechanisms enable your application to handle increased workloads, distribute the load across multiple nodes, and provide fault tolerance and automatic recovery. Proper monitoring and alerting help you identify and address any issues promptly, ensuring the smooth operation of your Vert.x application.

Section 6: Integrating with Other Technologies

Vert.x offers seamless integration with various technologies and frameworks, allowing you to leverage existing tools and services in your applications. Here are some common integration points for Vert.x:

  1. Database Integration:
    • Vert.x provides asynchronous clients and connectors for interacting with different databases, both SQL and NoSQL.
    • For example, you can use the Vert.x JDBC client to connect to relational databases like MySQL, PostgreSQL, or Oracle.
    • Vert.x also provides clients for popular NoSQL databases like MongoDB, Redis, and Apache Cassandra.
    • These database clients allow you to perform asynchronous database operations efficiently and integrate database access with other Vert.x components.
  2. Messaging Systems:
    • Vert.x seamlessly integrates with messaging systems, enabling you to build event-driven and distributed applications.
    • Vert.x provides a unified API for working with message brokers such as Apache Kafka, RabbitMQ, and ActiveMQ.
    • You can use the Vert.x event bus to publish and consume messages from these brokers, enabling communication between different parts of your system or integrating with external systems.
  3. Reactive Streams:
    • Vert.x integrates with Reactive Streams, which is a specification for asynchronous stream processing with non-blocking backpressure.
    • By leveraging Reactive Streams implementations like RxJava, Reactor, or CompletableFuture, you can easily integrate reactive libraries and frameworks into your Vert.x applications.
    • This integration allows you to handle streams of data efficiently and apply reactive patterns across your application.
  4. Service Discovery:
    • Vert.x provides a service discovery mechanism that allows services to discover and interact with each other dynamically.
    • With service discovery, you can register services with associated metadata and retrieve them by name or other attributes.
    • This feature is especially useful in microservices architectures, where services need to discover and communicate with each other without hard-coded dependencies.
  5. Web Technologies:
    • Vert.x offers a powerful set of APIs and tools for building web applications and APIs.
    • It integrates with web technologies like WebSocket, HTTP, and event-driven server-sent events.
    • You can use the Vert.x Web API to handle HTTP requests, build RESTful APIs, serve static files, and implement routing and middleware functionalities.
    • Additionally, Vert.x provides integration with popular web frameworks like Spring WebFlux and Express.js, allowing you to leverage their capabilities within your Vert.x applications.
  6. Authentication and Authorization:
    • Vert.x integrates with authentication and authorization mechanisms, enabling secure access control to your applications.
    • It supports various authentication methods, including basic authentication, OAuth 2.0, and JWT (JSON Web Tokens).
    • Vert.x also provides integration with popular identity providers like Keycloak, Okta, and Google Sign-In.

These are just a few examples of the technologies that can be integrated with Vert.x. Vert.x’s modular and flexible architecture allows you to integrate with a wide range of tools and services, enabling you to leverage existing solutions and build powerful, feature-rich applications. When integrating with external technologies, refer to the Vert.x documentation and specific integration guides for detailed instructions and best practices.

Section 7: Unit Testing Vert.x Applications

Unit testing is an essential practice in software development, and Vert.x provides support for writing unit tests for your Vert.x applications. Let’s explore how you can effectively unit test your Vert.x applications:

  1. Testing Verticles:
    • Verticles are the building blocks of a Vert.x application. You can write unit tests to validate the behavior of individual verticles.
    • To test a verticle, create a test class for it and use a testing framework like JUnit or TestNG.
    • Use the Vert.x Test API to set up and execute your tests. The Vert.x Test API provides utilities for creating Vert.x instances, deploying verticles, and simulating events.
    • You can simulate events on the event bus, mock dependencies, and verify the expected behavior of your verticle.
  2. Mocking Dependencies:
    • When unit testing a verticle, you may need to mock external dependencies such as databases, services, or message brokers.
    • Use mocking frameworks like Mockito or EasyMock to create mock objects for your dependencies.
    • Mock the behavior of these dependencies to simulate different scenarios and ensure the correct interaction between the verticle and its dependencies.
  3. Asynchronous Testing:
    • Vert.x is designed for asynchronous programming, and your tests need to handle asynchronous operations appropriately.
    • Use the Vert.x Test API to write assertions for asynchronous code. For example, you can use the await() method to wait for asynchronous operations to complete.
    • Use the async() method to inform the test framework that the test is asynchronous and provide a completion handler to signal the completion of the test.
  4. Dependency Injection:
    • Vert.x supports dependency injection, and you can use it to improve the testability of your code.
    • Use a dependency injection framework like Google Guice or Spring to manage dependencies in your verticles.
    • In your unit tests, you can provide mock or test-specific implementations of dependencies to ensure controlled testing environments.
  5. Integration Testing:
    • In addition to unit tests, you may also want to perform integration tests to validate the interactions between different components of your Vert.x application.
    • Integration tests involve deploying multiple verticles and simulating real-world scenarios.
    • Use the Vert.x Test API and tools like the embedded Vert.x instance or containers like Docker to set up integration test environments.
    • You can also use tools like WireMock to mock external dependencies and simulate network interactions.

Remember to follow best practices for unit testing, such as testing individual units in isolation, focusing on behavior rather than implementation details, and keeping tests concise and readable.

Vert.x provides a comprehensive testing framework and utilities to support effective unit testing of your applications. By writing unit tests, you can ensure the correctness of your code, detect bugs early, and maintain the quality and stability of your Vert.x applications.

Section 8: Deploying Vert.x Applications

Deploying Vert.x applications involves preparing your application for deployment and choosing the appropriate deployment options. Here are the key steps to deploy a Vert.x application:

  1. Package Your Application:
    • Ensure that your Vert.x application is properly packaged for deployment.
    • Create an executable JAR file that includes all the necessary dependencies.
    • You can use build tools like Maven or Gradle to package your application, which will create a self-contained JAR file.
  2. Choose Deployment Options:
    • Vert.x provides multiple deployment options based on your requirements and the target environment.
    • Standalone Deployment: You can deploy your Vert.x application as a standalone JAR file on a server or a virtual machine.
    • Containerized Deployment: Package your application as a Docker image and deploy it to container orchestration platforms like Kubernetes.
    • Serverless Deployment: If you want to leverage serverless architectures, you can deploy your Vert.x application to platforms like AWS Lambda or Azure Functions.
  3. Configuration Management:
    • Consider how you manage configuration for your Vert.x application in different deployment environments.
    • Externalize configuration using configuration files, environment variables, or configuration servers like Consul or Spring Cloud Config.
    • Make sure your application can read and utilize the configuration from the chosen configuration source.
  4. Scaling and Load Balancing:
    • When deploying your application in a production environment, consider how to scale and load balance your Vert.x instances.
    • Vert.x clustering allows you to run multiple instances of your application across different nodes, distributing the load and ensuring fault tolerance.
    • Use load balancers like Nginx or Apache HTTP Server to distribute incoming traffic across multiple Vert.x instances.
  5. Monitoring and Logging:
    • Set up monitoring and logging for your deployed Vert.x application to gather insights into its performance, health, and potential issues.
    • Use monitoring tools like Prometheus, Grafana, or the Vert.x Metrics API to collect and visualize application metrics.
    • Configure proper logging to capture important events, errors, and debugging information for troubleshooting purposes.
  6. Continuous Integration and Deployment (CI/CD):
    • Automate your deployment process using CI/CD pipelines to streamline and ensure consistent deployments.
    • Integrate your Vert.x application with CI/CD tools like Jenkins, GitLab CI, or AWS CodePipeline to automatically build, test, and deploy your application.

By following these steps and considering the deployment options, configuration management, scaling, monitoring, and automation, you can successfully deploy your Vert.x application and ensure its availability, scalability, and maintainability in various environments.

Section 9: Monitoring and Debugging Vert.x Applications

Monitoring and debugging Vert.x applications are crucial for maintaining their performance, identifying issues, and ensuring their smooth operation. Here are some approaches and tools you can use for monitoring and debugging Vert.x applications:

  1. Logging:
    • Utilize logging frameworks like Log4j, SLF4J, or Vert.x’s built-in logging capabilities to capture important events, errors, and debugging information.
    • Configure logging levels appropriately to balance the level of detail and performance impact.
    • Use log aggregation tools like ELK Stack (Elasticsearch, Logstash, Kibana) or Splunk to collect, search, and visualize log data.
  2. Metrics and Health Checks:
    • Vert.x provides a Metrics API that allows you to collect various performance metrics about your application, such as CPU usage, memory consumption, event loop utilization, and request/response rates.
    • Integrate with monitoring tools like Prometheus, Grafana, or DataDog to collect and visualize these metrics in real-time dashboards.
    • Implement health checks in your application to periodically assess its overall health and availability. Expose endpoints that can be probed by external monitoring systems.
  3. Distributed Tracing:
    • Distributed tracing helps you understand and debug the flow of requests across different components of your Vert.x application, especially in microservices architectures.
    • Tools like Jaeger, Zipkin, or OpenTelemetry can be integrated with Vert.x to provide distributed tracing capabilities.
    • Instrument your code with tracing annotations or APIs to track requests as they pass through different verticles and external services.
  4. Request Logging and Monitoring:
    • Log and monitor incoming requests to your Vert.x application to gain insights into their performance and identify potential bottlenecks.
    • Use tools like Apache HTTP Server or Nginx as reverse proxies to capture request logs and enable advanced logging features.
    • Implement request-level metrics and monitoring to track request/response times, error rates, and throughput.
  5. Debugging Techniques:
    • Vert.x supports remote debugging, allowing you to attach a debugger to running Vert.x instances.
    • Enable remote debugging by adding the appropriate JVM arguments to your application’s startup script or configuration.
    • Use an Integrated Development Environment (IDE) like IntelliJ IDEA, Eclipse, or Visual Studio Code with the Vert.x plugin to connect and debug your running application.
  6. Application Performance Monitoring (APM) Tools:
    • Consider using Application Performance Monitoring (APM) tools like New Relic, AppDynamics, or Dynatrace to gain deeper insights into your Vert.x application’s performance.
    • These tools provide end-to-end visibility, capturing detailed transaction traces, database queries, external service calls, and resource utilization.

Remember to monitor your Vert.x applications in both development and production environments. Understand the performance characteristics of your application and establish baselines to identify deviations and potential issues.

By combining logging, metrics, distributed tracing, request logging, debugging techniques, and APM tools, you can effectively monitor and debug your Vert.x applications, ensuring optimal performance, identifying and resolving issues quickly, and providing a smooth user experience.

Section 10: Conclusion

In conclusion, Vert.x is a powerful and versatile toolkit for building reactive, event-driven applications that can handle high concurrency and scale effectively. In this tutorial, we covered various aspects of Vert.x development, starting from setting up the development environment to deploying and monitoring Vert.x applications.

Spring Cloud Sleuth & Zipkin – Distributed Logging and Tracing


In standard applications, app logs are implemented into a single file which can be read for debugging purposes. However, apps which follows microservices architecture style comprises multiple small apps and multiple log files are to maintained to have at least one file per microservice. Due to this , identification and correlation of logs to a specific request chain becomes difficult.

For this, distributed logging & tracing mechanism can be implemented using tools like Sleuth, Zipkin, ELK etc

How to use Sleuth?

Sleuth is part of spring cloud libraries. It can be used to generate the traceid, spanid and add this information to the service calls in headers and mapped diagnostic context (MDC). These ids can be used by the tools such as Zipkin, ELK to store, index and process the log file.

To use sleuth in the app, following dependencies needs to be added

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

How to use Zipkin?

Zipkin contains two components

  • Zipkin Client
  • Zipkin Server

Zipkin client contains Sampler which collects data from ms apps with the help of sleuth and provides it the zipkin server.

To use zipkin client following dependency needs to be added in the application

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

To use zipkin server, we need to download and set up the server in our system

zipkin server

Implementation on microservice apps

To see distributed logging implementation, we need to create three services with the same configuration, the only difference has to be the service invocation details where the endpoint changes.

  • Create services as Spring boot applications with WebRest RepositoryZipkin and Sleuth dependencies.
  • Package services inside a single parent project so that three services can be built together. Also, I’ve added useful windows scripts in github repo to start/stop all the services with a single command
  • Below is one rest controller in service1 which exposes one endpoint and also invokes one downstream service using the RestTemplate. Also, we are using Sampler.ALWAYS_SAMPLE that traces each action.

Service 1

package com.mvtechbytes.service1;
 
import brave.sampler.Sampler;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
 
@SpringBootApplication
public class Service1Application {
 
    public static void main(String[] args) {
        SpringApplication.run(Service1Application.class, args);
    }
}
 
@RestController
class Service1Controller {

    private static final Logger LOG = Logger.getLogger(Service1Controller.class.getName());
     
    @Autowired
    RestTemplate restTemplate;
 
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
 
    @Bean
    public Sampler alwaysSampler() {
        return Sampler.ALWAYS_SAMPLE;
    }
     
    @GetMapping(value="/service1")
    public String service1() 
    {
        LOG.info("Inside Service 1..");         
String response = (String)   restTemplate.exchange("http://localhost:8082/service2", HttpMethod.GET, null, new ParameterizedTypeReference<String>() {}).getBody();
        return response;
    }
}

Appication Configuration

As all services will run in a single machine, so we need to run them in different ports. Also to identify in Zipkin, we need to give proper names. so configure the application name and port information in application.properties file under the resources folder.

application.propertiesserver.port = 8081
spring.application.name = zipkin-server1

Similarly, for the other 2 services, we will use ports 8082, 8083 and their name will also be zipkin-server2 and zipkin-server3

Also, we have intentionally introduced a delay in the second service so that we can view that in Zipkin.

Above project is available in below github location

Github repo : https://github.com/mvtechbytes/Zipkin-Sleuth

On running app using bat files

Find Traces
Individual Trace
Trace details

References

Spring Boot and Zuul API Gateway Integration


In this post, we will learn how to integrate zuul api gateway to the application developed in microservices architecture.

Our application consists of below components

  • customer-service
  • order-service
  • eureka-server
  • zuul-service

We have already seen how to create customer-service, order-service, eureka-server in the previous post given below

https://malliktalksjava.com/2020/05/28/spring-boot-netflix-eureka-integration/

Let us start integrating zuul api gateway service to the above application.

Firstly, Go to https://start.spring.io , Create SpringBoot Application with below configuration. 

As shown above, Spring Web, Eureka Server, Zuul as dependencies needs to be added.

Second Step, Import the project in the Eclipse, go to application.properties and add below properties

spring.application.name=zuul-service
zuul.routes.order.url=http://localhost:8080
eureka.client.serviceUrl.defaultZone=http://localhost:8090/eureka
server.port=8079

Next step is to create following filters

  • ErrorFilter
  • PreFilter
  • PostFilter
  • RouteFilter

Below diagram depicts flow of Request & Response intercepted by Zuul filters

Zuul_FlowDFilters creation step 1: Create ErrorFilter by extending ZuulFilter and override methods and shown below

package com.venkat.filters;

import com.netflix.zuul.ZuulFilter;

public class ErrorFilter extends ZuulFilter {

@Override
public String filterType() {
        return "error";
}

@Override
public int filterOrder() {
       return 0;
}

@Override
public boolean shouldFilter() {
       return true;
}

@Override
public Object run() {
        System.out.println(" ############# Using Error Filter ##################");               
return null;
}

}

Filters creation step 2: Create PreFilter by extending ZuulFilter and override methods and shown below

package com.venkat.filters;
import javax.servlet.http.HttpServletRequest;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

public class PreFilter extends ZuulFilter {

@Override
public String filterType() {
return "pre";
}

@Override
public int filterOrder() {
return 0;
}

@Override
public boolean shouldFilter() {
return true;
}

@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
System.out.println(" ############# In Pre Filter ################## ");
System.out.println(
"Request Method : " + request.getMethod() + " Request URL : " + request.getRequestURL().toString());

return null;
}

}

Filters creation step 3: Create PostFilter by extending ZuulFilter and override methods and shown below

package com.venkat.filters;

import java.io.IOException;
import java.io.InputStreamReader;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.common.io.CharStreams;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

public class PostFilter extends ZuulFilter {

@Override
public String filterType() {
return "post";
}

@Override
public int filterOrder() {
return 0;
}

@Override
public boolean shouldFilter() {
return true;
}

@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
System.out.println(" ############# In Post Filter ################## ");
try {
System.out.println(
"Response Status Code : " + ctx.getResponseStatusCode() + " Response Body : " + CharStreams.toString(new InputStreamReader(ctx.getResponseDataStream(), "UTF-8")));
} catch (IOException e) {

}

return null;
}

}

Filters creation step 4: Create RouteFilter by extending ZuulFilter and override methods and shown below

package com.venkat.filters;

import com.netflix.zuul.ZuulFilter;

public class RouteFilter extends ZuulFilter {

@Override
public String filterType() {
return "route";
}

@Override
public int filterOrder() {
return 0;
}

@Override
public boolean shouldFilter() {
return true;
}

@Override
public Object run() {
System.out.println("Using Route Filter");

return null;
}

}

Next, Add @EnableZuulProxy to ZuulProxyApplication class in zuul-service and add bean configurations for Filters which we have created as shown below

package com.venkat;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulProxyApplication {

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

@Bean
public PreFilter preFilter() {
return new PreFilter();
}

@Bean
public PostFilter postFilter() {
return new PostFilter();
}

@Bean
public ErrorFilter errorFilter() {
return new ErrorFilter();
}

@Bean
public RouteFilter routeFilter() {
return new RouteFilter();
}
}

Once we are done creating all the filters package structure of our
zuul-service will be as shown as shown below

Now we will see changes to done to the customer-service application to enable requests
pass via zuul-service filters.

Go to CusomerControllerClient.java in customer-service replace

List<ServiceInstance> instances = discoveryClient.getInstances("ORDER-SERVICE");

with

List<ServiceInstance> instances = discoveryClient.getInstances("ZUUL-SERVICE");

and 

String completeURL = baseURL + "/customerorder";

with 

String completeURL = baseURL + "/order/customerorder";

Upon completion of all the code changes/additons discussed above run all the services, eureka-server, order-service, customer-service, zuul-service.

Following will be output once we hit the REST endpoint /customerorderinfo

zuul-service logs on hitting the REST end point are given below, clearly we can see both Request and Response pass through Pre, Route, Post Filters 

############# In Pre Filter ################## 
Request Method : GET Request URL : http://Dell:8079/order/customerorder
Using Route Filter
############# In Post Filter ##################
Response Status Code : 200 Response Body : {"orderId":"TIF567","itemName":"Dosa","itemType":"Tiffin","cost":40.0}
2020-05-31 18:56:18.494 INFO 3892 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver : Resolving eureka endpoints via configuration
############# In Pre Filter ##################
Request Method : GET Request URL : http://Dell:8079/order/customerorder
Using Route Filter
############# In Post Filter ##################
Response Status Code : 200 Response Body : {"orderId":"TIF567","itemName":"Dosa","itemType":"Tiffin","cost":40.0}

Conclusion

In this post, we have seen how to configure Zuul-proxy and make requests from one microservice pass through customized zuul filters. These filters enable us to apply functionality to our edge service. These filters help us perform the following functions:

  • Authentication & Security – identifying authentication requirements for each resource and rejecting requests that do not satisfy them.
  • Monitoring – tracking data and statistics at the edge which gives us a view of production.
  • Dynamic Routing – dynamically routing requests to various back-end clusters.
  • Load Shedding – allocating capacity for each type of request and dropping requests that exceeds the limit set.
  • Stress Testing – increasing the traffic to a cluster to measure its performance.
  • Static Response handling – sending some responses directly at the edge instead of forwarding them to an internal cluster.

Related links:

References:

Spring Boot and Netflix Eureka Integration


In this post we will learn how to integrate applications developed in Spring Boot with Netflix Eureka.

First step is to create two Spring Boot application services

  • customer-service
  • order-service

Go to https://start.spring.io and create order-service app using below config details.

Mainly for our use case, adding Spring Web, Eureka Server dependencies are the required ones

Likewise, create customer-service app with same config details used for order-service by adding Spring Web, Eureka Server dependencies.

Next, create eureka-server app with below config . Adding Eureka Server is main important config for our use case

Next, Import the projects created from the above into Eclipse IDE.

Add @EnableEurekaServer on EurekaServerApplication class as shown Below

package com.venkat;

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

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

Add below properties to the application.properties

server.port=8090
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

Next, Add @EnableEurekaClient on CustomerServiceApplication class in customer-service  app as shown below

@SpringBootApplication
@EnableEurekaClient
public class CustomerServiceApplication {
public static void main(String[] args) throws RestClientException, IOException {
SpringApplication.run(CustomerServiceApplication.class, args);
}

@Bean
public ConsumerControllerClient consumerControllerClient()
{
return new ConsumerControllerClient();
}
}

Likewise, Add @EnableEurekaClient on OrderServiceApplication class in order-service app as shown below

@SpringBootApplication
@EnableEurekaClient
public class OrderSerivceApplication {

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

Next, Add below configuration in customer-service and order-service
application.properties files

customer-service

spring.application.name=customer-service
server.port=8091
eureka.client.serviceUrl.defaultZone=http://localhost:8090/eureka

order-service

spring.application.name=order-service
server.port=8080
eureka.client.serviceUrl.defaultZone=http://localhost:8090/eureka

Next, Create Order.java in model package as shown below with orderId, itemName, itemType, Cost attributes.

package com.venkat.model;

public class Order {
private String orderId;
private String itemName;
private String itemType;
private double cost;

public Order() {
}

public String getOrderId() {
return orderId;
}

public void setOrderId(String orderId) {
this.orderId = orderId;
}

public String getItemName() {
return itemName;
}

public void setItemName(String itemName) {
this.itemName = itemName;
}

public String getItemType() {
return itemType;
}

public void setItemType(String itemType) {
this.itemType = itemType;
}

public double getCost() {
return cost;
}

public void setCost(double cost) {
this.cost = cost;
}
}

Create OrderController with a REST GET mapping for /customerorder to return Order object

package com.venkat.controllers;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.venkat.model.Order;

@RestController
public class OrderController {

@RequestMapping(value = "/customerorder", method = RequestMethod.GET)
public Order customerOrder() {
Order order = new Order();
order.setOrderId("TIF567");
order.setItemName("Dosa");
order.setItemType("Tiffin");
order.setCost(40.00);
return order;
}
}

Create a ConsumerControllerClient.java class as shown below

package com.venkat.controllers;

import java.io.IOException;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

@RestController
public class ConsumerControllerClient {

@Autowired
private DiscoveryClient discoveryClient;

@GetMapping(path="/customerorderinfo")
public String getCustomerOrder() throws RestClientException, IOException {

List<ServiceInstance> instances = discoveryClient.getInstances("ORDER-SERVICE");

// Creating URL for calling order-service
ServiceInstance serviceInstance = instances.get(0);
String baseURL = serviceInstance.getUri().toString();
String completeURL = baseURL + "/customerorder";

// Calling order-service
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = null;
try {
response = restTemplate.exchange(completeURL, HttpMethod.GET, getHeaders(), String.class);
} catch (Exception ex) {
System.out.println(ex);
}
System.out.println(response.getBody());
return response.getBody();
}

private static HttpEntity<?> getHeaders() throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
return new HttpEntity<>(headers);
}

}

Final step is to Run EurekaServer, order-service, customer-service apps

Open http://localhost:8090 (port on which eureka server is running). Here you will see
order-service,customer-service app instances registered with it.

Output on hitting REST Endpoint http://localhost:8091/customerorderinfo is given below

Conclusion

In the above post we have seen how to register two service applications with Netflix Eureka
Server and communicate between the services via Eureka server registry without knowing the
host, port info of the service to which we are communicating with.

Spring Boot Starter dependencies


Spring Boot provides a number of starters which allow us to add jars in the classpath. Spring Boot Starters are the dependency descriptors. Spring Boot built-in starters make development easier, rapid and easily maintainable.

Naming Pattern

In the Spring Boot framework, all the starters follow a similar naming pattern: spring-boot-starter-*, where * denotes a particular type of application.

Example, if we require to use Spring and JPA for database access, spring-boot-starter-data-jpa dependency in our pom.xml file of the project can be included.

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

If we are developing REST API, spring-boot-starter-web dependency can be used.

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

If gradle is being used as build tool, then following can be added to build.gradle file in the project.

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
}

Below are the jars which are added to project’s classpath on adding “spring-boot-starter-data-jpa”

Spring Boot Starters can be broadly classified into three categories

  1. Production Starters
  2. Application Starters
  3. Technical Starters

Below is complete list of the starters available in above categories

Spring Boot Production Starters

Name

Description

spring-boot-starter-actuator This provides production-ready features to help you monitor and manage your application.
spring-boot-starter-remote-shell This is used for the CRaSH remote shell to monitor and manage your application over SSH. Deprecated since 1.5.

Spring Boot Application Starters

Name

Description

spring-boot-starter-thymeleaf For building MVC web applications using Thymeleaf views.
spring-boot-starter-data-couchbase For the Couchbase document-oriented database and Spring Data Couchbase.
spring-boot-starter-artemis For JMS messaging using Apache Artemis.
spring-boot-starter-web-services For Spring Web Services.
spring-boot-starter-mail To support Java Mail and Spring Framework’s email sending.
spring-boot-starter-data-redis Used for Redis key-value data store with Spring Data Redis and the Jedis client.
spring-boot-starter-web For building the web application, including RESTful applications using Spring MVC. It uses Tomcat as the default embedded container.
spring-boot-starter-data-gemfire Used to GemFire distributed data store and Spring Data GemFire.
spring-boot-starter-activemq For JMS messaging using Apache ActiveMQ.
spring-boot-starter-data-elasticsearch For Elasticsearch search and analytics engine and Spring Data Elasticsearch.
spring-boot-starter-integration It is used for Spring Integration.
spring-boot-starter-test Used to test Spring Boot applications with libraries, including JUnit, Hamcrest, and Mockito.
spring-boot-starter-jdbc Used for JDBC with the Tomcat JDBC connection pool.
spring-boot-starter-mobile Used for building web applications using Spring Mobile.
spring-boot-starter-validation Used for Java Bean Validation with Hibernate Validator.
spring-boot-starter-hateoas Used to build a hypermedia-based RESTful web application with Spring MVC and Spring HATEOAS.
spring-boot-starter-jersey Used to build RESTful web applications using JAX-RS and Jersey. An alternative to spring-boot-starter-web.
spring-boot-starter-data-neo4j Used for the Neo4j graph database and Spring Data Neo4j.
spring-boot-starter-data-ldap Used for Spring Data LDAP.
spring-boot-starter-websocket Used for building the WebSocket applications. It uses Spring Framework’s WebSocket support.
spring-boot-starter-aop For aspect-oriented programming with Spring AOP and AspectJ.
spring-boot-starter-amqp For Spring AMQP and Rabbit MQ.
spring-boot-starter-data-cassandra For Cassandra distributed database and Spring Data Cassandra.
spring-boot-starter-social-facebook For Spring Social Facebook.
spring-boot-starter-jta-atomikos For JTA transactions using Atomikos.
spring-boot-starter-security It is used for Spring Security.
spring-boot-starter-mustache It is used for building MVC web applications using Mustache views.
spring-boot-starter-data-jpa Used for Spring Data JPA with Hibernate.
spring-boot-starter Used for core starter, including auto-configuration support, logging, and YAML.
spring-boot-starter-groovy-templates Used for building MVC web applications using Groovy Template views.
spring-boot-starter-freemarker It is used for building MVC web applications using FreeMarker views.
spring-boot-starter-batch For Spring Batch.
spring-boot-starter-social-linkedin For Spring Social LinkedIn.
spring-boot-starter-cache For Spring Framework’s caching support.
spring-boot-starter-data-solr It is used for the Apache Solr search platform with Spring Data Solr.
spring-boot-starter-data-mongodb It is used for MongoDB document-oriented database and Spring Data MongoDB.
spring-boot-starter-jooq Used for jOOQ to access SQL databases. An alternative to spring-boot-starter-data-jpa or spring-boot-starter-jdbc.
spring-boot-starter-jta-narayana Used for Spring Boot Narayana JTA Starter.
spring-boot-starter-cloud-connectors It is used for Spring Cloud Connectors that simplifies connecting to services in cloud platforms like Cloud Foundry and Heroku.
spring-boot-starter-jta-bitronix It is used for JTA transactions using Bitronix.
spring-boot-starter-social-twitter For Spring Social Twitter.
spring-boot-starter-data-rest For exposing Spring Data repositories over REST using Spring Data REST.

Spring Boot Technical Starters

Name Description
spring-boot-starter-undertow Used for Undertow as the embedded servlet container. An alternative to spring-boot-starter-tomcat.
spring-boot-starter-jetty Used for Jetty as the embedded servlet container. An alternative to spring-boot-starter-tomcat.
spring-boot-starter-logging Used for logging using Logback. Default logging starter.
spring-boot-starter-tomcat Used for Tomcat as the embedded servlet container. Default servlet container starter used by spring-boot-starter-web.
spring-boot-starter-log4j2 Used for Log4j2 for logging. An alternative to spring-boot-starter-logging.

Spring Security Namespace Designs


The namespace is designed to capture the most common uses of the framework and provide a simplified and concise syntax for enabling them within an application. The design is based around the large-scale dependencies within the framework, and can be divided up into the following areas:

  • Web/HTTP Security – the most complex part. Sets up the filters and related service beans used to apply the framework authentication mechanisms, to secure URLs, render login and error pages and much more.
  • Business Object (Method) Security – options for securing the service layer.
  • AuthenticationManager – handles authentication requests from other parts of the framework.
  • AccessDecisionManager – provides access decisions for web and method security. A default one will be registered, but you can also choose to use a custom one, declared using normal Spring bean syntax.
  • AuthenticationProviders – mechanisms against which the authentication manager authenticates users. The namespace provides supports for several standard options and also a means of adding custom beans declared using a traditional syntax.
  • UserDetailsService – closely related to authentication providers, but often also required by other beans.

Features of Spring Web MVC


Spring’s web module includes many unique web support features:

  • Clear separation of roles. Each role—controller, validator, command object, form object, model object, DispatcherServlet, handler mapping, view resolver, and so on—can be fulfilled by a specialized object.
  • Powerful and straightforward configuration of both framework and application classes as JavaBeans. This configuration capability includes easy referencing across contexts, such as from web controllers to business objects and validators.
  • Adaptability, non-intrusiveness, and flexibility. Define any controller method signature you need, possibly using one of the parameter annotations (such as @RequestParam, @RequestHeader, @PathVariable, and more) for a given scenario.
  • Reusable business code, no need for duplication. Use existing business objects as command or form objects instead of mirroring them to extend a particular framework base class.
  • Customizable binding and validation. Type mismatches as application-level validation errors that keep the offending value, localized date and number binding, and so on instead of String-only form objects with manual parsing and conversion to business objects.
  • Customizable handler mapping and view resolution. Handler mapping and view resolution strategies range from simple URL-based configuration, to sophisticated, purpose-built resolution strategies. Spring is more flexible than web MVC frameworks that mandate a particular technique.
  • Flexible model transfer. Model transfer with a name/value Map supports easy integration with any view technology.
  • Customizable locale, time zone and theme resolution, support for JSPs with or without Spring tag library, support for JSTL, support for Velocity without the need for extra bridges, and so on.
  • A simple yet powerful JSP tag library known as the Spring tag library that provides support for features such as data binding and themes. The custom tags allow for maximum flexibility in terms of markup code.
  • A JSP form tag library, introduced in Spring 2.0, that makes writing forms in JSP pages much easier.
  • Beans whose lifecycle is scoped to the current HTTP request or HTTP Session. This is not a specific feature of Spring MVC itself, but rather of the WebApplicationContext container(s) that Spring MVC uses.

Methods of Bean Configurations for Spring Container


There are three ways to provide the configuration metadata to Spring container. Below are the more details about them.

1. Xml based configuration file

<?xml version=”1.0″ encoding=”UTF-8″?>

<beans xmlns=”http://www.springframework.org/schema/beans&#8221;
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221;
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd”&gt;

<!– A simple bean definition –>
<bean id=”…” class=”…”>
<!– collaborators and configuration for this bean go here –>
</bean>

<!– A bean definition with lazy init set on –>
<bean id=”…” class=”…” lazy-init=”true”>
<!– collaborators and configuration for this bean go here –>
</bean>

<!– A bean definition with initialization method –>
<bean id=”…” class=”…” init-method=”…”>
<!– collaborators and configuration for this bean go here –>
</bean>

<!– A bean definition with destruction method –>
<bean id=”…” class=”…” destroy-method=”…”>
<!– collaborators and configuration for this bean go here –>
</bean>

<!– more bean definitions go here –>

</beans>

2. Annotation based configuration

<?xml version=”1.0″ encoding=”UTF-8″?>

<beans xmlns=”http://www.springframework.org/schema/beans&#8221;
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221;
xmlns:context=”http://www.springframework.org/schema/context&#8221;
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd”&gt;

<context:annotation-config/>
<!– bean definitions go here –>

<bean id=”empAddress” class=”in.malliktalksjava.spring.samples.EmployeeAddress” />

</beans>

Once <context:annotation-config/> is configured, you can start annotating your code to indicate that Spring should automatically wire values into properties, methods, and constructors. Once you add the annotation config, you can use @Autowired annotation as below on setter methods to get rid of the <property> element in XML configuration file. When Spring finds an @Autowired annotation used with setter methods, it tries to perform byType autowiring on the method.

Employee.java:

package in.malliktalksjava.spring.samples;

public class Employee{

@Autowired

public EmployeeAddress empAddress;

public void test(){

System.out.println(empAddress.getStreet());

System.out.println(empAddress.getPostalCode());

}

}

EmployeeAddress.java:

package in.malliktalksjava.spring.samples;

public class EmployeeAddress{

private String street;

private String postalCode;

public void setStreet(String street){

this.street = street;

}

public String getStreet(){

return street;

}

public void setPostalCode(String postalCode)

this.postalCode = postalCode;

}

public String getPostalCode(){

return postalCode;

}

}

 

3. Java based configuration

Java based configuration option enables you to write most of your Spring configuration without XML but with the help of few Java-based annotations. Annotating a class with the @Configuration indicates that the class can be used by the Spring IoC container as a source of bean definitions. The @Bean annotation tells Spring that a method annotated with @Bean will return an object that should be registered as a bean in the Spring application context.

HelloWorldConfig.java

package in.malliktalksjava.spring.samples;
import org.springframework.context.annotation.*;

@Configuration
public class HelloWorldConfig {

@Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}

HelloWorld.java

package in.malliktalksjava.spring.samples;

public class HelloWorld {
private String message;

public void setMessage(String message){
this.message = message;
}

public void getMessage(){
System.out.println(” Message is : ” + message);
}
}

MainApp.java:

package in.malliktalksjava.spring.samples;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;

public class MainApp {
public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(HelloWorldConfig.class);

HelloWorld helloWorld = ctx.getBean(HelloWorld.class);

helloWorld.setMessage(“Hello World!”);
helloWorld.getMessage();
}
}

Complete application has been created without writing any configuration file.

Spring Bean Scopes – Examples


There are 5 spring bean scopes as below:

1. Singleton: 

If scope is set to singleton, the Spring IoC container creates exactly one instance of the object defined by that bean definition. This single instance is stored in a cache of such singleton beans, and all subsequent requests and references for that named bean return the cached object.

If we not set any scope to bean then spring container will set to the default scope and default scope of the bean is always singleton. use ‘singleton’ to set the bean scope to Singleton.

2. Prototype

If scope is set to prototype, the Spring IoC container creates new bean instance of the object every time a request for that specific bean is made.

Use ‘prototype’ word during spring configuration to set the bean scope to Proto Type.

As a rule, use the prototype scope for all state-full beans and the singleton scope for stateless beans.

3. Request:

This scopes a bean definition to an HTTP Request and its only valid in the context of a web-aware Spring ApplicationContext.

Use the ‘request’ keyword to set the bean scope to HttpRequest during spring bean configuration.

4. Session:

This scopes a bean definition to an HTTP Session and its only valid in the context of a web-aware Spring ApplicationContext.

Use the ‘session’ keyword to set the bean scope to Http Session during spring bean configuration.

5. Global Session

This scopes a bean definition to a Global HTTP Session and its only valid in the context of a web-aware Spring ApplicationContext.

Use the ‘global-session’ keyword to set the bean scope to Global Http Session during spring bean configuration.

Configuration of these scopes can be done as below:

Define the above mentioned scopes in beans.xml file along with bean declaration.

<!– A bean definition with singleton scope –>
<bean id=”…” class=”…” scope=”singleton”>
<!– collaborators and configuration for this bean go here –>
</bean>

Can also be mention the bean scope using annotation:

@Configuration
public class BeanJavaConfiguration {
@Bean
@Scope(“prototype”)
public Appleapp() {
return new Apple();
}
}