How do I use external configuration with Spring?

External configuration means keeping settings such as application names, URLs, ports, feature flags, credentials, or environment-specific values outside your Java code.

Spring supports this mainly through:

  • application.properties
  • application.yml
  • environment variables
  • command-line arguments
  • external property files
  • @Value
  • @ConfigurationProperties

1. Using application.properties

In a Spring or Spring Boot application, you can place configuration in:

src/main/resources/application.properties

Example:

app.name=My Spring App
app.version=1.0.0
app.description=Example application using external configuration

Then inject values with @Value:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class AppProperties {

    @Value("${app.name}")
    private String appName;

    @Value("${app.version}")
    private String appVersion;

    @Value("${app.description}")
    private String appDescription;

    public void printProperties() {
        System.out.println("App Name: " + appName);
        System.out.println("App Version: " + appVersion);
        System.out.println("App Description: " + appDescription);
    }
}

2. Using application.yml

You can also use YAML:

app:
  name: My Spring App
  version: 1.0.0
  description: Example application using external configuration

The same @Value expressions still work:

@Value("${app.name}")
private String appName;

3. Using @PropertySource in non-Boot Spring

If you are using plain Spring with Java configuration, register a property file using @PropertySource:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@ComponentScan("com.example.app")
@PropertySource("classpath:application.properties")
public class AppConfig {
}

Then Spring can resolve values like:

@Value("${app.name}")
private String appName;

If you are using Spring Boot, you usually do not need @PropertySource for application.properties or application.yml. Spring Boot loads them automatically.


4. Recommended Spring Boot Approach: @ConfigurationProperties

For multiple related properties, prefer @ConfigurationProperties over many @Value fields.

Example application.properties:

app.name=My Spring App
app.version=1.0.0
app.description=Example application using external configuration

Create a properties class:

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {

    private String name;
    private String version;
    private String description;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

Then inject it into another bean:

import org.springframework.stereotype.Service;

@Service
public class GreetingService {

    private final AppProperties appProperties;

    public GreetingService(AppProperties appProperties) {
        this.appProperties = appProperties;
    }

    public void printGreeting() {
        System.out.println("Welcome to " + appProperties.getName());
        System.out.println("Version: " + appProperties.getVersion());
        System.out.println(appProperties.getDescription());
    }
}

5. External Files Outside the JAR

You can override configuration from outside the application.

For Spring Boot:

java -jar myapp.jar --spring.config.location=file:/opt/myapp/application.properties

Or include an additional config file:

java -jar myapp.jar --spring.config.additional-location=file:/opt/myapp/

Example external file:

app.name=Production App
app.version=2.0.0
app.description=Running with production configuration

6. Environment Variables

Spring Boot can read environment variables automatically.

For example, this property:

app.name=My Spring App

Can be overridden with:

APP_NAME=Production App

Spring Boot maps environment variable names to property names using relaxed binding:

APP_NAME -> app.name
SERVER_PORT -> server.port
SPRING_DATASOURCE_URL -> spring.datasource.url

7. Command-Line Arguments

You can override properties when starting the application:

java -jar myapp.jar --app.name="Command Line App" --server.port=9090

Command-line arguments usually have high priority and override values from property files.


8. Profiles for Environment-Specific Config

Profiles let you separate configuration by environment.

Common files:

application.properties
application-dev.properties
application-test.properties
application-prod.properties

Example:

# application-prod.properties
app.name=Production App
server.port=8080

Run with a profile:

java -jar myapp.jar --spring.profiles.active=prod

Or set an environment variable:

SPRING_PROFILES_ACTIVE=prod

9. Default Values with @Value

You can provide fallback values:

@Value("${app.name:Default App}")
private String appName;

If app.name is missing, Spring uses "Default App".


10. Common Property Examples

server.port=8081

spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=myuser
spring.datasource.password=secret

logging.level.org.springframework=INFO

app.name=My Spring App
app.version=1.0.0

Summary

Use external configuration like this:

Use case Recommended approach
Simple single value @Value("${property.name}")
Group of related settings @ConfigurationProperties
Spring Boot default config application.properties or application.yml
Plain Spring Java config @PropertySource
Environment-specific config Spring profiles
Production overrides external file, environment variables, or command-line args

For most Spring Boot applications, the usual setup is:

src/main/resources/application.properties

plus a configuration class using:

@ConfigurationProperties(prefix = "app")

This keeps configuration clean, type-safe, and easy to override per environment.

How do I configure Spring using Java configuration?

Spring Java configuration lets you configure your application using Java classes instead of XML.

The main annotations are:

  • @Configuration — marks a class as a Spring configuration class
  • @Bean — declares a Spring bean manually
  • @ComponentScan — tells Spring where to find annotated components
  • @PropertySource — loads external properties
  • @Enable... annotations — enable specific Spring features, such as MVC, transactions, JPA, etc.

1. Create a configuration class

import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
}

