如何为 @Query 设置 SpEL contextProvider
How to setup SpEL contextProvider for @Query
如何设置上下文提供程序以使我的 SpEL 扩展在 @Query("...")
中可用?
我们在 postgres 中使用 r2dbc。
据我所知,我需要使用 ReactiveExtensionAwareQueryMethodEvaluationContextProvider
注册我的扩展程序,但我找不到任何关于如何执行此操作的文档。是否有特定的 bean 或 @Configuration
可用于它?
我找到了this unit test。它是 monogo 而不是 r2dbc,但我认为它是相同的原理 - 但是因为它是一个单元测试,所以它没有显示如何在我的正常代码中设置上下文。
试图像这样实现它并没有在 SpEL
中提供 my()
方法
@Configuration
class MySpELExtensionConf {
@Bean
fun mySpELExtension() : ReactiveEvaluationContextExtension {
return ReactiveSpelExtension()
}
class ReactiveSpelExtension : ReactiveEvaluationContextExtension {
override fun getExtension(): Mono<out EvaluationContextExtension> {
return Mono.just(SpelExtension.INSTANCE)
}
override fun getExtensionId(): String {
ReactiveQueryMethodEvaluationContextProvider.DEFAULT
return "mySpELExtension"
}
}
enum class SpelExtension : EvaluationContextExtension {
INSTANCE;
override fun getRootObject(): Any? {
return this
}
override fun getExtensionId(): String {
return "mySpELExtension"
}
fun my(): String {
return "x"
}
}
}
我现在在应用程序上下文中看到 mySpELExtension
,但是无法在 @Query
中使用 my()
方法:
interface MyRepository : ReactiveCrudRepository<MyEntity, Long> {
@Query("""
...
:#{my()}
...
""")
fun findByMyQuery() : Flux<MyEntity>
}
结果
EL1004E: Method call: Method my() cannot be found on type java.lang.Object[]
我找到了使用 PostBeanProcessor
的解决方案。
@Configuration
class MySpELExtensionConf {
companion object {
// list of provided extensions
val contextProviderWithExtensions =
ReactiveExtensionAwareQueryMethodEvaluationContextProvider(listOf(ReactiveSpelExtension()))
}
/**
* Registers the customizer to the context to make spring aware of the bean post processor.
*/
@Bean
fun spELContextInRepositoriesCustomizer(): AddExtensionsToRepositoryBeanPostProcessor {
return AddExtensionsToRepositoryBeanPostProcessor()
}
/**
* Sets the [contextProviderWithExtensions] for SpEL in the [R2dbcRepositoryFactoryBean]s which makes the extensions
* usable in `@Query(...)` methods.
*/
class AddExtensionsToRepositoryBeanPostProcessor : BeanPostProcessor {
override fun postProcessBeforeInitialization(bean: Any, beanName: String): Any {
if (bean is R2dbcRepositoryFactoryBean<*, *, *>) {
bean.addRepositoryFactoryCustomizer { it.setEvaluationContextProvider(contextProviderWithExtensions) }
}
return bean
}
}
// ... extension implementation as in question ...
}
请注意,自定义 R2dbcRepositoryFactoryBean
适用于 CoroutineCrudRepository
,您可能需要根据您使用的存储库自定义不同的工厂 bean。
如何设置上下文提供程序以使我的 SpEL 扩展在 @Query("...")
中可用?
我们在 postgres 中使用 r2dbc。
据我所知,我需要使用 ReactiveExtensionAwareQueryMethodEvaluationContextProvider
注册我的扩展程序,但我找不到任何关于如何执行此操作的文档。是否有特定的 bean 或 @Configuration
可用于它?
我找到了this unit test。它是 monogo 而不是 r2dbc,但我认为它是相同的原理 - 但是因为它是一个单元测试,所以它没有显示如何在我的正常代码中设置上下文。
试图像这样实现它并没有在 SpEL
中提供my()
方法
@Configuration
class MySpELExtensionConf {
@Bean
fun mySpELExtension() : ReactiveEvaluationContextExtension {
return ReactiveSpelExtension()
}
class ReactiveSpelExtension : ReactiveEvaluationContextExtension {
override fun getExtension(): Mono<out EvaluationContextExtension> {
return Mono.just(SpelExtension.INSTANCE)
}
override fun getExtensionId(): String {
ReactiveQueryMethodEvaluationContextProvider.DEFAULT
return "mySpELExtension"
}
}
enum class SpelExtension : EvaluationContextExtension {
INSTANCE;
override fun getRootObject(): Any? {
return this
}
override fun getExtensionId(): String {
return "mySpELExtension"
}
fun my(): String {
return "x"
}
}
}
我现在在应用程序上下文中看到 mySpELExtension
,但是无法在 @Query
中使用 my()
方法:
interface MyRepository : ReactiveCrudRepository<MyEntity, Long> {
@Query("""
...
:#{my()}
...
""")
fun findByMyQuery() : Flux<MyEntity>
}
结果
EL1004E: Method call: Method my() cannot be found on type java.lang.Object[]
我找到了使用 PostBeanProcessor
的解决方案。
@Configuration
class MySpELExtensionConf {
companion object {
// list of provided extensions
val contextProviderWithExtensions =
ReactiveExtensionAwareQueryMethodEvaluationContextProvider(listOf(ReactiveSpelExtension()))
}
/**
* Registers the customizer to the context to make spring aware of the bean post processor.
*/
@Bean
fun spELContextInRepositoriesCustomizer(): AddExtensionsToRepositoryBeanPostProcessor {
return AddExtensionsToRepositoryBeanPostProcessor()
}
/**
* Sets the [contextProviderWithExtensions] for SpEL in the [R2dbcRepositoryFactoryBean]s which makes the extensions
* usable in `@Query(...)` methods.
*/
class AddExtensionsToRepositoryBeanPostProcessor : BeanPostProcessor {
override fun postProcessBeforeInitialization(bean: Any, beanName: String): Any {
if (bean is R2dbcRepositoryFactoryBean<*, *, *>) {
bean.addRepositoryFactoryCustomizer { it.setEvaluationContextProvider(contextProviderWithExtensions) }
}
return bean
}
}
// ... extension implementation as in question ...
}
请注意,自定义 R2dbcRepositoryFactoryBean
适用于 CoroutineCrudRepository
,您可能需要根据您使用的存储库自定义不同的工厂 bean。