Skip to the content.

Advance Your Spring Development Skills

This are the notes for the 6 courses Specialization PATH on Linkedin Learning.

Table of Content

  1. Spring Cloud Load Balancing
  2. Performance Tuning in Spring Apps
  3. Spring Boot Observability: Deep Dive into Logging, Metrics, and Tracing
  4. Advanced Spring: Spring Boot Actuator
  5. Advanced Spring: Application Events
  6. Advanced Spring: Effective Integration Testing with Spring Boot

Spring Cloud Load Balancing

Introduction

In software engineering, Load Balancing is the practice of distributing computational workloads across multiple servers. This process ensures that no single server bears too much demand. By spreading the work evenly, load balancing improves application responsiveness. It also increases the availability of applications and websites for users. Load balancers evaluate client requests by examining application-level characteristics (the IP address, the HTTP header, and the contents of the request). The load balancer then looks at the servers and determines which server to send the request to.

Load balancing has a significant impact on user experience. By dividing user requests among multiple servers, user wait time is vastly cut down. This results in a better user experience. Long page load times, and poor response times to user actions, create a bad user experience. Waiting for content to load becomes frustrating for users and may provoke them into leaving the site or application altogether. Load balancers handle traffic spikes by moving data efficiently, optimizing application delivery resource usage, and preventing server overloads. That way, the website performance stays high, and users remain satisfied.

With Google Cloud Platform (GCP), load balancing is a software cloud-based offering to automatically facilitate shift of traffic from one instance to another when traffic or load is increased.

Google Cloud Platform (GCP) offer two types of internal load balancers:

Both load balancers are internal, meaning they serve traffic between internal instances and not from the external internet. They are assigned an internal IP address used for internal instances or clients to forward traffic to. Both types only support instances deployed in a single region. The choice between the two depends on the type of traffic and the application’s requirements.

External Load Balancer

Performance Tuning in Spring Apps

Introduction

Repository: Performance Tuning in Spring Apps)

Tools

IMPORTANT: to run the project, a link to the quoting service must be updated according to: https://github.com/spring-guides/gs-consuming-rest/issues/47#issuecomment-1079698023

Understanding Performance

The big question: “How does your application perform?

The selected text discusses the importance of understanding performance in Spring-based applications. Here are the key points:

JVM Perfomance

Transaction Profiling

Challenge JVM OutOfMemory

To start, we need to confgure the proper profile in the Run SpringBootApp:

Then, modify the run configuration for the JVM to change the heap size and do a Heap Dump for further analysis:

-Xmx100M 
-Xms100M
-XX:+HeapDumpOnOutOfMemoryError
-javaagent:C:\Users\matia\workspace\perf_tools\glowroot\glowroot.jar

After the application crashes, a memory dump is generated and we can open and analyze it with the VisualVM tool:

Heap Analysis:

Code:

Spring Actuators

Spring Boot Actuator is a sub-project of the Spring Boot Framework. It brings production-ready features to our application. The main benefit of using this library is that we get health and monitoring metrics from production-ready applications.

In essence, the Spring Boot Actuator is used for monitoring our app, gathering metrics, and understanding traffic or the state of our database. It becomes trivial with this dependency.

Spring Boot Actuator: Production-ready Features. https://docs.spring.io/spring-boot/docs/2.5.6/reference/html/actuator.html.

To enable and disabled this configuration, go to the “application.properties” and add:

management.endpoints.web.exposure.include=*
management.endpoints.jmx.exposure.include=*
management.endpoint.health.show-details=always
management.endpoint.health.show-components=always
management.endpoint.health.status.order=out-of-service,down,up

Actuators configuration

Actuator can be customize extending from classes that are provided by the Actuators package as in this example:

Then when you call the /actuator/health endpoint, a custom check is executed that validate is the current day is “weekend” (Saturday or Sunday):

Spring Actuator Micrometer Metrics

After running the Demo API with the new metric variable to registry, we run Prometheus and configure the TARGET using the YML file given:

Types of metrics

Spring Performance Monitor Interceptor

Documentation: Aspect Oriented Programming with Spring :: Spring Framework

When to use Interceptors

Interceptors that can be applied before, after, or around method executions. Here are some scenarios where you might consider using it:

  1. Targeted Performance Logging: If you need to log performance metrics for specific methods in your application.
  2. Aspect-Oriented Solutions: If you’re implementing aspect-oriented solutions, this interceptor can be used to declare advices and pointcuts.
  3. Intercepting Client Requests: Spring Interceptors can be used to intercept client requests before they are handled by the controller. They can also be used to intercept the response before it is sent back to the client.
  4. Execution Chain Processing: You can use this method to break or continue the processing of the execution chain.

