Spring Boot Starters, Auto-Configuration, and Properties in Spring AI

Felix Do
6 min readDec 24, 2023

--

This is article 2 of “Hello Spring AI” series https://medium.com/@toando.coffee/hello-spring-ai-d613cf72fe74

In the first article of our exploration into Spring AI, I demonstrated how to run a Spring AI application and test it using a RESTful endpoint. This allowed users to send prompts to the application, which seamlessly integrated with either the OpenAI API or Azure OpenAI API, providing responses from these powerful AI platforms.

In the “Hello Spring AI” project, several questions may arise:

1.. In the grade or maven file, there are only 2 dependencies of Spring AI have been mentioned but while exploring external libraries, it’s evident that there are additional dependencies not explicitly mentioned in the gradle build or maven pom file. Why are these dependencies automatically injected into the project? What role do they play in the overall functionality?

implementation 'org.springframework.experimental.ai:spring-ai-azure-openai-spring-boot-starter:0.7.1-SNAPSHOT'
implementation 'org.springframework.experimental.ai:spring-ai-openai-spring-boot-starter:0.7.1-SNAPSHOT'

2.. How does the application have the capability to instantiate an AiClient instance? (OpenAI or AzureOpenAI)

3.. How can I know that I need to provide these configurations as below to make my application work?

## Azure Open AI
spring:
ai:
azure:
openai:
api-key: ${AZURE_OPENAI_API_KEY}
endpoint: ${AZURE_OPENAI_ENDPOINT}
model: ${AZURE_OPENAI_MODEL}

## Open AI
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}

This article will delve extensively into spring boot starter, auto-configuration, and configuration properties in Spring AI. These will address all the doubts above

What is Spring Boot Starter?

In Spring Boot, a starter is a pre-configured, ready-to-use set of dependencies that simplifies the inclusion of specific functionalities or libraries in your Spring Boot application. It is a gradle or maven dependency where it will include all necessary dependencies to make the specific feature “ready to use”.

What does this mean? Let’s delve deeper into the concept of the Spring AI starter.

Dive into the spring-ai-openai-spring-boot-starter, a Spring Boot starter designed for the “Spring AI OpenAI” feature. This starter simplifies to include all necessary dependencies, including spring-ai-openai-auto-configuration and spring-ai-openai so developers can start implementation on spring AI and not worry about managing dependencies.

To discover the dependencies included in the starter, you can navigate to the pom.xml file under External Libraries or open Dependencies in IntelliJ for Gradle or Maven.

Upon inspection, you’ll notice that the spring-ai-openai-spring-boot-starter effectively consolidates all essential dependencies into a single module. This streamlined approach simplifies the management of dependencies for the “Spring AI OpenAI” feature.

To further your exploration, take a look at other Spring Boot starters, such as spring-boot-starter-web. By opening the Dependencies view in Gradle or Maven, you’ll discern the additional dependencies that this starter relies on, providing insights into the integral components required for web-related functionalities in a Spring Boot application.

Indeed, the typical naming convention for Spring Boot starters is spring-boot-starter-*, where the wildcard represents the specific functionality or features of the starter (e.g., spring-boot-starter-web for web applications). However, in the case of the Spring AI project, a different naming structure is spring-ai-openai-spring-boot-starter. So because this is an AI project, they created something differently?

What is auto-configuration?

In the starter dependences above, you’ll observe a key component known as spring-ai-auto-configuration. But what exactly does this?

Auto-configuration in Spring Boot is a feature that automatically configures the Spring application context based on the dependencies present in the classpath. It aims to minimize the amount of boilerplate code and configuration that developers need to write by providing sensible defaults and configurations for common use cases. Auto-configuration follows the principle of Convention Over Configuration to make things easier and quicker to set up a new spring application. It eliminates the need for explicit configuration by providing default settings based on common scenarios.