@Configuration tells Spring that this class contains bean definitions and application setup.


2. Define beans manually with @Bean

Use @Bean when you want Spring to manage an object that you create yourself.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyService();
    }
}

Spring will create and manage the MyService instance.

By default, the bean name is the method name: myService.


3. Use component scanning

Instead of defining every bean manually, you can let Spring discover classes annotated with:

  • @Component
  • @Service
  • @Repository
  • @Controller
  • @RestController

Example:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.example.app")
public class AppConfig {
}

Then Spring can find beans like this:

import org.springframework.stereotype.Service;

@Service
public class MyService {

    public void doWork() {
        System.out.println("Working...");
    }
}

4. Inject dependencies through constructors

Java configuration works together with dependency injection.

import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {

    public String findNameById(Long id) {
        return "Alice";
    }
}
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public String getUserName(Long id) {
        return userRepository.findNameById(id);
    }
}

If both classes are discovered by component scanning, Spring automatically injects UserRepository into UserService.


5. Bootstrapping Spring manually

For a non-Spring Boot application, you can start the Spring container like this:

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

    public static void main(String[] args) {
        ApplicationContext context =
                new AnnotationConfigApplicationContext(AppConfig.class);

        MyService myService = context.getBean(MyService.class);
        myService.doWork();
    }
}

6. Configure Spring MVC with Java configuration

For Spring MVC, use @EnableWebMvc and implement WebMvcConfigurer.

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
@ComponentScan("com.example.app")
public class WebConfig implements WebMvcConfigurer {
}

Example controller:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello from Spring MVC";
    }
}

7. Load properties

You can load a properties file with @PropertySource.

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig {
}

Then inject values with @Value:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class AppInfo {

    private final String appName;

    public AppInfo(@Value("${app.name}") String appName) {
        this.appName = appName;
    }
}

Example application.properties:

app.name=My Spring App

8. Enable transactions

If you use database transactions, enable them with @EnableTransactionManagement.

import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
public class PersistenceConfig {
}

Then use @Transactional on services:

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class OrderService {

    @Transactional
    public void placeOrder() {
        // database operations
    }
}

Typical setup

A common Java configuration setup looks like this:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@ComponentScan("com.example.app")
@PropertySource("classpath:application.properties")
@EnableTransactionManagement
public class AppConfig {
}

For Spring MVC:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
@ComponentScan("com.example.app")
public class WebConfig implements WebMvcConfigurer {
}

Summary

To configure Spring using Java configuration:

  1. Create a class annotated with @Configuration.
  2. Add @ComponentScan to discover annotated classes.
  3. Use @Bean methods for manually created beans.
  4. Use constructor injection for dependencies.
  5. Add feature-specific annotations such as @EnableWebMvc, @EnableTransactionManagement, or JPA-related configuration as needed.

In most modern Spring applications, Java configuration plus component scanning replaces XML configuration almost entirely.

How do I manage dependencies using Java-based @Configuration classes?

In Spring, managing dependencies and configurations is commonly done using Java-based @Configuration classes. These classes allow you to define the beans and their dependencies programmatically. Here’s a step-by-step guide on how to manage dependencies with @Configuration classes:

1. Use the @Configuration Annotation

Mark your class with the @Configuration annotation. This tells Spring that the class defines one or more beans to be managed by the Spring container.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
    // Define beans here
}

2. Define Beans with the @Bean Annotation

Within the @Configuration class, use the @Bean annotation to define individual beans. Methods annotated with @Bean will produce bean instances that will be managed by the container.

import org.springframework.context.annotation.Bean;

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyService();
    }

    @Bean
    public MyRepository myRepository() {
        return new MyRepository();
    }
}

In this example, MyService and MyRepository will be registered as beans in the Spring context.

3. Inject Dependencies Between Beans

You can inject dependencies by passing other beans as method parameters. Spring resolves these dependencies automatically.

@Configuration
public class AppConfig {

    @Bean
    public MyRepository myRepository() {
        return new MyRepository();
    }

    @Bean
    public MyService myService(MyRepository myRepository) {
        return new MyService(myRepository);
    }
}

Here, MyService depends on MyRepository. Spring automatically resolves myRepository when creating the MyService bean.

4. Use @Primary for Bean Prioritization

If there are multiple beans of the same type, you can use the @Primary annotation to set the default bean to be used during injection.

@Configuration
public class AppConfig {

    @Bean
    @Primary
    public MyRepository mainRepository() {
        return new MyRepository();
    }

