SpringBoot- Advanced

Spring Boot – Logging

Spring boot’s provide default logging mecahnisum, which is written with Apache Commons Logging

SpringBoot supports ERROR, WARN, INFO, DEBUG, or TRACE as logging level. By default, logging level is set to INFO. It means that code>DEBUG and TRACE messages are not visible.

To enable debug or trace logging, we can set the logging level in application.properties file. Also, we can pass the –debug or –trace arguments on the command line while starting the application.

# In Console
-Dlogging.level.org.springframework=ERROR 
-Dlogging.level.com.howtodoinjava=TRACE
 
# In properties file
logging.level.org.springframework=ERROR 
logging.level.com.howtodoinjava=TRACE

Example

 org.slf4j.Logger;
 org.slf4j.LoggerFactory;

@SpringBootApplication
  Application 
{
       Logger =LoggerFactory.(Application.);
 
       main(String[] args) {
        SpringApplication.(Application., args);         
        .info("Simple log statement with inputs {}, {} and {}", 1,2,3);
    }
}

Using @slf4j annotation

To use SLF4J for logging in a Spring Boot application, you typically use the @Slf4j annotation provided by Lombok, a library that helps reduce boilerplate code in Java.

Use @Slf4j Annotation: In your Spring component (e.g., service, controller, etc.), use the @Slf4j annotation to automatically generate a logger field for you:

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class MyService {

    public void doSomething() {
        log.info("Doing something...");
        // Your code here
    }
}

The @Slf4j annotation generates a logger named log for the class, which you can use to log messages.

Spring Boot - Devtools

If you have worked on latest UI development frameworks e.g. Node, angular, gulp etc. then you must have appreciated the auto-reload of UI in browser whenever there is change in some code. Its pretty useful and saves a lot of time.

To enable dev tools in spring boot application is very easy. Just add the spring-boot-devtools dependency in your build file.

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId></artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

Static Resource Caching

To improve the performance, dev tools cache the static content/template files to serve them faster to browser/client.

There are many such UI template libraries that support this feature. e.g. thymeleaf, freemarker, groovy, mustache etc.

#spring.freemarker.cache = true //set true in production environment
spring.freemarker.cache = false //set false in development environment; It is false by default.
 
//Other such properties 
spring.thymeleaf.cache = false
spring.mustache.cache = false
spring.groovy.template.cache = false

Automatic UI refresh

The spring-boot-devtools module includes an embedded LiveReload server that can be used to trigger a browser refresh when a resource is changed

spring.devtools.livereload.enabled  = false #Set false to disable live reload

SpringBoot Acuator - Health check, Auditing, Metrics,Monitoring

Actuator brings production-ready features to our application.

Monitoring our app, gathering metrics, understanding traffic or the state of our database becomes trivial with this dependency.

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

Some of important and widely used actuator endpoints are given below:

ENDPOINT USAGE
/env Returns list of properties in current environment
/health Returns application health information.
/auditevents Returns all auto-configuration candidates and the reason why they ‘were’ or ‘were not’ applied.
/beans Returns a complete list of all the Spring beans in your application.
/trace Returns trace logs (by default the last 100 HTTP requests).
/dump It performs a thread dump.
/metrics It shows metrics information like JVM memory used, system CPU usage, open files, and much more.

You can access all available endpoint by this URL: http://localhost:8080/actuator

{
	"_links": {
		"self": {
			"href": ,
			"templated": false
		},
		"health": {
			"href": ,
			"templated": false
		},
		"health-component-instance": {
			"href": ,
			"templated": true
		},
		"health-component": {
			"href": ,
			"templated": true
		},
		"info": {
			"href": ,
			"templated": false
		}
	}
}

If you see we have only 2 endpoints showing (health, info) out of 16 endpoints

By default, all the actuator endpoints are exposed over JMX but only the health and info endpoints are exposed over HTTP.

Here is how you can expose actuator endpoints over HTTP and JMX using application properties -

Exposing Actuator endpoints over HTTP

# Use "*" to expose all endpoints, or a comma-separated list to expose selected ones
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=

Exposing Actuator endpoints over JMX

# Use "*" to expose all endpoints, or a comma-separated list to expose selected ones
management.endpoints.jmx.exposure.include=*
management.endpoints.jmx.exposure.exclude=

