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

Spring Boot动态创建相似Bean替代重复代码的可行性及问题排查

Yes, dynamically creating multiple similar beans to replace repetitive @Bean methods is absolutely feasible in Spring—you just need to use the right lifecycle hook to ensure the beans are registered early enough for Spring to pick them up properly.

Why Your Current Approach Isn't Working

Your @PostConstruct attempt registers singletons after the Spring application context has already completed most of its initialization. Specifically, the Spring MVC handler mappings that map PubHessianServiceExporter beans to their URL endpoints would have already scanned the context for these beans before your @PostConstruct method runs. Even though you're registering the beans, they aren't added to the handler mappings, so they don't become accessible via their URLs.

The Correct Approach: Use BeanDefinitionRegistryPostProcessor

To fix this, you should use BeanDefinitionRegistryPostProcessor, which runs before any beans are instantiated. This allows you to register bean definitions dynamically, ensuring they're part of the context from the start and picked up by the handler mappings correctly.

Here's how to implement it:

Step 1: Create the Registry Post Processor

This class will read your sign-sys-ids configuration and register a PubHessianServiceExporter bean for each ID:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;

public class HessianServiceExporterRegistry implements BeanDefinitionRegistryPostProcessor, EnvironmentAware {

    private Environment environment;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // Read the system IDs from configuration
        String[] signSysIds = environment.getProperty("sign-sys-ids", String[].class, new String[]{});
        
        for (String sysId : signSysIds) {
            int id = Integer.parseInt(sysId);
            
            // Build the bean definition for PubHessianServiceExporter
            BeanDefinitionBuilder exporterBuilder = BeanDefinitionBuilder.genericBeanDefinition(PubHessianServiceExporter.class);
            exporterBuilder.addPropertyValue("service", StudentAppServiceFactory.curriculumScheduleServices.get(id));
            exporterBuilder.addPropertyValue("serviceInterface", CurriculumScheduleService.class);
            
            // Register the bean with the URL path as its name (matches your original @Bean naming)
            String beanName = "/svc/curriculumScheduleService/" + sysId;
            registry.registerBeanDefinition(beanName, exporterBuilder.getBeanDefinition());
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // No additional processing needed here
    }
}

Step 2: Register the Post Processor in Your Configuration

Update your HessianFactory configuration to include the post processor bean:

@Configuration
@Order(Integer.MIN_VALUE)
public class HessianFactory {

    @Bean
    public HessianServiceExporterRegistry hessianServiceExporterRegistry() {
        return new HessianServiceExporterRegistry();
    }
}

Step 3: Configure Your System IDs

Make sure your sign-sys-ids property is correctly set in your application configuration (e.g., application.properties):

sign-sys-ids=1,2,3,5

Key Notes

  • Bean Naming: We use the URL path as the bean name, just like your original @Bean methods. This is critical because Spring's default handler mapping for Hessian exporters uses the bean name as the endpoint URL.
  • Lifecycle Timing: BeanDefinitionRegistryPostProcessor runs early, ensuring the bean definitions are present when Spring scans for HessianServiceExporter beans to map to URLs.
  • Dependency Availability: Ensure StudentAppServiceFactory.curriculumScheduleServices is populated before the post processor runs. If this is a static factory, initialize the map before the Spring context starts; if it's a bean, mark it as @DependsOn or ensure it's initialized early.

This approach eliminates the repetitive @Bean methods while maintaining the same functionality as your original code.

内容的提问来源于stack exchange,提问作者lester.liang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:44:34