    @Bean
    public MyRepository backupRepository() {
        return new MyRepository();
    }
}

5. Use @Qualifier to Avoid Ambiguities

For cases where multiple beans of the same type exist but you don’t want to use the primary one, use the @Qualifier annotation along with the bean name.

@Bean("backupRepository")
public MyRepository createBackupRepository() {
    return new MyRepository();
}

Inject it as follows:

@Autowired
@Qualifier("backupRepository")
private MyRepository myRepository;

6. Leveraging Externalized Properties

You can link beans to properties defined in an application.properties file by using the @Value annotation or @ConfigurationProperties.

Using @Value:

@Configuration
public class AppConfig {

    @Value("${app.service.name}")
    private String serviceName;

    @Bean
    public MyService myService() {
        return new MyService(serviceName);
    }
}

7. Advance to Component Scanning (@Component)

Instead of manually defining @Bean methods, use annotations like @Component, @Service, @Repository, and @Controller for automatic bean detection, combined with @ComponentScan in the configuration. For example:

@Component
public class MyService {
    // Automatically registered
}

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
    // Automatically scans for annotated beans in the package
}

8. Conditional Bean Creation

Use annotations like @Conditional, @ConditionalOnProperty, or profiles (@Profile) to conditionally create beans based on environment or other properties.

By using @Configuration classes, you retain full control of your beans programmatically while keeping your project modular and easier to maintain.


Maven Dependencies

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>6.2.6</version>
</dependency>

Maven Central

How do I create my first Spring bean using XML configuration?

Creating your first Spring bean using XML configuration is a straightforward process. Here’s a step-by-step guide:


1. Add Spring Framework to Your Project

Make sure you have Spring dependencies added to your project. If you’re using Maven, include the following dependencies in your pom.xml:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>6.2.6</version> <!-- Update to a stable version -->
</dependency>

2. Create the Bean Class

Create a simple Java class that will serve as your Spring bean. For example:

HelloWorld.java

package com.example;

public class HelloWorld {
    private String message;

    public void setMessage(String message) { // Setter method for dependency injection
        this.message = message;
    }

    public void getMessage() {
        System.out.println("Your Message: " + message);
    }
}

3. Create the Spring XML Configuration File

Define the bean in an XML configuration file. Commonly, the file is named applicationContext.xml.

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- Definition of the HelloWorld bean -->
    <bean id="helloWorld" class="org.kodejava.spring.HelloWorld">
        <property name="message" value="Hello, Spring!"/>
    </bean>

</beans>

Here’s what’s happening:

  • id="helloWorld" specifies the name of the bean.
  • class="org.kodejava.spring.HelloWorld" points to the bean’s class.
  • The <property> tag is used to inject the value for the message property of the HelloWorld class.

4. Create the Main Class to Load the Bean

Write a Main class to load the Spring context and retrieve the bean:

MainApp.java

package org.kodejava.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        // Load the Spring configuration file
        ApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext.xml");

        // Retrieve the bean from the Spring container
        HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");

        // Call bean method
        helloWorld.getMessage();
    }
}

5. Run the Application

When you run the MainApp class, you should see the output:

Your Message: Hello, Spring!

Key Points to Remember:

  • XML-based configuration is one of the older ways to configure Spring beans and is still supported, but newer versions prefer Java-based or annotation-based configuration.
  • Ensure the applicationContext.xml file is in the classpath (e.g., under src/main/resources).

That’s it! You’ve successfully created your first Spring bean using XML configuration.

How do I compile and execute a JDK preview features with Maven?

To compile and execute a JDK preview features with Maven, you need to add in the following configurations in your pom.xml file:

  • Compiler Plugin: The configuration should specify the JDK version and enable the preview features. It should look similar to this:
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <release>21</release>
                <compilerArgs>--enable-preview</compilerArgs>
            </configuration>
        </plugin>
    </plugins>
</build>
  • Surefire Plugin: If you’re using the Maven Surefire Plugin to run your tests, you should also enable the preview features there. The configuration may look similar to this:
<build>
    <plugins>
    ...
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.22.2</version>
            <configuration>
                <argLine>--enable-preview</argLine>
            </configuration>
        </plugin>
    </plugins>
</build>

Before building your project, ensure that you have JDK 21-preview installed on your computer, and it’s properly set in JAVA_HOME environment variable or in the IDE settings.

Then use Maven to package or install your project:

mvn clean package
# or
mvn clean install

Please ensure that you have the correct version of maven-compiler-plugin and maven-surefire-plugin that support the JDK 21-preview features. For the project that uses Spring MVC, you should make sure all dependencies are compatible with JDK 21-preview as well.