Spring中如何引用Record类型配置Bean或自定义其Bean名称?
优雅解决@ConfigurationProperties Record的Bean名称与SpEL引用问题
问题场景
在Spring Boot中,通过@ConfigurationProperties(prefix = "apns")将配置读取到如下Record类:
package foo.bar.baz; @ConfigurationProperties(prefix = "apns") public record ApnsConfiguration( Duration gracefulShutdownTimeout, int maxAttempts, Duration minDelay, Duration maxDelay, List<ApnsEndpoint> endpoints ) {}
该Bean可正常使用,但在使用@Retryable注解时,尝试用SpEL引用其属性(如#{@apnsConfiguration.maxAttempts})报错,提示找不到apnsConfiguration Bean。实际打印Bean名称发现该Record对应的Bean名为baz-foo.bar.baz.ApnsConfiguration,直接写带连字符的名称会被SpEL解析为减法操作,只能用丑陋的转义写法#{(@'baz-foo.bar.baz.ApnsConfiguration').maxAttempts},需要更优雅的解决方案。
解决方案
方案1:显式指定自定义Bean名称(推荐)
创建一个配置类,显式声明ApnsConfiguration的Bean并指定自定义名称:
@Configuration public class ApnsBeanConfig { @Bean("apnsConfiguration") // 指定自定义Bean名称 @ConfigurationProperties(prefix = "apns") public ApnsConfiguration apnsConfiguration() { return new ApnsConfiguration(); } }
之后@Retryable的SpEL即可使用简洁的写法:
@Retryable( retryFor = RetryableException.class, maxAttemptsExpression = "#{@apnsConfiguration.maxAttempts}", backoff = @Backoff( delayExpression = "#{@apnsConfiguration.minDelay.toMillis}", maxDelayExpression = "#{@apnsConfiguration.maxDelay.toMillis}", multiplier = BACKOFF_MULTIPLIER) )
这种方式清晰直观,彻底避免了自动生成的复杂Bean名称问题。
方案2:通过类型直接引用Bean(无需修改Bean定义)
若不想新增配置类,可在SpEL中通过类型直接获取Bean,无需依赖自动生成的Bean名称:
@Retryable( retryFor = RetryableException.class, maxAttemptsExpression = "#{@beanFactory.getBean(T(foo.bar.baz.ApnsConfiguration)).maxAttempts}", backoff = @Backoff( delayExpression = "#{@beanFactory.getBean(T(foo.bar.baz.ApnsConfiguration)).minDelay.toMillis}", maxDelayExpression = "#{@beanFactory.getBean(T(foo.bar.baz.ApnsConfiguration)).maxDelay.toMillis}", multiplier = BACKOFF_MULTIPLIER) )
利用beanFactory的getBean方法通过类型定位Bean,跳过了复杂的Bean名称解析步骤,写法更简洁。
内容的提问来源于stack exchange,提问作者QuantumMechanic
相关产品推荐
相关产品推荐

