diff --git a/CODEOWNERS b/CODEOWNERS
index e690364..951eacc 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -1,2 +1,2 @@
 # Default owners
-* @lorenzsimon @sueskind @gimlet2
+* @lorenzsimon @gimlet2 @asyncapi-bot-eve
diff --git a/kotlin-asyncapi-annotation/src/main/kotlin/com/asyncapi/kotlinasyncapi/annotation/AsyncApiComponent.kt b/kotlin-asyncapi-annotation/src/main/kotlin/com/asyncapi/kotlinasyncapi/annotation/AsyncApiComponent.kt
new file mode 100644
index 0000000..c7c3c0f
--- /dev/null
+++ b/kotlin-asyncapi-annotation/src/main/kotlin/com/asyncapi/kotlinasyncapi/annotation/AsyncApiComponent.kt
@@ -0,0 +1,5 @@
+package com.asyncapi.kotlinasyncapi.annotation
+
+@Target(AnnotationTarget.CLASS)
+@AsyncApiAnnotation
+annotation  class AsyncApiComponent
\ No newline at end of file
diff --git a/kotlin-asyncapi-annotation/src/main/kotlin/com/asyncapi/kotlinasyncapi/annotation/channel/Channel.kt b/kotlin-asyncapi-annotation/src/main/kotlin/com/asyncapi/kotlinasyncapi/annotation/channel/Channel.kt
index 2e2e487..20b49b6 100644
--- a/kotlin-asyncapi-annotation/src/main/kotlin/com/asyncapi/kotlinasyncapi/annotation/channel/Channel.kt
+++ b/kotlin-asyncapi-annotation/src/main/kotlin/com/asyncapi/kotlinasyncapi/annotation/channel/Channel.kt
@@ -4,7 +4,8 @@ import com.asyncapi.kotlinasyncapi.annotation.AsyncApiAnnotation
 
 @Target(
     AnnotationTarget.CLASS,
-    AnnotationTarget.ANNOTATION_CLASS
+    AnnotationTarget.ANNOTATION_CLASS,
+    AnnotationTarget.FUNCTION
 )
 @AsyncApiAnnotation
 annotation class Channel(
diff --git a/kotlin-asyncapi-context/src/main/kotlin/com/asyncapi/kotlinasyncapi/context/annotation/AnnotationProvider.kt b/kotlin-asyncapi-context/src/main/kotlin/com/asyncapi/kotlinasyncapi/context/annotation/AnnotationProvider.kt
index b435d09..66b4bab 100644
--- a/kotlin-asyncapi-context/src/main/kotlin/com/asyncapi/kotlinasyncapi/context/annotation/AnnotationProvider.kt
+++ b/kotlin-asyncapi-context/src/main/kotlin/com/asyncapi/kotlinasyncapi/context/annotation/AnnotationProvider.kt
@@ -1,6 +1,7 @@
 package com.asyncapi.kotlinasyncapi.context.annotation
 
 import com.asyncapi.kotlinasyncapi.annotation.AsyncApiAnnotation
+import com.asyncapi.kotlinasyncapi.annotation.AsyncApiComponent
 import com.asyncapi.kotlinasyncapi.annotation.Schema
 import com.asyncapi.kotlinasyncapi.annotation.channel.Channel
 import com.asyncapi.kotlinasyncapi.annotation.channel.Message
@@ -31,7 +32,9 @@ class AnnotationProvider(
     private val scanner: AnnotationScanner,
     private val messageProcessor: AnnotationProcessor<Message, KClass<*>>,
     private val schemaProcessor: AnnotationProcessor<Schema, KClass<*>>,
-    private val channelProcessor: AnnotationProcessor<Channel, KClass<*>>
+    private val channelProcessor: AnnotationProcessor<Channel, KClass<*>>,
+    private val asyncApiComponentProcessor: AnnotationProcessor<AsyncApiComponent, KClass<*>>
+
 ) : AsyncApiContextProvider {
 
     private val componentToChannelMapping = mutableMapOf<String, String>()
@@ -70,7 +73,8 @@ class AnnotationProvider(
                 listOfNotNull(
                     clazz.findAnnotation<Message>()?.let { clazz to it },
                     clazz.findAnnotation<Schema>()?.let { clazz to it },
-                    clazz.findAnnotation<Channel>()?.let { clazz to it }
+                    clazz.findAnnotation<Channel>()?.let { clazz to it },
+                    clazz.findAnnotation<AsyncApiComponent>()?.let { clazz to it}
                 )
             }
             .mapNotNull { (clazz, annotation) ->
@@ -81,6 +85,11 @@ class AnnotationProvider(
                         componentToChannelMapping[clazz.java.simpleName] =
                             annotation.value.takeIf { it.isNotEmpty() } ?: clazz.java.simpleName
                     }
+                    is AsyncApiComponent -> asyncApiComponentProcessor.process(annotation, clazz).also { processedComponents ->
+                        processedComponents.channels?.forEach { (channelName, _) ->
+                            componentToChannelMapping[channelName] = channelName
+                        }
+                    }
                     else -> null
                 }
             }
diff --git a/kotlin-asyncapi-context/src/main/kotlin/com/asyncapi/kotlinasyncapi/context/annotation/processor/AsyncApiComponentProcessor.kt b/kotlin-asyncapi-context/src/main/kotlin/com/asyncapi/kotlinasyncapi/context/annotation/processor/AsyncApiComponentProcessor.kt
new file mode 100644
index 0000000..18ce768
--- /dev/null
+++ b/kotlin-asyncapi-context/src/main/kotlin/com/asyncapi/kotlinasyncapi/context/annotation/processor/AsyncApiComponentProcessor.kt
@@ -0,0 +1,31 @@
+package com.asyncapi.kotlinasyncapi.context.annotation.processor
+
+import com.asyncapi.kotlinasyncapi.annotation.AsyncApiComponent
+import com.asyncapi.kotlinasyncapi.annotation.channel.Channel
+import com.asyncapi.kotlinasyncapi.annotation.channel.Publish
+import com.asyncapi.kotlinasyncapi.annotation.channel.Subscribe
+import com.asyncapi.kotlinasyncapi.model.component.Components
+import kotlin.reflect.KClass
+import kotlin.reflect.full.findAnnotation
+import kotlin.reflect.full.functions
+import kotlin.reflect.full.hasAnnotation
+
+class AsyncApiComponentProcessor : AnnotationProcessor<AsyncApiComponent, KClass<*>> {
+    override fun process(annotation: AsyncApiComponent, context: KClass<*>): Components {
+        return Components().apply {
+            channels {
+                context.functions.filter { it.hasAnnotation<Channel>() }.forEach { currentFunction ->
+                    var currentAnnotation = currentFunction.findAnnotation<Channel>()!!
+                    currentAnnotation.toChannel()
+                        .apply {
+                            subscribe = subscribe ?: currentFunction.findAnnotation<Subscribe>()?.toOperation()
+                            publish = publish ?: currentFunction.findAnnotation<Publish>()?.toOperation()
+                        }
+                        .also {
+                            put(currentAnnotation.value, it)
+                        }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/kotlin-asyncapi-context/src/test/kotlin/com/asyncapi/kotlinasyncapi/context/annotation/processor/AsyncApiComponentProcessorTest.kt b/kotlin-asyncapi-context/src/test/kotlin/com/asyncapi/kotlinasyncapi/context/annotation/processor/AsyncApiComponentProcessorTest.kt
new file mode 100644
index 0000000..b4acdd8
--- /dev/null
+++ b/kotlin-asyncapi-context/src/test/kotlin/com/asyncapi/kotlinasyncapi/context/annotation/processor/AsyncApiComponentProcessorTest.kt
@@ -0,0 +1,62 @@
+package com.asyncapi.kotlinasyncapi.context.annotation.processor
+
+import org.junit.jupiter.api.Test
+import com.asyncapi.kotlinasyncapi.annotation.AsyncApiComponent
+import com.asyncapi.kotlinasyncapi.annotation.channel.Channel
+import com.asyncapi.kotlinasyncapi.annotation.channel.Message
+import com.asyncapi.kotlinasyncapi.annotation.channel.Parameter
+import com.asyncapi.kotlinasyncapi.annotation.channel.SecurityRequirement
+import com.asyncapi.kotlinasyncapi.annotation.channel.Subscribe
+import com.asyncapi.kotlinasyncapi.context.TestUtils.assertJsonEquals
+import com.asyncapi.kotlinasyncapi.context.TestUtils.json
+import kotlin.reflect.full.findAnnotation
+
+internal class AsyncApiComponentProcessorTest {
+
+    private val processor = AsyncApiComponentProcessor()
+
+    @Test
+    fun `should process async api component annotation on class`() {
+        val payload = TestChannelFunction::class
+        val annotation = payload.findAnnotation<AsyncApiComponent>()!!
+
+        val expected = json("annotation/async_api_component.json")
+        val actual = json(processor.process(annotation, payload))
+
+        assertJsonEquals(expected, actual)
+    }
+
+
+    @AsyncApiComponent
+    class TestChannelFunction {
+        @Channel(
+            value = "some/{parameter}/channel",
+            description = "testDescription",
+            servers = ["dev"],
+            parameters = [
+                Parameter(
+                    value = "parameter",
+                    description = "testDescription"
+                )
+            ]
+        )
+        @Subscribe(
+            operationId = "testOperationId",
+            security = [
+                SecurityRequirement(
+                    key = "petstore_auth",
+                    values = ["write:pets", "read:pets"]
+                )
+            ],
+            message = Message(TestSubscribeMessage::class)
+        )
+        fun testSubscribe() {}
+    }
+
+    @Message
+    data class TestSubscribeMessage(
+        val id: Int = 0,
+        val name: String,
+        val isTest: Boolean
+    )
+}
\ No newline at end of file
diff --git a/kotlin-asyncapi-context/src/test/resources/annotation/async_api_component.json b/kotlin-asyncapi-context/src/test/resources/annotation/async_api_component.json
new file mode 100644
index 0000000..a9edb0d
--- /dev/null
+++ b/kotlin-asyncapi-context/src/test/resources/annotation/async_api_component.json
@@ -0,0 +1,22 @@
+{
+  "channels" : {
+    "some/{parameter}/channel" : {
+      "description" : "testDescription",
+      "servers" : [ "dev" ],
+      "subscribe" : {
+        "operationId" : "testOperationId",
+        "security" : [ {
+          "petstore_auth" : [ "write:pets", "read:pets" ]
+        } ],
+        "message" : {
+          "$ref" : "#/components/messages/TestSubscribeMessage"
+        }
+      },
+      "parameters" : {
+        "parameter" : {
+          "description" : "testDescription"
+        }
+      }
+    }
+  }
+}
diff --git a/kotlin-asyncapi-ktor/src/main/kotlin/com/asyncapi/kotlinasyncapi/ktor/AsyncApiModule.kt b/kotlin-asyncapi-ktor/src/main/kotlin/com/asyncapi/kotlinasyncapi/ktor/AsyncApiModule.kt
index 56d7680..2ddd5e2 100644
--- a/kotlin-asyncapi-ktor/src/main/kotlin/com/asyncapi/kotlinasyncapi/ktor/AsyncApiModule.kt
+++ b/kotlin-asyncapi-ktor/src/main/kotlin/com/asyncapi/kotlinasyncapi/ktor/AsyncApiModule.kt
@@ -14,6 +14,7 @@ import com.asyncapi.kotlinasyncapi.context.PackageInfoProvider
 import com.asyncapi.kotlinasyncapi.context.ResourceProvider
 import com.asyncapi.kotlinasyncapi.context.annotation.AnnotationProvider
 import com.asyncapi.kotlinasyncapi.context.annotation.DefaultAnnotationScanner
+import com.asyncapi.kotlinasyncapi.context.annotation.processor.AsyncApiComponentProcessor
 import com.asyncapi.kotlinasyncapi.context.annotation.processor.ChannelProcessor
 import com.asyncapi.kotlinasyncapi.context.annotation.processor.MessageProcessor
 import com.asyncapi.kotlinasyncapi.context.annotation.processor.SchemaProcessor
@@ -52,6 +53,8 @@ class AsyncApiModule(
 
     private val channelProcessor = ChannelProcessor()
 
+    private val asyncApiComponentProcessor = AsyncApiComponentProcessor()
+
     private val annotationScanner = DefaultAnnotationScanner()
 
     private val annotationProvider = with(configuration) {
@@ -62,6 +65,7 @@ class AsyncApiModule(
             messageProcessor = messageProcessor,
             schemaProcessor = schemaProcessor,
             channelProcessor = channelProcessor,
+            asyncApiComponentProcessor = asyncApiComponentProcessor
         )
     }
 
diff --git a/kotlin-asyncapi-spring-web/pom.xml b/kotlin-asyncapi-spring-web/pom.xml
index 1d8791d..719a33d 100644
--- a/kotlin-asyncapi-spring-web/pom.xml
+++ b/kotlin-asyncapi-spring-web/pom.xml
@@ -32,7 +32,7 @@
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-autoconfigure</artifactId>
-            <version>[2.6.4,2.7.17], [3.2.0,)</version>
+            <version>[2.6.4,2.7.17], [3.2.0,3.3.5]</version>
         </dependency>
         <dependency>
             <groupId>org.jetbrains.kotlin</groupId>
diff --git a/kotlin-asyncapi-spring-web/src/main/kotlin/com/asyncapi/kotlinasyncapi/springweb/AsyncApiAutoConfiguration.kt b/kotlin-asyncapi-spring-web/src/main/kotlin/com/asyncapi/kotlinasyncapi/springweb/AsyncApiAutoConfiguration.kt
index 2b31f90..6e3150f 100644
--- a/kotlin-asyncapi-spring-web/src/main/kotlin/com/asyncapi/kotlinasyncapi/springweb/AsyncApiAutoConfiguration.kt
+++ b/kotlin-asyncapi-spring-web/src/main/kotlin/com/asyncapi/kotlinasyncapi/springweb/AsyncApiAutoConfiguration.kt
@@ -1,5 +1,6 @@
 package com.asyncapi.kotlinasyncapi.springweb
 
+import com.asyncapi.kotlinasyncapi.annotation.AsyncApiComponent
 import kotlin.reflect.KClass
 import kotlin.script.experimental.host.toScriptSource
 import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost
@@ -13,6 +14,7 @@ import com.asyncapi.kotlinasyncapi.context.annotation.AnnotationProvider
 import com.asyncapi.kotlinasyncapi.context.annotation.AnnotationScanner
 import com.asyncapi.kotlinasyncapi.context.annotation.DefaultAnnotationScanner
 import com.asyncapi.kotlinasyncapi.context.annotation.processor.AnnotationProcessor
+import com.asyncapi.kotlinasyncapi.context.annotation.processor.AsyncApiComponentProcessor
 import com.asyncapi.kotlinasyncapi.context.annotation.processor.ChannelProcessor
 import com.asyncapi.kotlinasyncapi.context.annotation.processor.MessageProcessor
 import com.asyncapi.kotlinasyncapi.context.annotation.processor.SchemaProcessor
@@ -102,6 +104,10 @@ internal open class AsyncApiAnnotationAutoConfiguration {
     open fun channelProcessor() =
         ChannelProcessor()
 
+    @Bean
+    open fun asyncApiComponentProcessor() =
+        AsyncApiComponentProcessor()
+
     @Bean
     open fun annotationScanner() =
         DefaultAnnotationScanner()
@@ -112,14 +118,16 @@ internal open class AsyncApiAnnotationAutoConfiguration {
         scanner: AnnotationScanner,
         messageProcessor: AnnotationProcessor<Message, KClass<*>>,
         schemaProcessor: AnnotationProcessor<Schema, KClass<*>>,
-        channelProcessor: AnnotationProcessor<Channel, KClass<*>>
+        channelClassProcessor: AnnotationProcessor<Channel, KClass<*>>,
+        asyncApiComponentProcessor: AnnotationProcessor<AsyncApiComponent, KClass<*>>
     ) = packageFromContext(context)?.let {
         AnnotationProvider(
             applicationPackage = it,
             scanner = scanner,
             messageProcessor = messageProcessor,
             schemaProcessor = schemaProcessor,
-            channelProcessor = channelProcessor,
+            channelProcessor = channelClassProcessor,
+            asyncApiComponentProcessor = asyncApiComponentProcessor,
         )
     }
 
diff --git a/kotlin-asyncapi-spring-web/src/test/kotlin/com/asyncapi/kotlinasyncapi/springweb/controller/AsyncApiControllerIntegrationTest.kt b/kotlin-asyncapi-spring-web/src/test/kotlin/com/asyncapi/kotlinasyncapi/springweb/controller/AsyncApiControllerIntegrationTest.kt
index 467946c..28080f5 100644
--- a/kotlin-asyncapi-spring-web/src/test/kotlin/com/asyncapi/kotlinasyncapi/springweb/controller/AsyncApiControllerIntegrationTest.kt
+++ b/kotlin-asyncapi-spring-web/src/test/kotlin/com/asyncapi/kotlinasyncapi/springweb/controller/AsyncApiControllerIntegrationTest.kt
@@ -1,5 +1,6 @@
 package com.asyncapi.kotlinasyncapi.springweb.controller
 
+import com.asyncapi.kotlinasyncapi.annotation.AsyncApiComponent
 import org.junit.jupiter.api.Test
 import com.asyncapi.kotlinasyncapi.annotation.channel.Channel
 import com.asyncapi.kotlinasyncapi.annotation.channel.Message
@@ -212,3 +213,52 @@ internal class AsyncApiControllerAnnotationIntegrationTest {
         val optionalValue: Boolean?
     )
 }
+
+@SpringBootTest
+@AutoConfigureMockMvc
+internal class AsyncApiComponentAnnotationControllerIntegrationTest {
+
+    @Autowired
+    lateinit var mockMvc: MockMvc
+
+    @Test
+    fun `should return AsyncApi document`() {
+        val expected = TestUtils.json("async_api_component_annotation_integration.json")
+
+        mockMvc.perform(get("/docs/asyncapi"))
+            .andExpect(MockMvcResultMatchers.status().is2xxSuccessful)
+            .andExpect(content().json(expected))
+    }
+
+    @SpringBootConfiguration
+    @EnableAutoConfiguration
+    @EnableAsyncApi
+    open class TestConfig {
+
+        @Bean
+        open fun asyncApiExtension() =
+            AsyncApiExtension.builder {
+                info {
+                    title("testTitle")
+                    version("testVersion")
+                }
+            }
+    }
+
+    @AsyncApiComponent
+    class TestChannel {
+
+        @Channel("my/channel")
+        @Publish(
+            description = "testDescription",
+            message = Message(TestMessage::class)
+        )
+        fun testOperation() {}
+    }
+
+    @Message
+    data class TestMessage(
+        val value: String,
+        val optionalValue: Boolean?
+    )
+}
diff --git a/kotlin-asyncapi-spring-web/src/test/resources/async_api_component_annotation_integration.json b/kotlin-asyncapi-spring-web/src/test/resources/async_api_component_annotation_integration.json
new file mode 100644
index 0000000..519b246
--- /dev/null
+++ b/kotlin-asyncapi-spring-web/src/test/resources/async_api_component_annotation_integration.json
@@ -0,0 +1,57 @@
+{
+  "asyncapi": "2.4.0",
+  "info": {
+    "title": "testTitle",
+    "version": "testVersion"
+  },
+  "channels": {
+    "my/channel": {
+      "$ref": "#/components/channels/TestChannel"
+    }
+  },
+  "components": {
+    "schemas": {
+      "TestMessage": {
+        "required": [
+          "value"
+        ],
+        "type": "object",
+        "properties": {
+          "value": {
+            "type": "string",
+            "exampleSetFlag": false,
+            "types": [
+              "string"
+            ]
+          },
+          "optionalValue": {
+            "type": "boolean",
+            "exampleSetFlag": false,
+            "types": [
+              "boolean"
+            ]
+          }
+        },
+        "exampleSetFlag": false
+      }
+    },
+    "channels": {
+      "my/channel": {
+        "publish": {
+          "description": "testDescription",
+          "message": {
+            "$ref": "#/components/messages/TestMessage"
+          }
+        }
+      }
+    },
+    "messages": {
+      "TestMessage": {
+        "payload": {
+          "$ref": "#/components/schemas/TestMessage"
+        },
+        "schemaFormat": "application/schema+json;version=draft-07"
+      }
+    }
+  }
+}
diff --git a/pom.xml b/pom.xml
index 7dfb8bc..6f638c6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -154,7 +154,7 @@
                 <extensions>true</extensions>
                 <configuration>
                     <serverId>ossrh</serverId>
-                    <nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
+                    <nexusUrl>https://oss.sonatype.org/</nexusUrl>
                     <autoReleaseAfterClose>true</autoReleaseAfterClose>
                 </configuration>
             </plugin>
@@ -200,12 +200,12 @@
         <snapshotRepository>
             <id>ossrh</id>
             <name>Sonatype Nexus Snapshots</name>
-            <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
+            <url>https://oss.sonatype.org/content/repositories/snapshots</url>
         </snapshotRepository>
         <repository>
             <id>ossrh</id>
             <name>Nexus Release Repository</name>
-            <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+            <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
         </repository>
     </distributionManagement>