Skip to content

Commit

Permalink
feat: Support for automatic configuration of scan packages
Browse files Browse the repository at this point in the history
  • Loading branch information
Ahoo-Wang committed Jan 20, 2024
1 parent 8f13e27 commit fdde4a3
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import org.springframework.boot.runApplication
TodoClient::class
]
)
@SpringBootApplication
@SpringBootApplication(scanBasePackages = ["me.ahoo.coapi.example.consumer.client"])
class ConsumerServer

fun main(args: Array<String>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ spring:
- host: localhost
port: 8010
coapi:
base-packages:
- me.ahoo.coapi.example.consumer.client
clients:
ServiceApiClientUseFilterBeanName:
reactive:
Expand All @@ -29,4 +31,4 @@ coapi:
reactive:
filter:
types:
- org.springframework.cloud.client.loadbalancer.reactive.LoadBalancedExchangeFilterFunction
- org.springframework.cloud.client.loadbalancer.reactive.LoadBalancedExchangeFilterFunction
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,45 @@ import me.ahoo.coapi.spring.CoApiDefinition.Companion.toCoApiDefinition
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition
import org.springframework.boot.autoconfigure.AutoConfigurationPackages
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider
import org.springframework.core.env.Environment
import org.springframework.core.type.AnnotationMetadata
import org.springframework.core.type.filter.AnnotationTypeFilter

class AutoCoApiRegistrar : AbstractCoApiRegistrar() {

private fun getCoApiBasePackages(): List<String> {
val basePackages = env.getProperty(CoApiProperties.COAPI_BASE_PACKAGES)
if (basePackages?.isNotBlank() == true) {
return basePackages.split(",").distinct().toList()
}
var currentIndex = 0
buildList {
while (true) {
val basePackage = env.getProperty("${CoApiProperties.COAPI_BASE_PACKAGES}[$currentIndex]")
if (basePackage.isNullOrBlank()) {
return this
}
add(basePackage)
currentIndex++
}
}
}

private fun getScanBasePackages(): List<String> {
val coApiBasePackages = getCoApiBasePackages()
if (coApiBasePackages.isNotEmpty()) {
return coApiBasePackages
}
return AutoConfigurationPackages.get(appContext)
}

override fun getCoApiDefinitions(importingClassMetadata: AnnotationMetadata): Set<CoApiDefinition> {
val scanBasePackages = AutoConfigurationPackages.get(appContext).toSet()
val scanBasePackages = getScanBasePackages()
return scanBasePackages.toApiClientDefinitions()
}

private fun Set<String>.toApiClientDefinitions(): Set<CoApiDefinition> {
val scanner = ApiClientScanner()
private fun List<String>.toApiClientDefinitions(): Set<CoApiDefinition> {
val scanner = ApiClientScanner(false, env)
return flatMap { basePackage ->
scanner.findCandidateComponents(basePackage)
}.map { beanDefinition ->
Expand All @@ -40,7 +67,8 @@ class AutoCoApiRegistrar : AbstractCoApiRegistrar() {
}
}

class ApiClientScanner : ClassPathScanningCandidateComponentProvider(false) {
class ApiClientScanner(useDefaultFilters: Boolean, environment: Environment) :
ClassPathScanningCandidateComponentProvider(useDefaultFilters, environment) {
init {
addIncludeFilter(AnnotationTypeFilter(CoApi::class.java))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@ const val ENABLED_SUFFIX_KEY = ".enabled"
data class CoApiProperties(
@DefaultValue("true") var enabled: Boolean = true,
val mode: ClientMode = ClientMode.AUTO,
val basePackages: List<String> = emptyList(),
val clients: Map<String, ClientDefinition> = emptyMap(),
) : ClientProperties {
companion object {
const val COAPI_BASE_PACKAGES = "$COAPI_PREFIX.base-packages"
}

override fun getFilter(coApiName: String): ClientProperties.FilterDefinition {
return clients[coApiName]?.reactive?.filter ?: ClientProperties.FilterDefinition()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,67 @@ class CoApiAutoConfigurationTest {
context.getBean(ServiceApiClientUseFilterType::class.java)
}
}

@Test
fun basePackages() {
ApplicationContextRunner()
.withPropertyValues("github.url=https://api.github.com")
.withPropertyValues("${CoApiProperties.COAPI_BASE_PACKAGES}=me.ahoo.coapi.spring.boot.starter")
.withPropertyValues(filterNameProperty)
.withPropertyValues(filterTypeProperty)
.withBean("loadBalancerExchangeFilterFunction", LoadBalancedExchangeFilterFunction::class.java, { mockk() })
.withUserConfiguration(WebClientAutoConfiguration::class.java)
.withUserConfiguration(CoApiAutoConfiguration::class.java)
.run { context ->
AssertionsForInterfaceTypes.assertThat(context)
.hasSingleBean(ReactiveHttpExchangeAdapterFactory::class.java)
.hasSingleBean(me.ahoo.coapi.spring.boot.starter.GitHubApiClient::class.java)
}
}

@Test
fun basePackagesMultiple() {
ApplicationContextRunner()
.withPropertyValues("github.url=https://api.github.com")
.withPropertyValues(
"${CoApiProperties.COAPI_BASE_PACKAGES}=me.ahoo.coapi.spring.boot.starter" +
",me.ahoo.coapi.example.consumer.client"
)
.withPropertyValues(filterNameProperty)
.withPropertyValues(filterTypeProperty)
.withBean("loadBalancerExchangeFilterFunction", LoadBalancedExchangeFilterFunction::class.java, { mockk() })
.withUserConfiguration(WebClientAutoConfiguration::class.java)
.withUserConfiguration(CoApiAutoConfiguration::class.java)
.run { context ->
AssertionsForInterfaceTypes.assertThat(context)
.hasSingleBean(ReactiveHttpExchangeAdapterFactory::class.java)
.hasSingleBean(me.ahoo.coapi.spring.boot.starter.GitHubApiClient::class.java)
.hasSingleBean(ServiceApiClient::class.java)
}
}

@Test
fun basePackagesYaml() {
ApplicationContextRunner()
.withPropertyValues("github.url=https://api.github.com")
.withPropertyValues(
"${CoApiProperties.COAPI_BASE_PACKAGES}[0]=me.ahoo.coapi.spring.boot.starter"
)
.withPropertyValues(
"${CoApiProperties.COAPI_BASE_PACKAGES}[1]=me.ahoo.coapi.example.consumer.client"
)
.withPropertyValues(filterNameProperty)
.withPropertyValues(filterTypeProperty)
.withBean("loadBalancerExchangeFilterFunction", LoadBalancedExchangeFilterFunction::class.java, { mockk() })
.withUserConfiguration(WebClientAutoConfiguration::class.java)
.withUserConfiguration(CoApiAutoConfiguration::class.java)
.run { context ->
AssertionsForInterfaceTypes.assertThat(context)
.hasSingleBean(ReactiveHttpExchangeAdapterFactory::class.java)
.hasSingleBean(me.ahoo.coapi.spring.boot.starter.GitHubApiClient::class.java)
.hasSingleBean(ServiceApiClient::class.java)
}
}
}

@SpringBootApplication
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ class CoApiPropertiesTest {
assertThat(properties.enabled, equalTo(true))
}

@Test
fun getBasePackages() {
val properties = CoApiProperties()
assertThat(properties.basePackages, Matchers.empty())
}

@Test
fun getFilterIfDefault() {
val properties = CoApiProperties()
Expand Down

0 comments on commit fdde4a3

Please sign in to comment.