Skip to content

Conversation

nerdroid-dev
Copy link

Description

While migrating our gateway service from spring-cloud-gateway-server-webflux to spring-cloud-gateway-server-webmvc, I discovered a limitation in how operation methods are currently invoked in spring-cloud-gateway-server-webmvc

In spring-cloud-gateway-server-webflux, it is possible to rely on spring bean lifecycle for dependency injection and to compose logic in a typical spring-oriented manner. However, in spring-cloud-gateway-server-webmvc, RouterFunctionHolderFactory currently never attempts to resolve an invocation target when passing an OperationMethod to ReflectiveOperationInvoker. As a result, methods defined as instance methods within a spring bean cannot be used as operation methods — only static methods are currently supported.

In my opinion, given that this project is part of the spring cloud gateway family, it seems natural to support resolving a bean instance from the application context when the declaring type of an OperationMethod is registered as a bean. This behavior would align with spring’s general design philosophy, allowing bean-managed components to participate in operation method invocation without requiring them to be static.

The proposed change introduces a small enhancement to RouterFunctionHolderFactory, enabling resolution of a bean instance from the BeanFactory when invoking non-static OperationMethods. If the declaring type is not registered as a bean or multiple candidates are found, the invocation gracefully falls back to the existing reflective behavior — ensuring full backward compatibility.

Use Case Example

@Component
class SampleGatewayNameFilter(
    private val sampleGatewayNameService: SampleGatewayNameService
) : SimpleFilterSupplier(SampleGatewayNameFilter::class.java) {

    companion object {
        private const val X_SAMPLE_GW_APP_NAME = "X-SAMPLE-GW-NAME"
    }

    data class Config(
        val prefixes: List<String>
    )

    @Configurable
    fun addGatewayName(config: Config): HandlerFilterFunction<ServerResponse, ServerResponse> {
        return FilterFunctions.addRequestHeader(
            X_SAMPLE_GW_APP_NAME,
            "${config.prefixes.joinToString("-")}-${sampleGatewayNameService.getGatewayName()}"
        )
    }
}

@Service
class SampleGatewayNameService(
    @Value("\${spring.application.name}")
    private val appName: String
) {
    fun getGatewayName(): String = appName
}

Copy link
Member

@spencergibb spencergibb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a test that verifies the functionality

@nerdroid-dev
Copy link
Author

Please add a test that verifies the functionality

Sure! I will soon

Signed-off-by: nerdroid <nerdroid@outlook.kr>
Signed-off-by: YeonHo Ju <nerdroid@outlook.kr>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants