Home Blog Page 86

Advanced Docker Concepts for Spring Boot Applications

0
java spring boot course
java spring boot course

Table of Contents

  1. Introduction to Advanced Docker Concepts
  2. Docker Networking
  3. Docker Volumes and Persistent Storage
  4. Multi-Stage Builds
  5. Dockerizing Spring Boot Applications with Dependencies
  6. Managing Configurations and Secrets in Docker
  7. Docker Swarm and Kubernetes for Orchestration
  8. Best Practices for Production-Ready Docker Images
  9. Troubleshooting Advanced Dockerized Spring Boot Apps
  10. Summary

1. Introduction to Advanced Docker Concepts

While Docker is useful for packaging and deploying applications in isolated containers, there are more advanced features and techniques that can help improve efficiency, scalability, and management of your Dockerized Spring Boot applications. In this module, we will cover:

  • Networking: How containers communicate with each other and with the outside world.
  • Volumes: How to persist data outside of containers.
  • Multi-Stage Builds: How to optimize Dockerfiles for production.
  • Docker Swarm and Kubernetes: Orchestrating containers for large-scale applications.
  • Best Practices: Ensuring production-ready containers.
  • Troubleshooting: Handling common issues in a production environment.

2. Docker Networking

Docker containers are isolated by default but can communicate with each other using various networking modes. When containers interact in a multi-container setup, Docker provides several networking options.

Types of Docker Networking

  • Bridge Network: This is the default network type for standalone containers. Containers on the bridge network can communicate with each other using their IP addresses, but they can’t be accessed directly from the outside unless port forwarding is set up.
  • Host Network: Containers share the host machine’s network stack. This is useful when you need the container to have direct access to the host’s networking features (e.g., firewall, interfaces).
  • Overlay Network: Used for communication between containers in different Docker hosts (useful in multi-host Docker deployments or when using Docker Swarm).
  • None: This option disables networking entirely, useful for containers that don’t need network access.

How to Define a Network in Docker Compose

You can define a custom network in docker-compose.yml to ensure proper communication between services.

version: '3'
services:
springboot-app:
image: myapp
ports:
- "8080:8080"
networks:
- my-network
mysql-db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: example
networks:
- my-network

networks:
my-network:
driver: bridge

This configuration defines a custom network my-network, and both springboot-app and mysql-db can communicate with each other using that network.


3. Docker Volumes and Persistent Storage

By default, data inside a Docker container is ephemeral. This means when the container is removed, the data is lost. To persist data, Docker uses volumes.

Why Use Volumes?

  • Persistence: Data can be stored outside of the container and persists even when the container is removed.
  • Sharing Data: Volumes allow multiple containers to access and share the same data.
  • Backup and Restore: Volumes are easier to back up and restore compared to data stored inside a container.

How to Define Volumes in Docker

In your docker-compose.yml file, you can define volumes as follows:

version: '3'
services:
springboot-app:
image: myapp
ports:
- "8080:8080"
volumes:
- app-data:/data

volumes:
app-data:

Here, app-data is a named volume, and it is mounted to the /data directory inside the container.

Mounting Local Directories as Volumes

You can also mount local directories on your machine as volumes:

version: '3'
services:
springboot-app:
image: myapp
ports:
- "8080:8080"
volumes:
- ./local-data:/data

This will mount the ./local-data directory from the host machine to the /data directory inside the container.


4. Multi-Stage Builds

Multi-stage builds allow you to optimize Docker images by separating the build environment from the runtime environment. This reduces the size of the final image and ensures that only the necessary files are included.

Sample Multi-Stage Dockerfile for Spring Boot

# Stage 1: Build the application
FROM maven:3.8-openjdk-17 AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests

# Stage 2: Create the runtime image
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY --from=build /app/target/myapp.jar myapp.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "myapp.jar"]

Explanation:

  • Stage 1: Builds the application using Maven in a separate build container (maven:3.8-openjdk-17).
  • Stage 2: Creates a much smaller image that only contains the necessary runtime components (openjdk:17-jdk-slim), along with the Spring Boot .jar file.

This approach results in a smaller and more efficient Docker image.


5. Dockerizing Spring Boot Applications with Dependencies