Securing Actuator Endpoints with Spring Security

Actuator endpoints are sensitive and must be secured from unauthorized access. you can add spring security to your application using the following dependency -

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

we can override the default spring security configuration and define our own access rules.

Creating a Custom Actuator Endpoint

To customize the endpoint and define your own endpoint, simply Create a classs annotate with @Endpoint URL :

 org.springframework.boot.actuate.endpoint.annotation.Endpoint;
 org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
 org.springframework.stereotype.Component;

@Endpoint(id="helloEndpoint")
@Component
  ListEndPoints {
    @ReadOperation
     String mypoint(){
         "Hello" ;
    }
}

Few more Endpoints

SpringBoot – Project Lombok

Project Lombok is a Java library tool that generates code for minimizing boilerplate code. The library replaces boilerplate code with easy-to-use annotations.

For example, by adding a couple of annotations, you can get rid of code clutters, such as getters and setters methods, constructors, hashcode, equals, and toString methods, and so on.

  • val :Finally! Hassle-free final local variables.

  • var :Mutably! Hassle-free local variables.

  • @Data:All together now: A shortcut for @ToString, @EqualsAndHashCode, @Getter on all fields, and @Setter on all non-final fields, and @RequiredArgsConstructor!

  • @NonNull : How I learned to stop worrying and love the NullPointerException.

  • @Cleanup :Automatic resource management: Call your close() methods safely

  • @Getter/@Setter :Never write public int getFoo() {return foo;} again.

  • @ToString : generate a toString for you!

  • @EqualsAndHashCode
    Generates hashCode and equals implementations from the fields of your object.
  • @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor

    Constructors made to order: Generates constructors that take no arguments, one argument per final / non-nullfield, or one argument for every field.

  • @Value :Immutable classes made very easy.

  • @Builder No-hassle fancy-pants APIs for object creation!

  • @SneakyThrows :To boldly throw checked exceptions where no one has thrown them before!

  • @Synchronized:synchronized done right: Don’t expose your locks.

  • @With:Immutable ‘setters’ - methods that create a clone but with one changed field.

  • @Getter(lazy=true):Laziness is a virtue!

  • @Log :Captain’s Log, stardate 24435.7: “What was that line again?”

  • experimental :Head to the lab: The new stuff we’re working on.

Maven dependency

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

Ref.

https://dzone.com/articles/spring-boot-actuator-a-complete-guide

https://www.callicoder.com/spring-boot-actuator/

Spring Boot – Asynchronous Implementation

This article is about how asynchronous behavior can be achieved in spring boot. But first of all, let’s see the difference between synchronous and asynchronous.

  • Synchronous Programming: In synchronous programming, tasks are performed one at a time and only when one is completed the next is unblocked.

  • Asynchronous Programming: In asynchronous programming, multiple tasks can be executed simultaneously. You can move to another task before the previous one finishes.

In spring boot, we can achieve asynchronous behavior using @EnableAsync & @Async annotations.

  • @EnableAsync - to enable async support by annotating the main application class.

  • @Async - annotate the method

When you annotate a method with @Async annotation, it creates a proxy for that object based on “proxyTargetClass” property.

When spring executes this method, by default it will be searching for associated thread pool definition. Either a unique spring framework TaskExecutor bean in the context or Executor bean named “taskExecutor”. If neither of these two is resolvable, default it will use spring framework SimpleAsyncTaskExecutor to process async method execution.

Example – Without Async

@RestController
public class DecomController {
	@Autowired
	DecomService service;

	@GetMapping("/decomTrial")
	public String decomClinicalTrial() {
		System.out.println(" *** decomClinicalTrial :: Started*** ");
		service.ArchiveUsers();
		service.ArchiveReports();
		System.out.println(" *** decomClinicalTrial :: Completed.*** ");
		return "decomClinicalTrial Complted.";
	}
}
@Service
public class DecomService {

	public void ArchiveUsers() {
     S.o.p(Thread.currentThread().getName() + " :ArchiveUsers :Start "+new Date());
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
     S.o.p (Thread.currentThread().getName() + " :ArchiveUsers :End " + new Date());
	}

