You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于配置文件动态创建Spring Bean并注入至其他Bean?

Hey there! Let's break down how to dynamically create Spring Beans from both .properties and application.yaml files, then inject them with @Autowired—I'll walk you through practical, actionable examples so you can implement this easily.


1. 基于.properties文件动态创建Bean并注入

Let's start with a common scenario: you have configuration values in a .properties file, and you want to turn those into Spring Beans that can be injected anywhere in your app.

1.1 Step 1: Bind Properties to a Configuration Class

First, define a class to hold your configuration values using @ConfigurationProperties. This lets Spring automatically map your .properties entries to object fields.

Suppose your app.properties looks like this:

# Single bean configuration
app.payment-service.api-key=sk_test_123
app.payment-service.timeout=3000

# Multiple beans (a list of users)
app.users[0].id=1
app.users[0].name=Alice
app.users[1].id=2
app.users[1].name=Bob

Create a corresponding configuration class:

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;

@Data
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
    // For single bean
    private PaymentServiceProperties paymentService;
    // For multiple beans
    private List<User> users;

    @Data
    public static class PaymentServiceProperties {
        private String apiKey;
        private int timeout;
    }

    @Data
    public static class User {
        private int id;
        private String name;
    }
}

Note: Don't forget to add spring-boot-configuration-processor as a dependency if you want IDE support for your properties.

1.2 Step 2: Dynamically Register Beans

You have two main approaches here—choose based on your use case:

Option A: Simple @Bean Method (For Fixed/Predefined Beans)

If you know the type of Bean you want to create upfront, use a @Configuration class to define Beans using the bound properties:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;

@Configuration
public class BeanConfig {

    private final ApplicationContext applicationContext;

    public BeanConfig(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    // Create a single PaymentService Bean from properties
    @Bean
    public PaymentService paymentService(AppProperties appProperties) {
        AppProperties.PaymentServiceProperties props = appProperties.getPaymentService();
        return new PaymentService(props.getApiKey(), props.getTimeout());
    }

    // Register each User from the list as a separate Bean
    public void registerUserBeans(AppProperties appProperties) {
        List<User> users = appProperties.getUsers();
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
        
        users.forEach(user -> {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
            builder.addPropertyValue("id", user.getId());
            builder.addPropertyValue("name", user.getName());
            // Register with unique Bean name
            registry.registerBeanDefinition("user-" + user.getId(), builder.getBeanDefinition());
        });
    }
}

Option B: Dynamic Registration with BeanDefinitionRegistryPostProcessor

For more flexibility (e.g., creating beans based on arbitrary property keys), implement BeanDefinitionRegistryPostProcessor to register beans directly with Spring's registry:

import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

@Component
public class DynamicBeanRegistrar implements BeanDefinitionRegistryPostProcessor {

    private final Environment environment;

    public DynamicBeanRegistrar(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void postProcessBeanDefinitionRegistry(org.springframework.beans.factory.support.BeanDefinitionRegistry registry) {
        // Read user count dynamically from properties
        int userCount = Integer.parseInt(environment.getProperty("app.user-count", "0"));
        
        for (int i = 0; i < userCount; i++) {
            String userId = environment.getProperty("app.users[" + i + "].id");
            String userName = environment.getProperty("app.users[" + i + "].name");
            
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
            builder.addPropertyValue("id", userId);
            builder.addPropertyValue("name", userName);
            
            // Register Bean with unique name
            registry.registerBeanDefinition("dynamicUser-" + i, builder.getBeanDefinition());
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Empty implementation for this use case
    }
}

1.3 Step 3: Inject and Use the Beans

Now you can inject these beans anywhere using @Autowired:

import org.springframework.stereotype.Service;
import java.util.List;
import org.springframework.beans.factory.annotation.Qualifier;

@Service
public class UserService {

    // Inject single bean
    @Autowired
    private PaymentService paymentService;

    // Inject all User beans (Spring collects all beans of type User)
    @Autowired
    private List<User> allUsers;

    // Inject a specific User bean using @Qualifier
    @Autowired
    @Qualifier("user-1")
    private User alice;

    // Use the beans in your logic
    public void printUsers() {
        allUsers.forEach(user -> System.out.println("User: " + user.getName()));
    }
}

2. 基于application.yaml文件动态创建Bean并注入

Good news: most of the process is identical to .properties files! Spring's Environment abstraction handles both formats uniformly—only the configuration file syntax changes.

2.1 Step 1: Define Your YAML Configuration

Here's the equivalent of the earlier .properties file in application.yaml:

app:
  payment-service:
    api-key: sk_test_123
    timeout: 3000
  users:
    - id: 1
      name: Alice
    - id: 2
      name: Bob

2.2 Step 2: Reuse the Configuration Class & Bean Registration

The AppProperties class we created earlier works exactly the same for YAML—no changes needed. Similarly, the @Configuration class or BeanDefinitionRegistryPostProcessor implementations will function identically, since they read from the Spring Environment (not directly from the file).

2.3 Step 3: Inject and Use (Same as Properties)

You can inject the beans the same way as before—Spring doesn't care if the config came from YAML or properties.


Key Notes to Remember
  • Enable Configuration Properties: If you don't use @Component on your @ConfigurationProperties class, add @EnableConfigurationProperties(AppProperties.class) to your main application class or a @Configuration class.
  • Bean Names: Always use unique names when registering dynamic beans to avoid conflicts. Use @Qualifier to specify which bean to inject if you have multiple beans of the same type.
  • Validation: Add @Validated to your configuration class and JSR-380 annotations (like @NotBlank, @Min) to validate your properties at startup.

内容的提问来源于stack exchange,提问作者Harsh Yadav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 14:32:47