Partner – Microsoft – NPI EA (cat = Baeldung)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Microsoft – NPI EA (cat= Spring Boot)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, you can get started over on the documentation page.

And, you can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Orkes – NPI EA (cat=Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag=Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – MongoDB – NPI EA (tag=MongoDB)
announcement - icon

Traditional keyword-based search methods rely on exact word matches, often leading to irrelevant results depending on the user's phrasing.

By comparison, using a vector store allows us to represent the data as vector embeddings, based on meaningful relationships. We can then compare the meaning of the user’s query to the stored content, and retrieve more relevant, context-aware results.

Explore how to build an intelligent chatbot using MongoDB Atlas, Langchain4j and Spring Boot:

>> Building an AI Chatbot in Java With Langchain4j and MongoDB Atlas

Partner – LambdaTest – NPI EA (cat=Testing)
announcement - icon

Accessibility testing is a crucial aspect to ensure that your application is usable for everyone and meets accessibility standards that are required in many countries.

By automating these tests, teams can quickly detect issues related to screen reader compatibility, keyboard navigation, color contrast, and other aspects that could pose a barrier to using the software effectively for people with disabilities.

Learn how to automate accessibility testing with Selenium and the LambdaTest cloud-based testing platform that lets developers and testers perform accessibility automation on over 3000+ real environments:

Automated Accessibility Testing With Selenium

1. Overview

We often need human-like interactions when we have a conversation with an AI application. Therefore, there is a need to maintain the conversation with the LLM model, while Spring AI addresses it through its chat memory functionality.

In this tutorial, we’ll explore different options of chat memory provided in Spring AI and provide examples on how we integrate the chat memory with the chat client.

2. Chat Memory

Large language models (LLMs) are stateless and do not memorize anything. Each prompt to the LLM is considered an isolated query, meaning that the model does not remember any previous message.

In AI applications, keeping previous conversations is crucial to let the LLM produce meaningful responses. This is where chat memory come in to fill the gap, providing:

  • Contextual Understanding – This allows the LLM to produce responses based on the whole conversation.
  • Personalization – This facilitates providing personalized responses based on the chat memory.
  • Persistence – Based on the implementation, the chat memory could persist across multiple sessions.

3. Chat Memory Repositories

Spring AI provides a ChatMemory interface and some off-the-shelf implementations to help us easily integrate chat memory into our application.

First, let’s add the Maven spring-ai-starter-model-openai dependency to enable OpenAI integration. This dependency will transitively import the Spring AI core libraries as well:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
    <version>1.0.0</version>
</dependency>

When we create the chat memory, we have to provide an implementation of ChatMemoryRepository, which is responsible for persisting the chat messages to the store:

ChatMemoryRepository chatMemoryRepository;

ChatMemory chatMemory = MessageWindowChatMemory.builder()
  .chatMemoryRepository(chatMemoryRepository)
  .maxMessages(10)
  .build();

Spring AI provides different types of chat memory repositories that we can choose from depending on the tech stack of our project. We’ll discuss two of them in here.

3.1. In-Memory Repository

If we do not explicitly define the chat memory, Spring AI uses an in-memory store by default. It stores the chat message internally in a ConcurrentHashMap where the conversation ID is the key, and the value is a list of messages in that conversation:

public final class InMemoryChatMemoryRepository implements ChatMemoryRepository {
    Map<String, List<Message>> chatMemoryStore = new ConcurrentHashMap();

    // other methods
}

The in-memory repository is very simple and works well when we don’t need any long-term persistence. We need to pick something else if long-term persistence is needed.

3.2. JDBC Repository

JDBC repository is to persist chat messages in a relational database. Spring AI provides built-in support for several relational databases, including MySQL, PostgreSQL, SQL Server, and HSQLDB.

If we want to store the chat memory in a relational database, we’ll need to include the Maven dependency to support it:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-model-chat-memory-repository-jdbc</artifactId>
    <version>1.0.0</version>
</dependency>

Each of the built-in supported databases has its own dialect implementation that provides the SQL statements for CRUD operations on the chat memory table. We need to supply the dialect when we initialize the JdbcChatMemoryRepository:

JdbcChatMemoryRepositoryDialect dialect = ...; // The choose repository dialect
ChatMemoryRepository repository = JdbcChatMemoryRepository.builder()
  .jdbcTemplate(jdbcTemplate)
  .dialect(dialect)
  .build();

For databases that do not have built-in support, we have to implement the JdbcChatMemoryRepositoryDialect interface and provide the SQL statements for each CRUD operation:

public interface JdbcChatMemoryRepositoryDialect {
    String getSelectMessagesSql();

    String getInsertMessageSql();

    String getSelectConversationIdsSql();

    String getDeleteMessagesSql();
}

For the implemented dialect in Spring AI, the CRUD operations follow standard SQL and do not rely on a specific vendor. Therefore, we could simply use a provided implementation such as MysqlChatMemoryRepositoryDialect without implementing our custom dialect.

We need to initialize the schema before using it. For supported dialects, Spring AI provides the schema creation script as well. We can find those scripts in classpath:org/springframework/ai/chat/memory/repository/jdbc.

4. Apply Chat Memory to Chat Client

Spring AI provides auto-configuration for chat memory in ChatMemoryAutoConfiguration. If we choose an in-memory repository, we don’t need to define anything explicitly, as this is the default.

However, if we want to use the JDBC repository instead, we need to provide our bean method of ChatMemoryRepository to override the default in-memory one:

@Configuration
public class ChatConfig {
    @Bean
    public ChatMemoryRepository getChatMemoryRepository(JdbcTemplate jdbcTemplate) {
        return JdbcChatMemoryRepository.builder()
          .jdbcTemplate(jdbcTemplate)
          .dialect(new HsqldbChatMemoryRepositoryDialect())
          .build();
    }
}

Note that we don’t need to define the bean method of ChatMemory explicitly, as it’s already defined in the ChatMemoryAutoConfiguration.

Let’s create a ChatService in Spring Boot:

@Component
@SessionScope
public class ChatService {
    private final ChatClient chatClient;
    private final String conversationId;

    public ChatService(ChatModel chatModel, ChatMemory chatMemory) {
        this.chatClient = ChatClient.builder(chatModel)
          .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
          .build();
        this.conversationId = UUID.randomUUID().toString();
    }

    public String chat(String prompt) {
        return chatClient.prompt()
          .user(userMessage -> userMessage.text(prompt))
          .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
          .call()
          .content();
    }
}

In the constructor, Spring Boot will automatically inject the ChatMemory implementation. We thereby initialize the ChatClient with it via MemoryChatMemoryAdvisor.

We define the chat method to accept the prompt and send the message to the chat model. Additionally, we add a conversation ID as the chat advisor parameter to uniquely identify the conversation based on the current session.

It’s important to note that we must annotate the service with @SessionScope so that its instance can be persisted across multiple requests.

5. Integration with OpenAI

In our demonstration, we’ll integrate chat memory with OpenAI and examine how the Spring AI calls the OpenAI API and adopt an in-memory HSQL DB as the persistence store.

Let’s add properties to application.yml for adding the OpenAI API key, setting up the database connection, and initializing the schema during application startup:

spring:
  ai:
    openai:
      api-key: "<YOUR-API-KEY>"

  datasource:
    url: jdbc:hsqldb:mem:chatdb
    driver-class-name: org.hsqldb.jdbc.JDBCDriver
    username: sa
    password:

  sql:
    init:
      mode: always
      schema-locations: classpath:org/springframework/ai/chat/memory/repository/jdbc/schema-hsqldb.sql

Now, the configuration is all set. Let’s create a REST endpoint so that we can call the ChatService that we defined earlier:

@RestController
public class ChatController {
    private final ChatService chatService;

    public ChatController(ChatService chatService) {
        this.chatService = chatService;
    }

    @PostMapping("/chat")
    public ResponseEntity<String> chat(@RequestBody @Valid ChatRequest request) {
        String response = chatService.chat(request.getPrompt());
        return ResponseEntity.ok(response);
    }
}

ChatRequest is a simple DTO that contains the prompt as a String:

public class ChatRequest {
    @NotNull
    private String prompt;

    // getter and setter
}

6. Test Run

We’re now ready to send requests to the REST endpoint. We’ll use Postman to send requests to the REST endpoint and intercept the HTTP requests between our Spring Boot application and OpenAI with the HTTP toolkit to see how things work together.

6.1. First Request

Let’s make a call to ask for a joke in Postman and check the response:

chat memory 1st request

When we observe the intercepted request in the HTTP toolkit, we’ll see the HTTP request to OpenAI:

{
  "messages": [
    {
      "content": "Tell me a joke",
      "role": "user"
    }
  ],
  "model": "gpt-4o-mini",
  "stream": false,
  "temperature": 0.7
}

This is a pretty trivial request that sends our prompt payload using the user role.

6.2. Second Request

Now, let’s make another request to compare the difference:

chat memory 2nd request

When we read the intercepted HTTP request to OpenAI this time, we see that Spring AI not only sends our prompt payload to OpenAI, but it also sends the previous prompt and response as well:

{
  "messages": [
    {
      "content": "Tell me a joke",
      "role": "user"
    },
    {
      "content": "Why did the scarecrow win an award? \n\nBecause he was outstanding in his field!",
      "role": "assistant"
    },
    {
      "content": "Tell me another one",
      "role": "user"
    }
  ],
  "model": "gpt-4o-mini",
  "stream": false,
  "temperature": 0.7
}

In this example, we observe that the Spring AI sends the entire chat history to the chat model. This approach helps the chat model to maintain the context of the whole conversation and make the interaction feel more natural.

7. Conclusion

In this article, we’ve learned how Spring AI enhances the conversational experience by maintaining the chat history across multiple chat requests via chat memory.

We explored different memory repositories and illustrated how to integrate chat memory with Spring AI and OpenAI. We also examined how the Spring AI chat memory works with OpenAI behind the scenes.

As usual, the full source code is available over on GitHub.

Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

Partner – Microsoft – NPI EA (cat = Baeldung)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Microsoft – NPI EA (cat = Spring Boot)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Orkes – NPI EA (cat = Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag = Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Partner – MongoDB – NPI EA (tag=MongoDB)
announcement - icon

Traditional keyword-based search methods rely on exact word matches, often leading to irrelevant results depending on the user's phrasing.

By comparison, using a vector store allows us to represent the data as vector embeddings, based on meaningful relationships. We can then compare the meaning of the user’s query to the stored content, and retrieve more relevant, context-aware results.

Explore how to build an intelligent chatbot using MongoDB Atlas, Langchain4j and Spring Boot:

>> Building an AI Chatbot in Java With Langchain4j and MongoDB Atlas

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Microsoft – NPI (cat=Spring)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

eBook Jackson – NPI EA – 3 (cat = Jackson)