【问题标题】:SpringFramework: set bean name programmaticallySpringFramework:以编程方式设置 bean 名称
【发布时间】:2016-08-05 20:35:14
【问题描述】:

对于基于springframwork的应用,在使用xml声明bean时,可以通过传递唯一值甚至参数来配置bean id,然后在运行时解析该值。

现在我希望将所有xml配置替换为java注解。

假设我想创建两个具有不同 id 的数据库 bean。

bean.xml
<bean id="A.database" class="org.apache.commons.dbcp.BasicDataSource">
    <!-- collaborators and configuration for this bean go here -->
</bean>   

<bean id="B.database" class="org.apache.commons.dbcp.BasicDataSource">
    <!-- collaborators and configuration for this bean go here -->
</bean> 

然后我将上层代码优化为一个bean,两个属性文件用于两个应用程序

bean.xml
<bean id="${appName.database}"   class="org.apache.commons.dbcp.BasicDataSource">
    <!-- collaborators and configuration for this bean go here -->
</bean> 

applicationA.properties    
appName.database=A.database

applicationB.properties
appName.database=B.database

整个应用程序由“框架”模块组成,它为每个应用程序提供通用的bean,如数据库bean、jdbcTemplate bean,以及为占位符提供属性值并用唯一ID初始化bean的“应用程序”模块。所以即使我同时启动多个应用程序,它们也会从上下文中找到对应的bean。

总的来说,我希望这样做

@Bean(name = "${beanName}")
public ABean getBean() {}

并在应用程序级别解析 ${beanName}。

【问题讨论】:

    标签: java spring


    【解决方案1】:

    通过阅读SpringFramwork文档,我找到了答案:BeanNameGenerator

    NameGenerator.class

    public class NameGenerator implements BeanNameGenerator{
    
    @Override
    public String generateBeanName(BeanDefinition definition,
            BeanDefinitionRegistry registry) {
        if(definition.getBeanClassName().contains("Toto")) {
            return "toto";
        }
        return return definition.getBeanClassName();
        }
    }
    

    AppConfiguration.class

    @Configuration
    @ComponentScan(basePackages = {"com.example.domain"}, nameGenerator = NameGenerator.class)
    public class Config {
    }
    

    带有@Component 的域类

    @Component
    public class Toto {
        private int id;
    }
    

    使用域名 bean 名称启动应用程序:toto

    @SpringBootApplication
    public class DemoApplication {
    
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(
                DemoApplication.class, args);
        for (String name : ctx.getBeanNamesForType(Toto.class)) {
            System.out.println(name);
        }
    }
    }
    

    【讨论】:

    • 这似乎是您问题中所述问题的合适解决方案。但是,我的感觉是问题本身需要重新考虑。
    • @CostiCiudatu 说实话,我同意你的看法。但我不是可以做出决定的负责人,这只是许多不标准的无聊概念之一,这些解决方案也不是。这就是我离开这家公司的原因。但从另一方面来说,我很高兴知道弹簧的这个功能,尽管这并不是真的有用。我学会了仔细阅读文件。所以,还不错。
    • 是否可以根据属性返回beanName。我想让它由属性驱动,而不是硬编码为“toto”。
    【解决方案2】:

    如果您想遵循这种方法,请创建多个配置类,并使用不同的 Spring profiles 进行注释。

    在启动时,您可以传递一个参数来指定要使用的配置文件,从而在相关配置文件中加载哪些 bean。

    一种更有效的方法是在所有应用程序 .properties 文件中使用相同的属性命名约定。为文件名设置一个参数占位符,该文件名解析为在运行时传递的 JVM 参数,该参数由@PropertySource 注释加载。

    如果只是属性发生变化,则无需为不同的环境定义重复的 bean。

    【讨论】:

    • 嗨,我了解您的解决方案,并且在不同的应用程序上下文中修改 同名 bean 的 属性 非常有效。但是我想要实现的是给不同的bean id**/**bean name,这往往是由bean的方法名或者bean的name值决定的。
    • 您是否发现为相同的 bean 设置方法使用不同的 bean 名称,只是具有不同的属性可能效率低下?
    • 好吧,这不是我能决定和改变的。事实上,所有应用程序都在 Liferay 上下文中运行,这就是为什么会有多个具有不同 id 和属性的 bean 的原因,因为会有多个应用程序需要相同的 bean,例如数据源 bean 等。这就是为什么我需要不同的 id 来传递不同的属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-15
    • 2014-01-17
    • 2011-11-20
    相关资源
    最近更新 更多