是否可以使 Spring @Import 或 @Configuration 参数化?
Is it possible to make Spring @Import or @Configuration parametrized?
我创建了很多常见的小型 bean 定义容器 (@Configuration
),我用它们来快速开发应用程序 Spring Boot like:
@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 ...
例如,其中一个 @Configuration
可以使用 Web 控制器为区域设置 cookie 设置会话存储以切换到所选语言等。
使用和重用它们非常有趣,但如果能将其参数化,这将允许更多重用,这真的很棒。我的意思是:
伪代码:
@Imports( imports = {
@FreemarkerViewResolver( escapeHtml = true, autoIncludeSpringMacros = true),
@ConfigurationFromProperties( path = "conf/configuration.properties" ),
@ContentTypeResponse( encoding = "UTF-8" ),
@LocaleResolver( switchLocaleUrl = "/locale/{loc}", defaultLocale = "en"
})
所以,我的意思基本上是 "configurable @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}");
}
让我引用 Spring Boot Reference Guide - Externalized Configuration:
"Spring Boot allows you to externalize your configuration so you can work with the same application code in different environments."
在我看来,定制不是像在第二个伪代码块中那样通过注释参数在导入时完成的,而是定制发生在 运行 时间,例如在配置 classes 中。让我调整你的第三个代码块(只有一个功能):
@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);
}
对于LocaleResolverConfigurator
,配置是从环境中读取的,定义了有意义的默认值。通过以任何支持的方式(在第一个 link 中记录)为配置参数提供不同的值,可以很容易地更改默认值 - 通过命令行或 yaml 文件。与注释参数相比的优势在于您可以在 运行 时间而不是编译时间更改行为。
您还可以注入配置参数(如果您更喜欢将它们作为实例变量)或使用许多其他条件,例如@ConditionalOnMissingBean
, @ConditionalOnClass
, @ConditionalOnExpression
and so on。例如,对于 @ConditionalOnClass
,您可以检查特定的 class 是否在您的 class 路径上,并为由该 class 标识的库提供设置。使用 @ConditionalOnMissingClass
您可以提供替代实现。在上面的示例中,我使用 ConditionalOnMissingBean
为 FreeMarkerConfigurer
提供默认实现。此实现仅在没有 FreeMarkerConfigurer
bean 可用时使用,因此可以轻松覆盖。
看看 Spring Boot 或社区提供的启动器。 blog entry. I learned a lot from spring-boot-starter-batch-web, they had an article series in a German Java magazine, but parts are also online, see Boot your own infrastructure – Extending Spring Boot in five steps(必读)也值得一读,尤其是 "Make your starter configurable by using properties".
段
虽然我喜欢将导入参数化的想法,但我认为现在使用 @Import
和 @Configuration
不太合适。
我可以想到两种使用动态配置的方法,它们不依赖于 PropertySource
样式配置。
- 创建自定义
@ImportConfig
注释和注释处理器,它接受硬编码到生成的源文件中的配置属性。
- 使用
BeanFactoryPostProcessor
或 BeanPostProcessor
分别添加或操作包含的 bean。
IMO 都不是特别简单,但看起来你有一种特殊的工作方式。所以值得投入时间。
我创建了很多常见的小型 bean 定义容器 (@Configuration
),我用它们来快速开发应用程序 Spring Boot like:
@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 ...
例如,其中一个 @Configuration
可以使用 Web 控制器为区域设置 cookie 设置会话存储以切换到所选语言等。
使用和重用它们非常有趣,但如果能将其参数化,这将允许更多重用,这真的很棒。我的意思是:
伪代码:
@Imports( imports = {
@FreemarkerViewResolver( escapeHtml = true, autoIncludeSpringMacros = true),
@ConfigurationFromProperties( path = "conf/configuration.properties" ),
@ContentTypeResponse( encoding = "UTF-8" ),
@LocaleResolver( switchLocaleUrl = "/locale/{loc}", defaultLocale = "en"
})
所以,我的意思基本上是 "configurable @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}");
}
让我引用 Spring Boot Reference Guide - Externalized Configuration:
"Spring Boot allows you to externalize your configuration so you can work with the same application code in different environments."
在我看来,定制不是像在第二个伪代码块中那样通过注释参数在导入时完成的,而是定制发生在 运行 时间,例如在配置 classes 中。让我调整你的第三个代码块(只有一个功能):
@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);
}
对于LocaleResolverConfigurator
,配置是从环境中读取的,定义了有意义的默认值。通过以任何支持的方式(在第一个 link 中记录)为配置参数提供不同的值,可以很容易地更改默认值 - 通过命令行或 yaml 文件。与注释参数相比的优势在于您可以在 运行 时间而不是编译时间更改行为。
您还可以注入配置参数(如果您更喜欢将它们作为实例变量)或使用许多其他条件,例如@ConditionalOnMissingBean
, @ConditionalOnClass
, @ConditionalOnExpression
and so on。例如,对于 @ConditionalOnClass
,您可以检查特定的 class 是否在您的 class 路径上,并为由该 class 标识的库提供设置。使用 @ConditionalOnMissingClass
您可以提供替代实现。在上面的示例中,我使用 ConditionalOnMissingBean
为 FreeMarkerConfigurer
提供默认实现。此实现仅在没有 FreeMarkerConfigurer
bean 可用时使用,因此可以轻松覆盖。
看看 Spring Boot 或社区提供的启动器。 blog entry. I learned a lot from spring-boot-starter-batch-web, they had an article series in a German Java magazine, but parts are also online, see Boot your own infrastructure – Extending Spring Boot in five steps(必读)也值得一读,尤其是 "Make your starter configurable by using properties".
段虽然我喜欢将导入参数化的想法,但我认为现在使用 @Import
和 @Configuration
不太合适。
我可以想到两种使用动态配置的方法,它们不依赖于 PropertySource
样式配置。
- 创建自定义
@ImportConfig
注释和注释处理器,它接受硬编码到生成的源文件中的配置属性。 - 使用
BeanFactoryPostProcessor
或BeanPostProcessor
分别添加或操作包含的 bean。
IMO 都不是特别简单,但看起来你有一种特殊的工作方式。所以值得投入时间。