For applications that rely on external services (like a database), Docker allows you to define and manage dependencies directly in the docker-compose.yml file. You can use a MySQL or PostgreSQL container alongside your Spring Boot application.

Example with MySQL:

version: '3'
services:
springboot-app:
image: myapp
ports:
- "8080:8080"
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql-db:3306/mydb
- SPRING_DATASOURCE_USERNAME=root
- SPRING_DATASOURCE_PASSWORD=example
depends_on:
- mysql-db

mysql-db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: example
volumes:
- mysql-data:/var/lib/mysql

volumes:
mysql-data:

This setup ensures that the Spring Boot application can communicate with the MySQL container using the mysql-db service name as the database host.


6. Managing Configurations and Secrets in Docker

Docker allows you to manage configurations and secrets securely. While environment variables are often used for simple configuration, sensitive data like passwords should be handled carefully.

Environment Variables:

You can define sensitive information such as passwords and tokens directly in your docker-compose.yml file using environment variables:

services:
springboot-app:
environment:
- SPRING_DATASOURCE_PASSWORD=${DB_PASSWORD}

You can also use .env files to store these variables locally and keep them out of source control.

Using Docker Secrets:

Docker secrets can be used for more secure storage of sensitive information, particularly when deploying in a Swarm mode.


7. Docker Swarm and Kubernetes for Orchestration

When working with large-scale applications, container orchestration platforms like Docker Swarm and Kubernetes become essential. They manage container deployment, scaling, load balancing, and networking.

Docker Swarm:

Docker Swarm is a native clustering tool for Docker. It allows you to manage multiple Docker engines as a single cluster, making it easier to scale applications and manage their lifecycle.

Kubernetes:

Kubernetes is the most widely used orchestration platform. It offers robust features such as automatic scaling, self-healing, service discovery, and more. You can deploy Docker containers on Kubernetes clusters, which will handle the orchestration for you.


8. Best Practices for Production-Ready Docker Images

  • Keep images small: Use a minimal base image and avoid unnecessary dependencies.
  • Use multi-stage builds: Separate the build environment from the runtime environment.
  • Use non-root users: Avoid running containers as the root user. Create a non-root user in your Dockerfile.
  • Avoid hardcoding sensitive data: Use environment variables, Docker secrets, or other external tools for managing sensitive information.

9. Troubleshooting Advanced Dockerized Spring Boot Apps

  • Container fails to start: Check the container logs with docker logs <container_id> to identify the issue. Common problems include misconfigured environment variables or missing dependencies.
  • Application not responding: Ensure that the application is correctly bound to the correct port and that Docker networking is configured correctly.
  • Port conflicts: If the port is already in use on the host machine, change the port mapping in the docker-compose.yml file.

10. Summary

In this module, we explored more advanced Docker concepts like networking, volumes, multi-stage builds, and orchestration tools such as Docker Swarm and Kubernetes. Docker allows for efficient and scalable deployments, and by using these techniques, you can ensure that your Spring Boot application is both lightweight and production-ready.

Caching with Spring Boot (@Cacheable)

0
java spring boot course
java spring boot course

Table of Contents

  1. Introduction to Caching in Spring Boot
  2. Benefits of Caching
  3. Setting Up Caching in Spring Boot
  4. Understanding @Cacheable Annotation
  5. Caching Providers in Spring Boot
  6. Cacheable Methods and Cache Names
  7. Cache Eviction and Expiration
  8. Advanced Caching Features (e.g., @CachePut, @CacheEvict)
  9. Troubleshooting Caching Issues
  10. Summary

1. Introduction to Caching in Spring Boot

Caching is an essential concept in application performance optimization. It allows you to store frequently accessed data in memory, thereby reducing the load on underlying resources such as databases or external services. In Spring Boot, caching can be easily enabled and configured using Spring’s powerful caching abstraction.

Spring provides a simple yet flexible mechanism for caching with annotations like @Cacheable, @CachePut, and @CacheEvict. This module will explore how to use these annotations and configure caching effectively in your Spring Boot application.