	public void ArchiveReports() {
	S.o.p(Thread.currentThread().getName() + ":ArchiveReports : Start" + new Date());
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	S.o.p(Thread.currentThread().getName() + " :ArchiveReports : End" + new Date());
	}
}
@SpringBootApplication
public class TrialServicesApplication {
	public static void main(String[] args) {
		SpringApplication.run(TrialServicesApplication.class, args);
		System.out.println("*************************************");
		System.out.println("Trial Services Startred ... ");
		System.out.println("*************************************");
	}
}
*** decomClinicalTrial: Started*** 
http-nio-8080-exec-1:ArchiveUsers :Start 24 Sep 2021 07:52:32 GMT
http-nio-8080-exec-1:ArchiveUsers :End 24 Sep 2021 07:52:37 GMT
http-nio-8080-exec-1:ArchiveReports :Start24 Sep 2021 07:52:37 GMT
http-nio-8080-exec-1:ArchiveReports :End24 Sep 2021 07:52:42 GMT
 *** decomClinicalTrial: Completed.***

Here all methods execute by single Thread http-nio-8080-exec-1

With @Aync

Place @EnableAsync on the Top of SpringBoot Main class - TrialServicesApplication

@EnableAsync 
@SpringBootApplication
public class TrialServicesApplication {
	public static void main(String[] args) {
		SpringApplication.run(TrialServicesApplication.class, args);
		System.out.println("*************************************");
		System.out.println("Trial Services Startred ... ");
		System.out.println("*************************************");
	}
}

Place @Async on the top of each method, which we want to execute in parallel.

@Service
public class DecomService {
	@Async
	public void ArchiveUsers() {
S.o.p(Thread.currentThread().getName() + " :ArchiveUsers :Start " + new Date());
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		S.o.p(Thread.currentThread().getName() + " :ArchiveUsers :End " + new Date());
	}

	@Async
	public void ArchiveReports() {
	 S.o.p(Thread.currentThread().getName() + ":ArchiveReports : Start" + new Date());
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	S.o.p(Thread.currentThread().getName() + " :ArchiveReports : End" + new Date());
	}
}
*** decomClinicalTrial :: Started*** 
*** decomClinicalTrial :: Completed.*** 
task-1 :ArchiveUsers : Start 24 Sep 2021 08:01:20 GMT
task-2 :ArchiveReports : Start24 Sep 2021 08:01:20 GMT
task-2 :ArchiveReports : End24 Sep 2021 08:01:25 GMT
task-1 :ArchiveUsers :End 24 Sep 2021 08:01:25 GMT

In above ArchiveUsers, ArchiveReports are executed paralley by two different threads task-1, task-2

Async methods with Return Types

Previously, The async method only used a void return type. And in my opinion, that is the best way to write self sufficient asynchronous functions. However, If you want to handle the results from an @Async function, you are in luck. Because Spring framework provides out of the box support for these situations using Future type. This is possible by wrapping the result inside of an AsyncResult class.

@Async
public Future<String> longRunningProcessThatReturns() {
    try {
        Thread.sleep(10000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return new AsyncResult<>("I take 10 seconds to return on a Thread named : " + Thread.currentThread().getName());
}

https://medium.com/globant/asynchronous-calls-in-spring-boot-using-async-annotation-d34d8a82a60c

https://springhow.com/spring-async/

https://howtodoinjava.com/spring-boot2/rest/enableasync-async-controller/

SpringBoot – Switch Between Environments

https://stackabuse.com/how-to-access-property-file-values-in-spring-boot/

Spring Boot already has support for profile based properties.

Simply add an application-[profile].properties file and specify the profiles to use using the spring.profiles.active property.

-Dspring.profiles.active=local

This will load the application.properties and the application-local.properties with the latter overriding properties from the first.

SpringBoot – Reactive Web

Spring WebFlux provides reactive, async, non-blocking programming support for web applications in an annotated Controller format similar to SpringMVC.

This approach is similar to how Node.js uses an async, non-blocking model which helps make it more scalable. Spring WebFlux uses a similar model but with multiple event loops.

Spring WebFlux moves away from the thread-per-request blocking model in traditional SpringMVC(with Tomcat by default) and moves towards a multi-EventLoop, async, non-blocking(with Netty by default) paradigm with back-pressure that is more scalable and efficient than traditional blocking code.