What does this mean again? :(

Let’s delve into the spring-ai-auto-configuration module and examine its contents.

Navigate to OpenAiAutoConfiguration. Eh wait, how can I know that I need to go to OpenAiAutoConfiguration? Where does the information come from?

Open the auto-configuration dependency in IntelliJ, navigate through the packages, and inspect each one. Look for a class with a name following the pattern “xxxAutoConfiguration,” where “xxx” corresponds to the module you are interested in. In this case, you should search for something like “OpenAiAutoConfiguration” within the packages of the auto-configuration dependency.

These are a few lines of code in the class

@AutoConfiguration
@ConditionalOnClass(OpenAiService.class)
@EnableConfigurationProperties(OpenAiProperties.class)
@ImportRuntimeHints(NativeHints.class)
public class OpenAiAutoConfiguration {

@Bean
@ConditionalOnMissingBean
public OpenAiClient openAiClient(OpenAiProperties openAiProperties) {

OpenAiService openAiService = theoOpenAiService(openAiProperties, openAiProperties.getBaseUrl(),
openAiProperties.getApiKey(), openAiProperties.getDuration());

OpenAiClient openAiClient = new OpenAiClient(openAiService);
openAiClient.setTemperature(openAiProperties.getTemperature());
openAiClient.setModel(openAiProperties.getModel());

return openAiClient;
}
...
}

There are some interesting annotations:

  • @AutoConfiguration: This annotation is just a special annotation @Congiguration with the exception that Configuration#proxyBeanMethods() is always false. It is equivalent to @Configuration(proxyBeanMethods = false). Setting proxyBeanMethods = false on configuration will avoid proxy instances for configuration instances to make the startup time of the application faster. Learn more about proxyBeanMethods https://www.danvega.dev/blog/spring-proxy-bean-methods
  • @ConditionalOnClass(OpenAiService.class): This is an annotation that you may be interested in. It tells spring context that if it sees the OpenAiService in the classpath, the configuration class is applicable. If OpenAiService is not found, the configuration in this class will not be activated

Now look into the bean creation method public OpenAiClient openAiClient(OpenAiProperties openAiProperties)

  • @ConditionalOnMissingBean When the condition for the auto-configuration class is activated, it will create beans that meet the condition as well. This annotation ensures that the openAiClient bean is only created if there is no existing bean of the same type in the context. If there is already a bean of type OpenAiClient, the method will not be called to create a new one.
  • OpenAiProperties openAiProperties has been injected into the bean. The properties instance has been told to be created @EnableConfigurationProperties(OpenAiProperties.class) in the auto-configuration class.

Opening package condition under spring-boot-auto-configure module, you can find all condition classes

There are 2 most popular conditions @ConditionalOnClass and @ConditionalOnProperty. They are commonly used in auto-configuration classes to conditionally enable or disable certain configurations based on the presence of classes or properties.

So, the 2nd question has been answered on how AiClient instance has been created. But wait, 2 auto-configurations have been injected into the project OpenAIAutoConfiguration and AzureOpenAIAutoConfiguration, which one will get created? So auto-configuration has an exclusion feature.

But first, if you include the 2 dependencies and start the application you will get the error:

Description:

Parameter 0 of constructor in com.felix.hellospringai.controller.BasicPromptController required a single bean, but 2 were found:
- azureOpenAiClient: defined by method 'azureOpenAiClient' in class path resource [org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.class]
- openAiClient: defined by method 'openAiClient' in class path resource [org/springframework/ai/autoconfigure/openai/OpenAiAutoConfiguration.class]

Now, take a look at application.yml file

spring:
config:
activate:
on-profile: azure-openai
autoconfigure:
exclude: org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration
ai:
azure:
openai:
api-key: ${AZURE_OPENAI_API_KEY}
endpoint: ${AZURE_OPENAI_ENDPOINT}
model: ${AZURE_OPENAI_MODEL}
---
spring:
config:
activate:
on-profile: openai
autoconfigure:
exclude: org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiAutoConfiguration
ai:
openai:
api-key: ${OPENAI_API_KEY}

There is a property called spring.autoconfigure.exclude to exclude auto-configuration class. In this case, when I started the application with azure-openai profile, it excluded auto-configuration for OpenAI and vise vera.

Configuration properties

The last question I need to answer is how can I know what properties to configure to make Spring AI work. To identify the properties required to configure Spring AI, typically, you can refer to the project reference page from the Spring team. Alternatively, you may explore the configuration property class, such as OpenAIProperties. Eh wait again, how could I know I need to go to the class?

This configuration property is usually inside the auto-configuration package as well.

The class indicated that configuration properties for Azure Open AI have a prefix spring.ai.azure.openai, following apiKey, endpoint, temperature, model, and embeddingModel

Conclusion

The primary objective of this article is to provide you with insights into Spring Boot starters, auto-configuration, and the process of discovering predefined properties within specific modules, using Spring AI as an example. I hope you find it helpful to figure out how to explore further these features in Spring Boot

--

--