2. Benefits of Caching

  • Improved Performance: Reduces the need to fetch data repeatedly from a database or make external API calls by caching results.
  • Reduced Latency: Fetching data from memory is much faster than querying a database or external service.
  • Scalability: Cache helps to reduce the load on critical resources, making your application more scalable.
  • Cost-effective: For applications relying heavily on external APIs or databases, caching can reduce operational costs related to database and network calls.

3. Setting Up Caching in Spring Boot

To enable caching in Spring Boot, you need to add the necessary dependencies and configurations.

Add Caching Dependency

If you’re using Maven, add the following dependency:

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

For Gradle, use:

implementation 'org.springframework.boot:spring-boot-starter-cache'

Enable Caching in Your Spring Boot Application

You need to enable caching in your Spring Boot application by adding the @EnableCaching annotation to one of your configuration classes.

@Configuration
@EnableCaching
public class CacheConfig {
}

This annotation enables Spring’s caching support across the application.


4. Understanding @Cacheable Annotation

The @Cacheable annotation tells Spring to cache the result of a method based on its arguments. If the method is called again with the same arguments, Spring will return the cached result rather than executing the method.

Example of @Cacheable

@Service
public class ProductService {

@Cacheable(value = "products", key = "#id")
public Product getProductById(Long id) {
simulateSlowService();
return new Product(id, "Product Name");
}

private void simulateSlowService() {
try {
Thread.sleep(3000); // Simulate a delay
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

In this example:

  • The @Cacheable annotation tells Spring to cache the result of getProductById.
  • The value parameter is the name of the cache.
  • The key parameter specifies the cache key, which in this case is the id of the product.

5. Caching Providers in Spring Boot

Spring Boot supports several caching providers, including:

  • Simple in-memory cache: Default caching provider (using ConcurrentMapCache).
  • EhCache: Popular open-source caching solution.
  • Redis: A fast, open-source key-value store.
  • Caffeine: High-performance, Java-based caching library.
  • Guava: Google’s caching library.

To use an external caching provider, you need to include the corresponding dependency and configure it in application.properties or application.yml.

Example: Using Redis for Caching

Add the Redis dependency:

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

Configure Redis in application.properties:

spring.cache.type=redis
spring.redis.host=localhost
spring.redis.port=6379

6. Cacheable Methods and Cache Names

In addition to basic method caching, Spring also allows you to specify cache names, expiration times, and conditional caching.

Cache Names

You can specify multiple cache names by providing an array for the value attribute:

@Cacheable(value = {"cache1", "cache2"}, key = "#id")
public Product getProductById(Long id) {
// Method logic
}

This will store the cached data in both cache1 and cache2.

Conditional Caching

You can control when to cache results based on method parameters or other conditions:

@Cacheable(value = "products", key = "#id", condition = "#id > 10")
public Product getProductById(Long id) {
// Method logic
}

Here, the cache will only be used if the id is greater than 10.


7. Cache Eviction and Expiration

Spring Boot supports cache eviction using the @CacheEvict annotation. This allows you to remove specific entries from the cache or clear the entire cache.

Example: Evicting Cache

@CacheEvict(value = "products", key = "#id")
public void deleteProduct(Long id) {
productRepository.deleteById(id);
}

This will remove the cached entry for the product with the specified id when the deleteProduct method is called.

Cache Expiration

To set cache expiration times, you typically configure this at the provider level. For example, in Redis or EhCache, you can set TTL (Time To Live) settings to automatically expire cached entries after a certain period.


8. Advanced Caching Features (e.g., @CachePut, @CacheEvict)

@CachePut

The @CachePut annotation is used to update the cache without interfering with the method execution. It forces the cache to be updated with the method’s result even if the method is executed.

@CachePut(value = "products", key = "#product.id")
public Product updateProduct(Product product) {
return productRepository.save(product);
}

Here, after saving the updated product, the cache is updated with the new value.

@CacheEvict (Advanced Use)

You can also evict the cache based on specific conditions like method execution or after a certain delay:

@CacheEvict(value = "products", allEntries = true)
public void clearCache() {
// Logic to clear the cache
}

This clears all entries from the products cache.


9. Troubleshooting Caching Issues

  • Cache not updating: Ensure that the cache manager is properly configured, and check if the @CachePut and @CacheEvict annotations are being used correctly.
  • Inconsistent cache values: Verify that the cache key generation logic (key attribute in annotations) is accurate.
  • Cache misses: This may occur if the cache is being cleared unexpectedly or if the cache expires too quickly.

10. Summary

Caching in Spring Boot can greatly improve the performance of your applications by reducing redundant operations. By leveraging annotations like @Cacheable, @CachePut, and @CacheEvict, you can easily manage your cache logic. Spring Boot’s flexible caching framework supports a variety of cache providers, making it suitable for different types of applications, from small to large-scale systems.

Spring Boot Admin and Health Endpoints

0
java spring boot course
java spring boot course

Table of Contents

  1. What is Spring Boot Admin?
  2. Why Use Spring Boot Admin?
  3. Setting Up Spring Boot Admin Server
  4. Registering Clients to the Admin Server
  5. Exploring Spring Boot Admin Dashboard
  6. Spring Boot Actuator Health Endpoints
  7. Custom Health Indicators
  8. Securing Spring Boot Admin
  9. Spring Boot Admin Notifications and Alerts
  10. Summary

1. What is Spring Boot Admin?

Spring Boot Admin is a community-driven project by Codecentric that provides a web-based UI for managing and monitoring Spring Boot applications. It leverages Spring Boot Actuator under the hood to gather metrics and system health data, presenting it in a centralized, visual format. It’s especially useful when you have multiple microservices running and need a single pane of glass to monitor them all.


2. Why Use Spring Boot Admin?

  • Monitor multiple Spring Boot applications in one dashboard
  • Visual representation of application metrics, logs, environment, and endpoints
  • Easily track application status and health
  • Customize health checks and alerts
  • Centralize management of log levels, threads, and JVM state

3. Setting Up Spring Boot Admin Server

To set up a Spring Boot Admin Server:

Add Dependencies

In your Admin Server’s pom.xml:

<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>3.1.8</version> <!-- Use compatible version -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

Enable Admin Server

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

Basic Config in application.properties

server.port=8080
spring.application.name=admin-server

4. Registering Clients to the Admin Server

On each Spring Boot application you want to monitor:

Add Client Dependencies

<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>3.1.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Configure Application Properties

spring.application.name=my-app
management.endpoints.web.exposure.include=*
spring.boot.admin.client.url=http://localhost:8080

Ensure that the actuator endpoints are exposed and accessible.


5. Exploring Spring Boot Admin Dashboard

Once everything is configured:

  • Visit http://localhost:8080 (Admin Server UI)
  • You’ll see the registered clients with their:
    • Health
    • Metrics
    • Beans
    • Environment variables
    • JVM memory, threads, GC info
    • Loggers and configuration
    • Custom endpoints

Each client is continuously monitored and updated in real time.


6. Spring Boot Actuator Health Endpoints

Spring Boot Admin uses the actuator’s /health endpoint to determine if an application is up or down.

By default, the /actuator/health shows a simple “UP” or “DOWN”. You can show detailed health information by setting:

management.endpoint.health.show-details=always

Default Health Indicators

Spring Boot includes indicators for:

  • Disk space
  • Database
  • Redis, MongoDB
  • Ping
  • Custom indicators

7. Custom Health Indicators

You can define your own logic for health reporting:

@Component
public class MyCustomHealthIndicator implements HealthIndicator {

@Override
public Health health() {
// Your custom logic
boolean isHealthy = checkService();
if (isHealthy) {
return Health.up().withDetail("customService", "Available").build();
} else {
return Health.down().withDetail("customService", "Unavailable").build();
}
}

private boolean checkService() {
// Simulate a service check
return true;
}
}

This will appear under the /actuator/health and in the Spring Boot Admin dashboard.


8. Securing Spring Boot Admin

You can secure the Admin UI and client registration using Spring Security:

Security Configuration (Server)

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/assets/**", "/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().permitAll();
}
}

You can also secure the actuator endpoints on each client.


9. Spring Boot Admin Notifications and Alerts

Spring Boot Admin supports notifications via:

  • Email
  • Slack
  • PagerDuty
  • HipChat
  • OpsGenie
  • Let’s you define thresholds and alerting rules

To enable Slack integration, add:

<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-notifier-slack</artifactId>
</dependency>

And configure:

spring.boot.admin.notify.slack.enabled=true
spring.boot.admin.notify.slack.webhook-url=https://hooks.slack.com/services/...

10. Summary

Spring Boot Admin combined with Actuator provides a comprehensive, real-time dashboard for managing and monitoring Spring Boot applications. It scales well for microservices, enhances observability, and supports both out-of-the-box and custom metrics and health indicators. It also improves operational response time by enabling secure, centralized monitoring with real-time notifications.

Spring Boot Actuator for Monitoring

0
java spring boot course
java spring boot course

Table of Contents

  1. What is Spring Boot Actuator?
  2. Why Use Actuator?
  3. Adding Actuator to Your Project
  4. Exposing Actuator Endpoints
  5. Commonly Used Endpoints
  6. Customizing Endpoint Exposure
  7. Securing Actuator Endpoints
  8. Actuator and Health Monitoring
  9. Metrics and Integration with Prometheus/Grafana
  10. Creating Custom Actuator Endpoints
  11. Summary

1. What is Spring Boot Actuator?

Spring Boot Actuator is a powerful feature of the Spring Boot ecosystem that enables production-ready features for monitoring and managing applications. It exposes various REST endpoints to monitor the internal state and behavior of your application without changing the code logic.


2. Why Use Actuator?

  • Health Checks – Monitor application readiness and liveness.
  • Metrics – View memory usage, CPU load, and JVM statistics.
  • Audit Events – Track important system events.
  • Thread Dumps – Analyze running threads.
  • Environment Info – View environment variables, active profiles, etc.
  • Integration – Easily integrate with Prometheus, Micrometer, and other monitoring tools.

3. Adding Actuator to Your Project

Add the Spring Boot Actuator dependency in your pom.xml:

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

Or if you’re using Gradle:

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

4. Exposing Actuator Endpoints

By default, only the /actuator/health and /actuator/info endpoints are exposed over HTTP. To expose all or specific endpoints, configure your application.properties or application.yml:

management.endpoints.web.exposure.include=*

Or selectively:

management.endpoints.web.exposure.include=health,info,metrics,env

5. Commonly Used Endpoints

EndpointDescription
/actuator/healthApplication health status
/actuator/infoApp info like version, build
/actuator/metricsDetailed metrics (JVM, CPU, etc.)
/actuator/envEnvironment variables
/actuator/beansList of all Spring beans
/actuator/loggersView/change logging levels
/actuator/mappingsShow request-to-handler mappings

To get a full list, visit /actuator after exposing endpoints.


6. Customizing Endpoint Exposure

You can include/exclude endpoints individually:

management.endpoints.web.exposure.include=health,metrics
management.endpoints.web.exposure.exclude=beans,env

To change the base path for all actuator endpoints:

management.endpoints.web.base-path=/management

7. Securing Actuator Endpoints

Actuator endpoints can expose sensitive application internals. Use Spring Security to restrict access:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/actuator/health", "/actuator/info").permitAll()
.antMatchers("/actuator/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.httpBasic();
}
}

You can also use application.properties to enable HTTP Basic authentication.


8. Actuator and Health Monitoring

The /actuator/health endpoint provides insight into the application’s status. You can include detailed health info:

management.endpoint.health.show-details=always

Spring Boot integrates with various health indicators:

  • Database health
  • Disk space
  • Redis/Mongo/RabbitMQ connections
  • Custom health indicators (covered below)

Custom Health Indicator

@Component
public class CustomHealthIndicator implements HealthIndicator {
@Override
public Health health() {
// You can add logic here to check custom conditions
return Health.up().withDetail("customService", "Available").build();
}
}

9. Metrics and Integration with Prometheus/Grafana

Spring Boot integrates with Micrometer, which supports metrics exporting.

To use Prometheus:

<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

Expose the Prometheus endpoint:

management.endpoints.web.exposure.include=prometheus

Then access metrics at /actuator/prometheus and configure Prometheus to scrape it.


10. Creating Custom Actuator Endpoints

You can define your own actuator endpoints:

@Component
@Endpoint(id = "custom")
public class CustomEndpoint {

@ReadOperation
public Map<String, String> customEndpoint() {
return Map.of("status", "Custom actuator endpoint working");
}
}

The above creates an endpoint at /actuator/custom.


11. Summary

Spring Boot Actuator offers comprehensive monitoring and management capabilities for Spring Boot applications. By exposing standardized and custom endpoints, you gain real-time insights into application behavior, making it invaluable for debugging, observability, and DevOps automation.

JWT-Based Authentication (Stateless Auth) in Spring Boot

0
java spring boot course
java spring boot course

Table of Contents

  1. Introduction to JWT
  2. How JWT Works (Stateless Auth)
  3. Benefits of JWT in Spring Applications
  4. Generating JWT Tokens
  5. Validating JWT Tokens
  6. Creating a Custom Filter
  7. Configuring Spring Security for JWT
  8. Testing the Full Flow
  9. Best Practices
  10. Summary

1. Introduction to JWT

JSON Web Tokens (JWT) are a compact, URL-safe means of representing claims to be transferred between two parties. In the context of Spring Security, JWTs are used to authorize users in a stateless manner—no server-side session storage is required.

A JWT typically contains three parts:

  • Header: Type and signing algorithm.
  • Payload: User information and claims.
  • Signature: Verifies the token wasn’t tampered with.

2. How JWT Works (Stateless Auth)

In JWT-based stateless authentication:

  1. The user logs in with credentials.
  2. Server authenticates and returns a signed JWT token.
  3. The client stores the JWT (usually in localStorage or cookies).
  4. For each request, the client sends the token in the Authorization header.
  5. The server verifies the token and processes the request.

3. Benefits of JWT in Spring Applications

  • Stateless: No session storage on server.
  • Scalable: Ideal for distributed systems.
  • Self-contained: Carries user data and metadata.
  • Cross-platform: Can be used across languages and services.

4. Generating JWT Tokens

Use a utility class to generate tokens:

public class JwtUtil {
private final String SECRET_KEY = "your-secret";

public String generateToken(UserDetails userDetails) {
return Jwts.builder()
.setSubject(userDetails.getUsername())
.claim("roles", userDetails.getAuthorities())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10 hrs
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
}

5. Validating JWT Tokens

public boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}

You’ll also need methods like extractUsername(), extractExpiration() etc., using Jwts.parser().


6. Creating a Custom JWT Filter

This filter intercepts requests, extracts the JWT, and sets the security context.

public class JwtRequestFilter extends OncePerRequestFilter {

@Autowired
private JwtUtil jwtUtil;

@Autowired
private UserDetailsService userDetailsService;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {

final String authHeader = request.getHeader("Authorization");

String username = null;
String jwt = null;

if (authHeader != null && authHeader.startsWith("Bearer ")) {
jwt = authHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
}

if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);

if (jwtUtil.validateToken(jwt, userDetails)) {
UsernamePasswordAuthenticationToken token =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());

token.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

SecurityContextHolder.getContext().setAuthentication(token);
}
}

chain.doFilter(request, response);
}
}

7. Configuring Spring Security for JWT

Update your security configuration:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

@Autowired
private JwtRequestFilter jwtRequestFilter;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeHttpRequests()
.requestMatchers("/authenticate").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);

http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);

return http.build();
}
}

8. Testing the Full Flow

  1. Authenticate:
    • POST to /authenticate with username and password.
    • Receive JWT token.
  2. Access Protected Resource:
    • Set header: Authorization: Bearer <token>
    • GET /api/protected – success if token is valid.

9. Best Practices

  • Always sign tokens with a strong secret or RSA keys.
  • Use HTTPS to secure tokens in transit.
  • Set short expiration times and refresh tokens.
  • Avoid storing JWTs in localStorage on browsers prone to XSS.
  • Use claim fields wisely—don’t overstuff JWTs.

10. Summary

JWT-based authentication provides a scalable, stateless solution for securing your Spring Boot APIs. It avoids session storage, making it ideal for RESTful microservices.

Key Concepts Covered:

  • What JWT is and how it works
  • How to generate, sign, and validate tokens
  • Creating a custom JWT filter
  • Securing endpoints using JWT