However, it’s important to note that target objects should not normally know about Spring AOP, as this creates a dependency on Spring API. Target objects should be plain POJOs (Plain Old Java Objects) as far as possible. If used, this interceptor will normally be the first in the interceptor chain.

Example of intercepting a client request

@Configuration
public class RestClientConfig {
    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
        if (CollectionUtils.isEmpty(interceptors)) {
            interceptors = new ArrayList<>();
        }
        interceptors.add(new RestTemplateHeaderModifierInterceptor());
        restTemplate.setInterceptors(interceptors);
        return restTemplate;
    }
}

public class RestTemplateHeaderModifierInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        ClientHttpResponse response = execution.execute(request, body);
        response.getHeaders().add("Internal Payment Gateway", "Payment");
        return response;
    }
}

In this example, RestTemplateHeaderModifierInterceptor is an interceptor that adds a custom header “Internal Payment Gateway” to every response. This interceptor will be invoked for every incoming request for a payment.

Interceptors are useful for several reasons:

  1. Cross-cutting concerns: Interceptors are often used to implement cross-cutting concerns such as transaction management, security, or logging.
  2. Global application of logic: Interceptors provide a quick and easy way to apply the same logic globally (or to a set of pages) without needing to mess around with individual controllers.
  3. Modifying requests and responses: Interceptors allow you to modify requests and responses. For example, you can add or modify headers, or even deny the request based on certain conditions.
  4. Logging: Interceptors can be used to log requests and responses for every HTTP request.

AOP Performance

Weaving in deep

Weaving is a crucial process in Aspect-Oriented Programming (AOP). It’s the process where the aspect code (additional behavior) is combined with the main application code.

  1. Aspect Weaver: An aspect weaver is a metaprogramming utility for aspect-oriented languages. It takes instructions specified by aspects (isolated representations of significant concepts in a program) and generates the final implementation code.

  2. Weaving Process: The weaver integrates aspects into the locations specified by the software as a pre-compilation step. By merging aspects and classes (representations of the structure of entities in the program), the weaver generates a woven class.

  3. Advice, Pointcuts, and Join Points: Aspect weavers take instructions known as advice specified through the use of pointcuts and join points, special segments of code that indicate what methods should be handled by aspect code. The implementation of the aspect then specifies whether the related code should be added before, after, or throughout the related methods.

  4. Weaving Time: Weaving can be done at compile time, post-compile time, or runtime. Compile-time weaving modifies the byte code before the program runs. Post-compile weaving (also known as binary weaving) modifies the byte code after the program has been compiled but before it runs. Load-time weaving modifies the byte code as the program runs.

  5. Benefits of Weaving: By doing this, aspect weavers improve modularity, keeping code in one place that would otherwise have been interspersed throughout various, unrelated classes. This ensures that any existing object-oriented code will still be valid aspect-oriented code and that development will feel like a natural extension of the object-oriented language.

Important concepts

Hibernate Performance

Connection pooling

Hibernate Caching

The JPA and Hibernate second-level cache - Vlad Mihalcea. https://vladmihalcea.com/jpa-hibernate-second-level-cache/. The JPA and Hibernate first-level cache - Vlad Mihalcea. https://vladmihalcea.com/jpa-hibernate-first-level-cache/.

Metrics in prometheus

Application StartUP time

In this example, we add a “BufferingApplicationStartup” class to the context of the spring project to get metrics:

On this metrics we can filter by some criteria:

public static void main(String[] args) {

AbstractApplicationContext context = new ClassPathXmlApplicationContext("/META-INF/spring/application.xml",

DemoClientApplication.class);

DemoProperties props = (DemoProperties) context.getBean("appProperties");

SpringApplication demoApplication = new SpringApplication(DemoClientApplication.class);

// Below lines require JVM parameters in order to run. This is covered in lesson

BufferingApplicationStartup bas = new BufferingApplicationStartup(10000);

// Adding FILTER
bas.addFilter(startupStep -> startupStep.getName().startsWith("spring.beans.instantiate"));

demoApplication.setApplicationStartup(bas);

demoApplication.run(args);

logger.info("Open this application in your browser at http://localhost:"

+ props.getRuntimeProperties().getProperty("server.port", ""));

demoManager = new DemoManager(props);

context.close();

}

Java Flight Recorder

In this example we use the Flight Recorder functionality to record the Spring Boot Startup process and view its metrics in the Flight Recorder Application:

Blog with documentation: [Monitoring Java Applications with Flight Recorder Baeldung](https://www.baeldung.com/java-flight-recorder-monitoring)

Compiling a performance profile

)

Presenting your Work

This recommendations are particularly useful for formal and semi-formal events such as iteration demos or architectural reviews.


Spring Boot Observability: Deep Dive into Logging, Metrics, and Tracing


Advanced Spring: Spring Boot Actuator


Advanced Spring: Application Events

Advanced Spring: Effective Integration Testing with Spring Boot