是否有可能使Spring@Import或@Configuration参数化?

我已经创建了很多常见的小bean定义容器(),我用它们来快速开发带有Spring Boot的应用程序,例如:@Configuration

@Import({
   FreemarkerViewResolver.class, // registers freemarker that auto appends <#escape etc.
   ConfigurationFromPropertiesFile.class, // loads conf/configuration.properties
   UtfContentTypeResponse.class, // sets proper Content-language and Content-type
   LocaleResolverWithLanguageSwitchController // Locale resolver + switch controller
 );
 class MySpringBootApp ...

例如,其中一个可以使用Web控制器为区域设置cookie的会话存储,以切换到所选语言等。@Configuration

使用它们和重用非常有趣,但是将其参数化真的很棒,这可以允许更多的重用。我的意思是这样的:

伪代码

@Imports( imports = {
  @FreemarkerViewResolver( escapeHtml = true, autoIncludeSpringMacros = true),
  @ConfigurationFromProperties( path = "conf/configuration.properties" ),
  @ContentTypeResponse( encoding = "UTF-8" ),
  @LocaleResolver( switchLocaleUrl = "/locale/{loc}", defaultLocale = "en"
})

所以,我基本上意味着“可配置”。以这种方式进行配置的最佳方法是什么?@Configurations

也许更像这样的东西(再次,伪代码):

@Configuration
public class MyAppConfiguration {

    @Configuration
    public FreemarkerConfiguration freemarkerConfiguration() {
       return FreemarkerConfigurationBuilder.withEscpeAutoAppend();
    }

    @Configuration
    public ConfigurationFromPropertiesFile conf() {
       return ConfigurationFromPropertiesFile.fromPath("...");
    }

    @Configuration
    public LocaleResolverConfigurator loc() {
       return LocaleResolverConfigurator.trackedInCookie().withDefaultLocale("en").withSwitchUrl("/switchlocale/{loc}");
    }

答案 1

让我引用弹簧靴参考指南 - 外部化配置

“Spring Boot 允许您将配置外部化,以便您可以在不同的环境中使用相同的应用程序代码。

在我看来,自定义不是在导入时通过注释参数完成的,就像在第二个伪代码块中一样,而是在运行时进行自定义,例如在配置类中。让我调整你的第三个代码块(只有一个函数):

@Configuration
public class MyAppConfiguration {

    @Autowired
    private Environment env;

    // Provide a default implementation for FreeMarkerConfigurer only
    // if the user of our config doesn't define her own configurer.
    @Bean
    @ConditionalOnMissingBean(FreeMarkerConfigurer.class)
    public FreeMarkerConfigurer freemarkerConfig() {
        FreeMarkerConfigurer result = new FreeMarkerConfigurer();
        result.setTemplateLoaderPath("/WEB-INF/views/");
        return result;
    }

    ...

    @Bean
    public LocaleResolverConfigurator loc() {
        String defaultLocale = env.getProperty("my.app.config.defaultlocale", "en");
        String switchLocale = env.getProperty("my.app.config.switchlocale", "/switchlocale/{loc}");

        return LocaleResolverConfigurator.trackedInCookie().withDefaultLocale(defaultLocale).withSwitchUrl(switchLocale);
    }

对于从环境中读取的配置,定义了有意义的默认值。通过任何受支持的方式(记录在第一个链接中)为配置参数提供不同的值(记录在第一个链接中) - 通过命令行或 yaml 文件,可以轻松更改默认值。与注释参数相比,优点是可以在运行时而不是编译时更改行为。LocaleResolverConfigurator

您还可以注入配置参数(如果您希望将它们作为实例变量)或使用许多其他条件,例如@ConditionalOnMissingBean@ConditionalOnClass@ConditionalOnExpression。例如,您可以检查特定类是否在您的类路径上,并为该类标识的库提供设置。您可以提供另一种实现。在上面的示例中,我用于为 .此实现仅在没有可用的 Bean 时使用,因此可以轻松覆盖。@ConditionalOnClass@ConditionalOnMissingClassConditionalOnMissingBeanFreeMarkerConfigurerFreeMarkerConfigurer

看看Spring Boot或社区提供的入门产品。一个很好的阅读也是这个博客条目。我从spring-boot-starter-batch-web中学到了很多东西,他们在德国Java杂志上有一个系列文章,但部分内容也在线,请参阅引导你自己的基础设施 - 在五个步骤中扩展Spring Boot必读),特别是“使用属性使你的启动器可配置”这一段。


答案 2

虽然我喜欢将导入参数化的想法,但我认为现在使用而不是一个好的选择。@Import@Configuration

我可以想到两种使用动态配置的方法,它们不依赖于样式配置。PropertySource

  1. 创建一个自定义注释和注释处理器,该处理器接受硬编码到生成的源文件中的配置属性。@ImportConfig
  2. 分别使用 或 添加或操作包含的 Bean。BeanFactoryPostProcessorBeanPostProcessor

两者都不是特别简单的IMO,但是因为它看起来你有一种特定的工作方式。因此,投入时间可能是值得的。


推荐