---
title: "Java Spring — Аннотации Spring"
url: "https://romankryvolapov.com/ru/java-spring-annotations/"
description: "Справочник аннотаций Spring с примерами на Kotlin: @Component, @Bean, @Transactional, маппинг запросов, JPA и разница между @Component и @Bean."
language: ru
updated: 2026-01-21
---
## Какие основные аннотации в Spring {#Какие-основные-аннотации-в-Spring}

```text
Annotation
    ├── Component
    │     ├── Repository
    │     ├── Service
    │     ├── Controller
    │     │     └── RestController
    ├── Configuration
    │     └── EnableAutoConfiguration
    ├── SpringBootApplication
    │     └── Configuration
    │         └── EnableAutoConfiguration
    ├── Conditional
    │     ├── ConditionalOnBean
    │     ├── ConditionalOnMissingBean
    │     ├── ConditionalOnClass
    │     ├── ConditionalOnMissingClass
    │     ├── ConditionalOnProperty
    │     ├── ConditionalOnResource
    │     ├── ConditionalOnWebApplication
    │     └── ConditionalOnNotWebApplication
    ├── Enable
    │     ├── EnableAspectJAutoProxy
    │     ├── EnableCaching
    │     ├── EnableScheduling
    │     └── EnableAsync
    ├── Transactional
    ├── Bean
    ├── Qualifier
    ├── Autowired
    ├── Value
    ├── Primary
    ├── Lazy
    ├── Scope
```

<span id="Configuration"></span>

**@Configuration**\
указывает, что класс содержит определения бинов и должен быть обработан контейнером Spring для генерации бинов Spring.

```java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration
```

```kotlin
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration


@Configuration
class AppConfig {

    @Bean
    fun myBean(): MyBean {
        return MyBean()
    }

}


class MyBean {

    fun doSomething() {
        println("Doing something...")
    }

}
```

<span id="Bean"></span>

**@Bean**\
указывает, что метод производит бин, управляемый Spring-контейнером.

```java
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean
```

```kotlin
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration


@Configuration
class AppConfig {

    @Bean
    fun myBean(): MyBean {
        return MyBean()
    }

}
```

<span id="Component"></span>

**@Component**\
указывает, что класс является компонентом Spring, что позволяет Spring автоматически определять его для управления в контейнере.

```java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component
```

```kotlin
import org.springframework.stereotype.Component


@Component
class MyComponent {

    fun doWork() {
        println("Component is working...")
    }

}
```

<span id="Service"></span>

**@Service**\
специализированная аннотация, используемая для классов сервисного уровня. Это также разновидность @Component.

```java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service
```

```kotlin
import org.springframework.stereotype.Service


@Service
class MyService {

    fun performService() {
        println("Service is performing...")
    }

}
```

<span id="Repository"></span>

**@Repository**\
специализированная аннотация для классов доступа к данным (DAO). Это также разновидность @Component.

```java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository
```

```kotlin
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository


@Repository
interface UserRepository : JpaRepository<User, Long> {

    fun findByUsername(
      username: String
    ): User?

}
```

<span id="Controller"></span>

**@Controller**\
указывает, что класс является контроллером Spring MVC. Эта аннотация используется для обработки веб-запросов.

```java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller
```

```kotlin
import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping


@Controller
@RequestMapping("/web")
class WebController {

    @GetMapping("/hello")
    fun hello(model: Model): String {
        model.addAttribute(
          "message",
          "Hello, World!"
        )
        return "hello"
    }

}
```

<span id="RestController"></span>

**@RestController**\
является комбинацией @Controller и @ResponseBody. Она указывает, что класс является RESTful контроллером, и возвращаемые данные должны быть напрямую написаны в HTTP-ответе в формате JSON или XML.

```java
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController
```

```kotlin
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController


@RestController
@RequestMapping("/api")
class ApiController {

    @GetMapping("/greeting")
    fun greeting(): String {
        return "Hello, API World!"
    }

}
```

<span id="RestControllerAdvice"></span>

**@RestControllerAdvice**\
используется для глобальной обработки исключений и предоставления совета контроллерам, работающим с REST API. Это расширение аннотации @ControllerAdvice, которое автоматически включает @ResponseBody, что делает ее подходящей для обработки исключений в контроллерах REST, возвращая ответы в формате JSON или XML.

```java
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice
@ResponseBody
public @interface RestControllerAdvice
```

```kotlin
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice


class UserNotFoundException(
  message: String
) : RuntimeException(message)


data class ErrorResponse(
  val message: String,
  val details: String
)


@RestControllerAdvice
class RestExceptionHandler {

    @ExceptionHandler(UserNotFoundException::class)
    fun handleUserNotFoundException(
      ex: UserNotFoundException
    ): ResponseEntity<ErrorResponse> {
        val errorResponse = ErrorResponse(
            message = ex.message ?: "User not found",
            details = "The user you are looking for does not exist."
        )
        return ResponseEntity(errorResponse, HttpStatus.NOT_FOUND)
    }

    @ExceptionHandler(Exception::class)
    fun handleGenericException(
      ex: Exception
    ): ResponseEntity<ErrorResponse> {
        val errorResponse = ErrorResponse(
            message = ex.message ?: "An error occurred",
            details = "Please contact support."
        )
        return ResponseEntity(
          errorResponse,
          HttpStatus.INTERNAL_SERVER_ERROR
        )
    }

}
```

```kotlin
// Контроллер, выбрасывающий исключение
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RestController


@RestController
@RequestMapping("/users")
class UserController {

    private val users = mapOf(
        1L to "John Doe",
        2L to "Jane Doe"
    )

    @GetMapping("/{id}")
    fun getUser(@PathVariable id: Long): String {
        return users[id]
      ?: throw UserNotFoundException(
        "User with ID $id not found"
      )
    }

}
```

**Пример обработки исключений с использованием @RestControllerAdvice:**\
При запросе пользователя с ID, который не существует, сервер вернет JSON-ответ с HTTP-статусом 404 (Not Found) и телом:

```json
{
    "message": "User with ID 3 not found",
    "details": "The user you are looking for does not exist."
}
```

Если возникает общее исключение, сервер вернет JSON-ответ с HTTP-статусом 500 (Internal Server Error) и телом:

```json
{
    "message": "An error occurred",
    "details": "Please contact support."
}
```

<span id="ResponseBody"></span>

**@ResponseBody**\
делает автоматическую сериализацию в JSON любого возвращаемого объекта

```java
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody
```

```kotlin
@Controller
class PersonController {

    @GetMapping("/persons/{id}")
    @ResponseBody
    fun getData(
      @PathVariable id: Long
    ): String {
        return ""
    }

}

// то же самое что

@RestController
class PersonController {

    @GetMapping("/persons/{id}")
    fun getData(
      @PathVariable id: Long
    ): String{
        return ""
    }

}
```

<span id="Aspect"></span>

**@Aspect**\
способ вынести повторяющуюся логику (например, логирование или проверку безопасности) из методов в отдельный класс. Он автоматически подключается к нужным методам и выполняет нужные действия до, после или вокруг них. Это удобно, потому что не нужно дублировать один и тот же код во многих местах.

<span id="Before"></span>

**@Before**\
указывает, что метод-совет должен выполняться до вызова целевого метода. Используется, например, для логирования входа в метод или проверки прав доступа.

<span id="After"></span>

**@After**\
указывает, что метод-совет должен выполняться после завершения целевого метода — независимо от того, успешно он завершился или с исключением. Подходит для очистки ресурсов или логирования выхода.

<span id="Around"></span>

**@Around**\
позволяет полностью обернуть вызов целевого метода: выполнить код до, вызвать сам метод через proceed(), а затем выполнить код после. Даёт полный контроль над выполнением — можно изменить аргументы, результат, или даже не вызывать сам метод.

<span id="Pointcut"></span>

**@Pointcut**\
описывает, к каким методам применять аспект (по сигнатурам, аннотациям и т.д.)

```kotlin
@Aspect
@Component
class LoggingAspect {

    // Pointcut that matches all methods in the service package
    @Pointcut("execution(* com.example.service.*.*(..))")
    fun allServiceMethods() {
    }

    // Runs before the matched method
    @Before("allServiceMethods()")
    fun logBefore() {
        println("Method is about to be called")
    }

    // Runs after the matched method finishes
    @After("allServiceMethods()")
    fun logAfter() {
        println("Method has finished execution")
    }

    // Runs around the matched method: before and after
    @Around("allServiceMethods()")
    fun logAround(joinPoint: ProceedingJoinPoint): Any? {
        println("Before method: ${joinPoint.signature.name}")
        val result = joinPoint.proceed()
        println("After method: ${joinPoint.signature.name}")
        return result
    }

}
```

<span id="ModelAttribute"></span>

**@ModelAttribute**\
используется для привязки данных модели к параметрам метода или возвращаемым значениям методов контроллера. Она может применяться как к параметрам метода, так и к самим методам, предоставляя гибкий механизм для подготовки и связывания данных модели.

<span id="MatrixVariable"></span>

**@MatrixVariable**\
в Spring используется для привязки значений переменных матрицы к параметрам метода в контроллере. Переменные матрицы — это параметры, которые включаются в части пути URL между точками с запятой (;). Эта аннотация позволяет извлечь значения переменных матрицы и использовать их в методах контроллера.

<span id="InitBinder"></span>

**@InitBinder**\
используется для настройки средств привязки данных на уровне контроллера. Эти средства привязки данных обрабатывают данные, поступающие из HTTP-запросов, и преобразуют их в объекты модели. Аннотация @InitBinder позволяет вам регистрировать пользовательские редакторы свойств или валидаторы для обработки данных, перед их связыванием с объектами модели.

<span id="CookieValue"></span>

**@CookieValue**\
используется для привязки значения из HTTP cookie к параметру метода в контроллере. Это позволяет вам получать значения cookie непосредственно в методах контроллера, что упрощает работу с ними.

```kotlin
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.CookieValue
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController


@RestController
@RequestMapping("/api")
class UserController {

    @GetMapping("/token")
    fun getToken(
      @CookieValue("userToken") token: String
    ): String {
        return "User token: $token"
    }

}
```

<span id="Autowired"></span>

**@Autowired**\
используется для автоматического внедрения зависимостей. Spring автоматически находит подходящий бин и внедряет его в поле, конструктор или метод.

```java
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired
```

```kotlin
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service


@Service
class MainService @Autowired constructor(
    private val myComponent: MyComponent
) {

    fun execute() {
        myComponent.doWork()
    }

}
```

<span id="Transactional"></span>

**@Transactional**\
используется для управления транзакциями. Она может быть применена к методам или классам для автоматического начала, коммита или отката транзакций.\
Механизм работы @Transactional в Spring основан на использовании прокси и аспектно-ориентированного программирования для управления транзакциями. Прокси перехватывает вызовы методов и взаимодействует с транзакционным менеджером для начала, подтверждения или отката транзакций. Это позволяет автоматически обрабатывать транзакции, упрощая разработку надежных и согласованных приложений.

```java
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Reflective
public @interface Transactional
```

```kotlin
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional


@Service
class TransactionalService(
    private val userRepository: UserRepository
) {

    @Transactional
    fun processTransaction() {
        val data = userRepository
        	.findByUsername("username")
        println("Processing data: $data")
    }

}
```

<span id="EnableTransactionManagement"></span>

**@EnableTransactionManagement**\
используется в Spring для включения поддержки транзакционного менеджмента, основанного на аннотациях. Она автоматически настраивает необходимые бины и прокси для обработки методов, аннотированных @Transactional. Рассмотрим, как это работает и как его использовать.

**Основные функции @EnableTransactionManagement:**

**Активация поддержки транзакций:**\
Включает инфраструктуру, необходимую для работы с транзакциями, основанными на аннотациях, такими как @Transactional.

**Прокси:**\
Создает прокси для бинов, которые имеют методы, аннотированные @Transactional. Прокси перехватывает вызовы этих методов и управляет транзакциями.

**Конфигурация:**\
Аннотация автоматически настраивает TransactionManager, который управляет началом, подтверждением и откатом транзакций.

**Основные атрибуты @EnableTransactionManagement:**

**mode:**\
Определяет, будет ли использоваться проксирование на основе интерфейсов (JDK) или классов (CGLIB). Значение по умолчанию — AdviceMode.PROXY.

**proxyTargetClass:**\
Если true, то используется CGLIB проксирование (по умолчанию false).

**order:**\
Устанавливает порядок выполнения транзакционных аспектов.

```kotlin
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.transaction.annotation.EnableTransactionManagement
import org.springframework.transaction.annotation.TransactionManagementConfigurer
import org.springframework.transaction.PlatformTransactionManager
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource
import org.springframework.transaction.interceptor.TransactionInterceptor
import org.springframework.transaction.interceptor.TransactionProxyFactoryBean
import javax.sql.DataSource


@Configuration
@EnableTransactionManagement
class TransactionConfig(
    private val dataSource: DataSource
) : TransactionManagementConfigurer {

    @Bean
    override fun annotationDrivenTransactionManager(): PlatformTransactionManager {
        return DataSourceTransactionManager(dataSource)
    }

    @Bean
    fun transactionInterceptor(): TransactionInterceptor {
        val source = AnnotationTransactionAttributeSource()
        val transactionManager = annotationDrivenTransactionManager()
        return TransactionInterceptor(transactionManager, source)
    }

    @Bean
    fun transactionProxyFactoryBean(): TransactionProxyFactoryBean {
        val proxyFactoryBean = TransactionProxyFactoryBean()
        proxyFactoryBean.transactionManager = annotationDrivenTransactionManager()
        proxyFactoryBean.setTransactionAttributes(
            mapOf(
                "save*" to "PROPAGATION_REQUIRED",
                "delete*" to "PROPAGATION_REQUIRED",
                "update*" to "PROPAGATION_REQUIRED",
                "*" to "PROPAGATION_REQUIRED,readOnly"
            )
        )
        return proxyFactoryBean
    }

}
```

**DataSourceTransactionManager:**\
Используется как транзакционный менеджер для управления транзакциями на уровне JDBC.

**TransactionInterceptor:**\
Перехватывает вызовы методов и обрабатывает транзакционную логику.

**TransactionProxyFactoryBean:**\
Создает прокси для бинов, чтобы перехватывать вызовы методов и обрабатывать транзакционную логику.

<span id="RequestPart"></span>

**@RequestPart**\
используется для привязки части многочастного (multipart) запроса к параметру метода контроллера. Она позволяет обрабатывать файлы и данные формы, отправленные с использованием формы с атрибутом enctype=”multipart/form-data”.

```java
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestPart
```

```kotlin
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestPart
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.multipart.MultipartFile
import java.nio.file.Files
import java.nio.file.Paths


@RestController
@RequestMapping("/api")
class FileUploadController {

    @PostMapping("/upload")
    fun handleFileUpload(
      @RequestPart("file") file: MultipartFile
    ): String {
        val uploadDir = Paths.get("uploads")
        Files.createDirectories(uploadDir)
        val uploadFilePath = uploadDir.resolve(
          file.originalFilename ?: "uploadedFile"
        )
        file.inputStream.use { input ->
            Files.copy(input, uploadFilePath)
        }
        return "File uploaded successfully: ${file.originalFilename}"
    }

}
```

```kotlin
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestPart
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.multipart.MultipartFile


data class User(
    val name: String,
    val email: String
)


@RestController
@RequestMapping("/api")
class UserUploadController {

    @PostMapping("/upload-user")
    fun handleUserUpload(
        @RequestPart("user") user: User,
        @RequestPart("file") file: MultipartFile
    ): String {
        return "User: ${user.name}, File: ${file.originalFilename}"
    }

}
```

<span id="Value"></span>

**@Value**\
используется для внедрения значений из файла свойств в поля.

```java
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value
```

```kotlin
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Configuration


@Configuration
class AppConfig {

    @Value("\${my.property}")
    lateinit var myProperty: String

    fun showProperty() {
        println("Property value: $myProperty")
    }

}
```

<span id="RequestMapping"></span>

**@RequestMapping**\
добавляет перед qrl метода то, что в него передано

```java
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
@Reflective({ControllerMappingReflectiveProcessor.class})
public @interface RequestMapping
```

```kotlin
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController


@RestController
@RequestMapping("/api")
class ApiController {

    @RequestMapping("/all")
    fun getAll(): String {
        return "Get all data"
    }

}
```

<span id="GetMapping-и-PostMapping"></span>

**@GetMapping и @PostMapping**\
являются специализированными версиями @RequestMapping для обработки GET и POST запросов соответственно.\
Есть также @DeleteMapping, @PutMapping

```java
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = {RequestMethod.GET})
public @interface GetMapping
```

```kotlin
@RestController
@RequestMapping("/api")
class ApiController {

    @GetMapping("/get")
    fun getData(): String {
        return "Get data"
    }

    @PostMapping("/post")
    fun postData(
      @RequestParam data: String
    ): String {
        return "Posted data: $data"
    }

}
```

<span id="RequestParam"></span>

**@RequestParam**\
используется для извлечения параметров запроса, тогда как @PathVariable используется для извлечения переменных пути из URL

```java
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam
```

```kotlin
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController


@RestController
@RequestMapping("/api")
class ParameterController {

    @GetMapping("/request")
    fun requestParam(
      @RequestParam name: String
    ): String {
        return "Request param: $name"
    }

    @GetMapping("/path/{id}")
    fun pathVariable(
      @PathVariable id: Int
    ): String {
        return "Path variable: $id"
    }

}
```

<span id="RequestBody"></span>

**@RequestBody**\
сериализует класс в JSON

```java
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestBody
```

```kotlin
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController


data class User(
  val username: String,
  val password: String
)


@RestController
@RequestMapping("/api")
class UserController {

    @PostMapping("/user")
    fun createUser(
      @RequestBody user: User
    ): String {
        return "User created: ${user.username}"
    }

}
```

<span id="SessionAttribute"></span>

**@SessionAttribute**\
используется для доступа к атрибутам HTTP-сессии в методах контроллера. Эта аннотация позволяет легко получить значение атрибута сессии и использовать его в методе контроллера, не прибегая к прямому взаимодействию с объектом HttpSession.

```java
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SessionAttribute
```

```kotlin
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.SessionAttributes
import org.springframework.web.bind.support.SessionStatus
import javax.servlet.http.HttpSession


@Controller
@RequestMapping("/session")
@SessionAttributes("user")
class SessionController {

    @GetMapping("/set")
    fun setSessionAttribute(
      @RequestParam name: String,
      session: HttpSession
    ): String {
        session.setAttribute("user", name)
        return "redirect:/session/show"
    }

    @GetMapping("/show")
    fun showSessionAttribute(
      @SessionAttribute("user") user: String
    ): String {
        println("User in session: $user")
        return "session"
    }

    @GetMapping("/invalidate")
    fun invalidateSession(
      session: HttpSession,
      status: SessionStatus
    ): String {
        status.setComplete()
        session.invalidate()
        return "redirect:/session/show"
    }

}
```

```kotlin
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.SessionAttribute


@Controller
class UserController {

    @GetMapping("/current-user")
    fun currentUser(
      @SessionAttribute("user") user: String
    ): String {
        println("Current user: $user")
        return "currentUser"
    }

}
```

<span id="SessionAttributes"></span>

**@SessionAttributes**\
используется для указания, какие атрибуты модели должны быть сохранены в HTTP-сессии и доступны в течение нескольких запросов в рамках одной сессии пользователя. Это полезно, когда вы хотите сохранить данные между запросами без необходимости вручную управлять объектом HttpSession.

```java
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface SessionAttributes
```

```kotlin
import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.ModelAttribute
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.SessionAttributes
import org.springframework.web.bind.support.SessionStatus


data class User(
    var firstName: String = "",
    var lastName: String = "",
    var email: String = ""
)

@Controller
@RequestMapping("/session")
@SessionAttributes("user")
class SessionController {

    @ModelAttribute("user")
    fun user(): User {
        return User()
    }

    @GetMapping("/form")
    fun showForm(
      model: Model
    ): String {
        return "userForm"
    }

    @PostMapping("/save")
    fun saveUser(
      @ModelAttribute("user") user: User
    ): String {
        // Сохранение пользователя в сессии
        println("User saved: $user")
        return "redirect:/session/details"
    }

    @GetMapping("/details")
    fun userDetails(
      @ModelAttribute("user") user: User
    ): String {
        println("User details: $user")
        return "userDetails"
    }

    @GetMapping("/clear")
    fun clearSession(
      sessionStatus: SessionStatus
    ): String {
        sessionStatus.setComplete()
        return "redirect:/session/form"
    }

}

```

userForm.html

```html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>User Form</title>
</head>
<body>
    <form action="#" th:action="@{/session/save}" th:object="${user}" method="post">
        <label for="firstName">First Name:</label>
        <input type="text" id="firstName" name="firstName" th:field="*{firstName}" /><br/>
        <label for="lastName">Last Name:</label>
        <input type="text" id="lastName" name="lastName" th:field="*{lastName}" /><br/>
        <label for="email">Email:</label>
        <input type="email" id="email" name="email" th:field="*{email}" /><br/>
        <button type="submit">Save</button>
    </form>
</body>
</html>
```

userDetails.html

```html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>User Details</title>
</head>
<body>
    <h1>User Details</h1>
    <p>First Name: <span th:text="${user.firstName}">First Name</span></p>
    <p>Last Name: <span th:text="${user.lastName}">Last Name</span></p>
    <p>Email: <span th:text="${user.email}">Email</span></p>
    <a th:href="@{/session/clear}">Clear Session</a>
</body>
</html>
```

<span id="ResponseStatus"></span>

**@ResponseStatus**\
используется для указания статуса HTTP-ответа, который должен быть возвращен с аннотированного метода или исключения. Это позволяет вам управлять HTTP-статусами, возвращаемыми клиенту, без необходимости вручную устанавливать их в коде контроллера.

**Основные параметры @ResponseStatus**:

**code (тип: HttpStatus):**\
Указывает код статуса HTTP, который должен быть возвращен. Это обязательный параметр.

**reason (тип: String):**\
Указывает причину, которая будет возвращена вместе с кодом статуса. Этот параметр является необязательным.

```java
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseStatus
```

```kotlin
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.bind.annotation.RestController


@RestController
@RequestMapping("/api")
class MyController {

    @GetMapping("/success")
    @ResponseStatus(HttpStatus.OK)
    fun success(): String {
        return "Request was successful"
    }

    @GetMapping("/notfound")
    @ResponseStatus(HttpStatus.NOT_FOUND)
    fun notFound(): String {
        return "Resource not found"
    }

}
```

<span id="RequestHeader"></span>

**@RequestHeader**\
используется для привязки значения заголовка HTTP-запроса к параметру метода в контроллере. Это позволяет вам получать значения заголовков HTTP-запроса непосредственно в методах контроллера, что упрощает работу с заголовками запросов.

```java
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestHeader
```

```kotlin
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestHeader
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController


@RestController
@RequestMapping("/api")
class HeaderController {

    @GetMapping("/user-agent")
    fun getUserAgent(
        @RequestHeader("User-Agent") userAgent: String
    ): String {
        return "User-Agent: $userAgent"
    }

}
```

```kotlin
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestHeader
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController


@RestController
@RequestMapping("/api")
class HeaderController {

    @GetMapping("/accept-language")
    fun getAcceptLanguage(
        @RequestHeader(
          "Accept-Language",
          defaultValue = "en-US"
        ) acceptLanguage: String
    ): String {
        return "Accept-Language: $acceptLanguage"
    }

}
```

```kotlin
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestHeader
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController


@RestController
@RequestMapping("/api")
class HeaderController {

    @GetMapping("/required-header")
    fun getRequiredHeader(
        @RequestHeader(
          "X-Custom-Header",
          required = true
        ) customHeader: String
    ): String {
        return "X-Custom-Header: $customHeader"
    }

}
```

<span id="RequestAttribute"></span>

**@RequestAttribute**\
используется для привязки значения атрибута HTTP-запроса к параметру метода в контроллере. Это позволяет вам получать значения атрибутов запроса непосредственно в методах контроллера, что упрощает работу с атрибутами, установленными в запросе.

```java
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestAttribute
```

```kotlin
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestAttribute
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController


@RestController
@RequestMapping("/api")
class MyController {

    @GetMapping("/attribute")
    fun getRequestAttribute(
        @RequestAttribute("myAttribute") myAttribute: String
    ): String {
        return "Request Attribute: $myAttribute"
    }

}
```

```kotlin
import javax.servlet.Filter
import javax.servlet.FilterChain
import javax.servlet.FilterConfig
import javax.servlet.ServletRequest
import javax.servlet.ServletResponse
import org.springframework.stereotype.Component


@Component
class MyFilter : Filter {

    override fun init(filterConfig: FilterConfig?) {
    }

    override fun doFilter(
        request: ServletRequest,
        response: ServletResponse,
        chain: FilterChain
    ) {
        request.setAttribute("myAttribute", "Some Value")
        chain.doFilter(request, response)
    }

    override fun destroy() {
    }

}
```

<span id="ExceptionHandler"></span>

**@ExceptionHandler**\
используется для определения метода, который будет обрабатывать определенные типы исключений

```java
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Reflective({ExceptionHandlerReflectiveProcessor.class})
public @interface ExceptionHandler
```

```kotlin
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController


@RestController
@RequestMapping("/api")
class ExceptionController {

    @GetMapping("/exception")
    fun throwException(): String {
        throw RuntimeException("Exception occurred!")
    }

    @ExceptionHandler(RuntimeException::class)
    fun handleRuntimeException(
      ex: RuntimeException
    ): ResponseEntity<String> {
        return ResponseEntity(
            "Handled exception: ${ex.message}",
            HttpStatus.INTERNAL_SERVER_ERROR
        )
    }

}
```

<span id="CrossOrigin"></span>

**@CrossOrigin**\
позволяет кросс-доменные запросы к методу или классу.

```java
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin
```

```kotlin
import org.springframework.web.bind.annotation.CrossOrigin
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController


@RestController
@RequestMapping("/api")
@CrossOrigin(origins = ["http://example.com"])
class CrossOriginController {

    @GetMapping("/data")
    fun getData(): String {
        return "Cross-origin data"
    }

}
```

<span id="Qualifier"></span>

**@Qualifier**\
используется в Spring для разрешения неоднозначностей при внедрении зависимостей. Когда у Spring-контейнера есть несколько бинов одного типа, @Qualifier позволяет указать, какой именно бин должен быть внедрен.

```java
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier
```

```kotlin
interface Animal {

    fun speak()

}

@Component
@Qualifier("dog")
class Dog : Animal {

    override fun speak() {
        println("Woof!")
    }

}

@Component
@Qualifier("cat")
class Cat : Animal {

    override fun speak() {
        println("Meow!")
    }

}
```

```kotlin
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.stereotype.Component


@Component
class AnimalService @Autowired constructor(
    @Qualifier("dog") private val animal: Animal
) {

    fun makeAnimalSpeak() {
        animal.speak()
    }

}
```

<span id="Primary"></span>

**@Primary**\
если у вас есть бин, который вы хотите использовать по умолчанию, вы можете аннотировать его с помощью @Primary. Тогда @Qualifier будет использоваться только для уточнения. В этом случае, если @Qualifier не используется, будет внедрен бин DefaultAnimal

```java
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Primary
```

```kotlin
@Component
@Primary
class DefaultAnimal : Animal {

    override fun speak() {
        println("Default sound!")
    }

}
```

<span id="ImportResource"></span>

**@ImportResource**\
используется для загрузки XML-конфигурации в контекст приложения. Это полезно, если у вас есть существующие XML-файлы конфигурации Spring, которые вы хотите импортировать в конфигурацию, основанную на аннотациях или Java-коде.

**Пример использования:**\
Предположим, у вас есть XML-конфигурация applicationContext.xml:

```xml
<!-- applicationContext.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="exampleBean" class="com.example.ExampleBean">
        <property name="property" value="value"/>
    </bean>
</beans>
```

Теперь вы хотите импортировать эту конфигурацию в ваш Spring Boot или другой Java-базированный конфигурационный класс:

```kotlin
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.ImportResource


@Configuration
@ImportResource("classpath:applicationContext.xml")
class AppConfig {
    // Java-based configuration or bean definitions
}
```

<span id="ComponentScan"></span>

**@ComponentScan**\
используется для автоматического поиска и регистрации бинов (компонентов) в Spring-контейнере. Это включает классы, аннотированные такими аннотациями, как @Component, @Service, @Repository, @Controller, и другими, которые указывают Spring, что эти классы являются бинами, которые необходимо управлять.

```java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan
```

```kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.annotation.ComponentScan


@SpringBootApplication
@ComponentScan(basePackages = [
    "com.example.demo.services",
    "com.example.demo.controllers"
])
class DemoApplication


fun main(args: Array<String>) {
    runApplication<DemoApplication>(*args)
}
```

<span id="Entity"></span>

**@Entity**\
используется в JPA (Java Persistence API) для указания, что класс представляет собой сущность (entity) и сопоставляется с таблицей в реляционной базе данных. Это часть ORM (Object-Relational Mapping), которая позволяет разработчикам работать с базой данных через объектно-ориентированные модели.

**Основные аспекты аннотации @Entity:**

**Класс как сущность:**\
Аннотация @Entity определяет, что данный класс является сущностью и будет сопоставлен с таблицей в базе данных.

**Таблица по умолчанию:**\
Если имя таблицы не указано, оно будет совпадать с именем класса. Однако это можно переопределить с помощью аннотации @Table.

**Идентификационные столбцы:**\
Каждая сущность должна иметь хотя бы одно поле, аннотированное как @Id, чтобы указать первичный ключ.

```kotlin
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.Table
import javax.persistence.Column


@Entity
@Table(name = "users")
data class User(

    @Id
    @Column(name = "user_id")
    val userId: String,


    @Column(name = "email")
    val email: String,


    @Column(name = "username")
    val username: String

)
```

**@Entity**\
Указывает, что класс User является сущностью.

<span id="Table"></span>

**@Table**\
Определяет имя таблицы, с которой будет связана сущность. В данном случае, таблица называется users.

<span id="Id"></span>

**@Id**\
Обозначает первичный ключ сущности.

<span id="Column"></span>

**@Column**\
Указывает имя столбца в таблице, который будет сопоставлен с полем userId.

<span id="GeneratedValue"></span>

**@GeneratedValue**\
Используется для указания стратегии генерации значений для первичного ключа (например, автоинкремент).

<span id="OneToMany-ManyToOne-OneToOne-ManyToMany"></span>

**@OneToMany, @ManyToOne, @OneToOne, @ManyToMany**\
Определяют отношения между сущностями.

**Пример с отношениями:**

```kotlin
import javax.persistence.*


@Entity
@Table(name = "users")
data class User(

    @Id
    @Column(name = "user_id")
    val userId: String,


    @Column(name = "email")
    val email: String,


    @Column(name = "username")
    val username: String,


    @OneToMany(mappedBy = "user")
    val orders: List<Order>

)


@Entity
@Table(name = "orders")
data class Order(

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "order_id")
    val orderId: Long,


    @ManyToOne
    @JoinColumn(name = "user_id")
    val user: User,


    @Column(name = "product")
    val product: String

)
```

<span id="EntityScan"></span>

**@EntityScan**\
используется для указания Spring, где искать JPA-сущности (классы, аннотированные @Entity). Это необходимо, когда сущности расположены вне стандартного пути сканирования Spring Boot, или если вы хотите указать другой пакет для сканирования сущностей.

```java
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({EntityScanPackages.Registrar.class})
public @interface EntityScan
```

```kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.domain.EntityScan


@SpringBootApplication
@EntityScan(basePackages = ["com.example.demo.entities"])
class DemoApplication


fun main(args: Array<String>) {
    runApplication<DemoApplication>(*args)
}
```

<span id="Document-в-MongoDB"></span>

**@Document в MongoDB**\
используется в Spring Data MongoDB для указания того, что класс представляет собой документ в коллекции MongoDB. Это эквивалент аннотации @Entity в JPA для реляционных баз данных. Аннотация @Document определяет, что данный класс будет отображаться на коллекцию в базе данных MongoDB.

**Основные атрибуты аннотации @Document:**

**collection:**\
Имя коллекции в MongoDB, с которой связан документ. Если не указано, имя коллекции будет совпадать с именем класса, но приведенным к нижнему регистру.

**language:**\
Указывает язык для полнотекстового поиска (опционально).

```kotlin
import org.springframework.data.annotation.Id
import org.springframework.data.mongodb.core.mapping.Document


@Document(collection = "users")
data class User(
    @Id
    val id: String? = null,
    val email: String,
    val username: String,
)
```

**@Document(collection = “users”):**\
Указывает, что класс User сопоставляется с коллекцией users в базе данных MongoDB.

**@Id**\
Обозначает идентификатор документа. В MongoDB это поле обычно называется _id.

**Дополнительные аннотации и атрибуты:**

**@Field**\
Используется для указания имени поля в документе MongoDB, если оно отличается от имени поля в классе.

**@Indexed**\
Создает индекс на поле.

**@CompoundIndex**\
Создает составной индекс на несколько полей.

**@GeoSpatialIndexed**\
Создает геопространственный индекс на поле.

```kotlin
import org.springframework.data.annotation.Id
import org.springframework.data.mongodb.core.index.Indexed
import org.springframework.data.mongodb.core.mapping.Document
import org.springframework.data.mongodb.core.mapping.Field


@Document(collection = "users")
data class User(

    @Id
    val id: String? = null,


    @Field("email")
    @Indexed(unique = true)
    val email: String,


    @Field("username")
    val username: String

)
```

**@Field(“email”):**\
Указывает, что поле email в классе User соответствует полю email в документе MongoDB.

**@Indexed(unique = true):**\
Создает уникальный индекс на поле email, что предотвращает наличие дублирующихся значений.

<span id="Document-в-Elasticsearch"></span>

**@Document в Elasticsearch**\
используется в Spring Data Elasticsearch для указания, что класс представляет собой документ в индексе Elasticsearch. Эта аннотация позволяет настроить индекс и его свойства, такие как имя, настройки шардирования и репликации, и некоторые другие параметры.

**Основные атрибуты аннотации @Document:**

**indexName:**\
Указывает имя индекса, в котором будет храниться документ.

**shards:**\
Указывает количество шардов (по умолчанию 5).

**replicas:**\
Указывает количество реплик (по умолчанию 1).

**refreshInterval:**\
Указывает интервал обновления индекса.

**indexStoreType:**\
Указывает тип хранилища индекса (например, “fs” или “memory”).

```kotlin
import org.springframework.data.annotation.Id
import org.springframework.data.elasticsearch.annotations.Document


@Document(
  indexName = "users",
  shards = 3,
  replicas = 2
)
data class User(
    @Id
    val id: String? = null,
    val email: String,
    val username: String
)
```

**indexName:**\
Имя индекса Elasticsearch, в котором будет храниться документ (users).

**shards:**\
Количество шардов (3).

**replicas:**\
Количество реплик (2).

**@Table**\
используется в Spring Data для обозначения того, что класс представляет собой сущность базы данных и сопоставляется с таблицей в базе данных. В контексте Spring Data Cassandra эта аннотация используется для указания, что класс будет отображаться на таблицу в базе данных Cassandra.

**Основные атрибуты аннотации @Table:**

**value:**\
Имя таблицы в базе данных. Если не указано, имя таблицы будет совпадать с именем класса.

**forceQuote:**\
Указывает, должны ли имена таблиц и столбцов заключаться в кавычки.

```kotlin
import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn
import org.springframework.data.cassandra.core.mapping.Table
import org.springframework.data.cassandra.core.cql.PrimaryKeyType
import org.springframework.data.cassandra.core.cql.Ordering


@Table("users")
data class User(

    @PrimaryKeyColumn(
      name = "user_id",
      type = PrimaryKeyType.PARTITIONED
    )
    val userId: String,

    @PrimaryKeyColumn(
      name = "region",
      type = PrimaryKeyType.PARTITIONED
    )
    val region: String,

    @PrimaryKeyColumn(
      name = "email",
      ordinal = 0,
      type = PrimaryKeyType.CLUSTERED,
      ordering = Ordering.ASCENDING
    )
    val email: String,

    @PrimaryKeyColumn(
      name = "username",
      ordinal = 1,
      type = PrimaryKeyType.CLUSTERED,
      ordering = Ordering.ASCENDING
    )
    val username: String

)
```

**@Table(“users”):**\
Указывает, что класс User сопоставляется с таблицей users в базе данных Cassandra.

**@PrimaryKeyColumn:**\
Указывает, какие столбцы являются частью первичного ключа.

**Полное описание:**

**Класс:**\
Класс User является сущностью, которая будет сопоставлена с таблицей users в базе данных Cassandra.

**Аннотация @Table:**\
Указывает имя таблицы, с которой связан класс. Если имя таблицы не указано, используется имя класса.

**Аннотация @PrimaryKeyColumn:**\
Определяет столбцы первичного ключа в таблице. В данном случае, userId и region являются составными разделяющими ключами, а email и username являются кластерными ключами с порядком сортировки по возрастанию.

<span id="PrimaryKeyColumn"></span>

**@PrimaryKeyColumn**\
используется в Spring Data Cassandra для определения столбцов первичного ключа в таблицах Cassandra. Она является частью API, которое помогает разработчикам взаимодействовать с базой данных Cassandra более удобно и эффективно. Эта аннотация позволяет явно указать, какие столбцы должны быть частью первичного ключа и как они должны быть обработаны.

**Основные атрибуты аннотации @PrimaryKeyColumn:**

**name:**\
Имя столбца в таблице.

**type:**\
Тип столбца первичного ключа (partitioned, clustered).

**ordinal:**\
Порядковый номер столбца первичного ключа.

**ordering:**\
Порядок сортировки для кластерных столбцов (ASC или DESC).

```kotlin
import org.springframework.data.cassandra.core.cql.PrimaryKeyType
import org.springframework.data.cassandra.core.cql.Ordering
import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn
import org.springframework.data.cassandra.core.mapping.Table


@Table
data class User(

    @PrimaryKeyColumn(
      name = "user_id",
      type = PrimaryKeyType.PARTITIONED
    )
    val userId: String,


    @PrimaryKeyColumn(
      name = "region",
      type = PrimaryKeyType.PARTITIONED
    )
    val region: String,


    @PrimaryKeyColumn(
      name = "email",
      ordinal = 0,
      type = PrimaryKeyType.CLUSTERED,
      ordering = Ordering.ASCENDING
    )
    val email: String,


    @PrimaryKeyColumn(
      name = "username",
      ordinal = 1,
      type = PrimaryKeyType.CLUSTERED,
      ordering = Ordering.ASCENDING
    )
    val username: String

)
```

**name: name = “user_id”**\
задает имя столбца в таблице, которое соответствует полю userId.

**type: type = PrimaryKeyType.PARTITIONED**\
указывает, что столбец userId является разделяющим ключом (partition key).

**ordinal: ordinal = 0**\
задает порядок столбца в составе кластерного ключа.

**ordering: ordering = Ordering.ASCENDING**\
указывает порядок сортировки для кластерного столбца.

**Типы столбцов первичного ключа:**

**PARTITIONED:**\
Разделяющий ключ (partition key) определяет, на каком узле будет храниться строка. Разделяющий ключ может состоять из одного или нескольких столбцов.

**CLUSTERED:**\
Кластерный ключ (clustering key) определяет порядок строк внутри одного раздела.

<span id="Unwrapped"></span>

**@Unwrapped**\
В контексте Spring Data MongoDB и других реализаций Spring Data, аннотация @Unwrapped используется для указания, что атрибуты вложенного объекта должны быть развернуты (или "раскрыты") и сохранены как отдельные поля в родительском документе вместо того, чтобы сохранять вложенный объект как поддокумент.\
Это может быть полезно, когда вам нужно, чтобы атрибуты вложенного объекта хранились на том же уровне, что и атрибуты родительского объекта, что позволяет упростить структуру хранения данных.

```kotlin
import org.springframework.data.annotation.Id
import org.springframework.data.mongodb.core.mapping.Document
import org.springframework.data.mongodb.core.mapping.Unwrapped


@Document(collection = "users")
data class User(

    @Id
    val id: String? = null,

    val name: String,


    @Unwrapped(prefix = "address_")
    val address: Address

)
```

**User:**\
Основной документ, аннотированный как @Document для хранения в коллекции users.

**Address:**\
Вложенный объект.

<span id="Unwrapped-prefix-address"></span>

**@Unwrapped(prefix = “address_”)**\
Атрибуты объекта Address будут развернуты и сохранены в документе User как отдельные поля с префиксом address_.

<span id="QueryIndexed"></span>

**@QueryIndexed**\
используется в Spring Data для обозначения поля как индексируемого. Эта аннотация применяется в основном в контексте Spring Data для MongoDB и позволяет указывать, что определенное поле должно быть проиндексировано для улучшения производительности поиска.

**Применение аннотации @QueryIndexed в Spring Data MongoDB:**

Когда поле аннотировано как @QueryIndexed, это указывает MongoDB создать индекс для этого поля. Индексация помогает ускорить операции поиска по этому полю, что особенно полезно для полей, которые часто используются в запросах.

```kotlin
import org.springframework.data.annotation.Id
import org.springframework.data.mongodb.core.index.QueryIndexed
import org.springframework.data.mongodb.core.mapping.Document


@Document(collection = "users")
data class User(

    @Id
    val id: String? = null,


    @QueryIndexed
    val email: String,


    val username: String

)
```

**@Document(collection = “users”):**\
Определяет, что класс User представляет собой документ в коллекции users MongoDB.

**@Id:**\
Обозначает поле id как идентификатор документа.

**@QueryIndexed**\
Указывает, что поле email должно быть проиндексировано для ускорения операций поиска по этому полю.

<span id="PreAuthorize"></span>

**@PreAuthorize**\
в Spring Security используется для ограничения доступа к методам на основе выражений SpEL (Spring Expression Language). Она позволяет задать условия, при которых доступ к методу будет разрешен или запрещен.

**Основные возможности @PreAuthorize:**

**Проверка ролей и привилегий:**\
Проверяет, имеет ли текущий пользователь необходимые роли или привилегии для выполнения метода.

**Проверка атрибутов:**\
Позволяет проверять различные атрибуты текущего пользователя, такие как имя пользователя, email и т.д.

**Использование SpEL:**\
Позволяет использовать выражения SpEL для создания сложных логических условий.

```java
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface PreAuthorize
```

**Пример использования @PreAuthorize:**\
Рассмотрим пример использования @PreAuthorize для ограничения доступа к методам на основе ролей.\
Создание сервиса с ограничением доступа. В этом примере метод adminMethod доступен только пользователям с ролью ADMIN, метод userMethod доступен только пользователям с ролью USER, а метод userOrAdminMethod доступен как пользователям с ролью USER, так и пользователям с ролью ADMIN.

```kotlin
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.stereotype.Service


@Service
class UserService {


    @PreAuthorize("hasRole('ADMIN')")
    fun adminMethod() {
        println("Admin method accessed")
    }


    @PreAuthorize("hasRole('USER')")
    fun userMethod() {
        println("User method accessed")
    }


    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    fun userOrAdminMethod() {
        println("User or Admin method accessed")
    }


}
```

**Включение аннотаций безопасности:**\
Чтобы @PreAuthorize работала, необходимо включить аннотации метода безопасности в конфигурации безопасности.

```kotlin
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
class SecurityConfig : WebSecurityConfigurerAdapter() {}
```

<span id="DataMongoTest"></span>

**@DataMongoTest**\
используется для тестирования MongoDB репозиториев. Она фокусируется на конфигурации компонентов Spring Data MongoDB и обеспечивает быстрый тестовый контекст, исключая из него все лишние зависимости, не относящиеся к тестированию работы с данными.

<span id="DynamicPropertySource"></span>

**@DynamicPropertySource**\
используется для динамического добавления свойств в Environment контекста приложения во время выполнения тестов. Это особенно полезно в интеграционных тестах, где необходимо настроить свойства, такие как URL базы данных, учетные данные или другие параметры, которые могут зависеть от внешних ресурсов, таких как Docker-контейнеры, поднятые с помощью Testcontainers.

```kotlin
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.DynamicPropertyRegistry
import org.springframework.test.context.DynamicPropertySource
import org.springframework.test.context.junit.jupiter.SpringExtension
import org.testcontainers.containers.PostgreSQLContainer
import org.testcontainers.junit.jupiter.Container
import org.testcontainers.junit.jupiter.Testcontainers


@ExtendWith(SpringExtension::class)
@SpringBootTest
@Testcontainers
class UserServiceTest {

    @Autowired
    private lateinit var userService: UserService

    companion object {

        @Container
        val postgreSQLContainer = PostgreSQLContainer<Nothing>(
          "postgres:latest"
        ).apply {
            withDatabaseName("testdb")
            withUsername("test")
            withPassword("test")
        }

        @JvmStatic
        @DynamicPropertySource
        fun registerPgProperties(
          registry: DynamicPropertyRegistry
        ) {
            registry.add(
              "spring.datasource.url",
              postgreSQLContainer::getJdbcUrl
            )
            registry.add(
              "spring.datasource.username",
              postgreSQLContainer::getUsername
            )
            registry.add(
              "spring.datasource.password",
              postgreSQLContainer::getPassword
            )
        }

    }

    @Test
    fun `test createUser`() {
        val user = User(
          email = "test@example.com",
          username = "testuser"
        )
        val savedUser = userService.createUser(user)
        assertNotNull(savedUser.id)
        assertEquals(
          "test@example.com",
          savedUser.email
        )
        assertEquals(
          "testuser",
          savedUser.username
        )
    }

    @Test
    fun `test getAllUsers`() {
        val user1 = User(
          email = "test1@example.com",
          username = "testuser1"
        )
        val user2 = User(
          email = "test2@example.com",
          username = "testuser2"
        )
        userService.createUser(user1)
        userService.createUser(user2)
        val users = userService.getAllUsers()
        assertEquals(2, users.size)
    }

}
```

<span id="Testcontainers"></span>

**@Testcontainers**\
Аннотация, обозначающая, что этот класс теста использует Testcontainers для управления жизненным циклом контейнеров.

<span id="Container"></span>

@Container\
Обозначает контейнер, который будет автоматически управляться Testcontainers.

**@DynamicPropertySource**\
Статический метод, аннотированный @DynamicPropertySource, используется для регистрации динамических свойств в контексте теста.

В данном примере метод registerPgProperties добавляет свойства, такие как URL базы данных, имя пользователя и пароль, которые извлекаются из контейнера PostgreSQL.

<span id="BeforeEach"></span>

**@BeforeEach**\
аннотация из библиотеки JUnit 5, которая указывает, что аннотированный метод должен выполняться перед каждым тестовым методом в текущем классе тестов. Это полезно для настройки условий или инициализации данных, необходимых для каждого теста.

**@Embedded и @Embeddable**\
в JPA (Java Persistence API) используется для указания того, что класс представляет собой встраиваемый компонент, который может быть включен в другие сущности. Встраиваемые компоненты позволяют повторно использовать поля и логику в нескольких сущностях без дублирования кода.

```kotlin
import javax.persistence.Embeddable


@Embeddable
data class Address(
    val street: String,
    val city: String,
    val country: String
)
```

```kotlin
import javax.persistence.*


@Entity
data class User(

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long? = null,

    val name: String,

    @Embedded
    val address: Address
)
```

<span id="Embeddable"></span>

**@Embeddable**\
указывает, что класс Address может быть встраиваемым компонентом в других сущностях.

<span id="Embedded"></span>

**@Embedded**\
используется в сущности User для указания, что объект Address должен быть включен как составная часть User.

<span id="Secured"></span>

**@Secured**\
в Spring Security используется для ограничения доступа к методам на основе ролей. В отличие от аннотации @PreAuthorize, которая использует выражения SpEL (Spring Expression Language) для проверки условий, @Secured ограничивается только проверкой ролей. Эта аннотация является более простой и удобной, если нужно просто проверять наличие определенных ролей у пользователя.

**Основные возможности @Secured:**

**Проверка ролей:**\
Позволяет указать, какие роли необходимы для доступа к методу.

**Простота использования:**\
Используется для простой проверки наличия одной или нескольких ролей у пользователя.

```java
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Secured
```

**Пример использования @Secured:**

Рассмотрим пример использования @Secured для ограничения доступа к методам на основе ролей.\
Включение поддержки аннотаций безопасност\
Чтобы @Secured работала, необходимо включить поддержку аннотаций метода безопасности в конфигурации безопасности.

```kotlin
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
class SecurityConfig : WebSecurityConfigurerAdapter() {}
```

**Создание сервиса с ограничением доступа:**\
В этом примере метод adminMethod доступен только пользователям с ролью ADMIN, метод userMethod доступен только пользователям с ролью USER, а метод userOrAdminMethod доступен как пользователям с ролью USER, так и пользователям с ролью ADMIN.

```kotlin
import org.springframework.security.access.annotation.Secured
import org.springframework.stereotype.Service


@Service
class UserService {
    @Secured("ROLE_ADMIN")
    fun adminMethod() {
        println("Admin method accessed")
    }

    @Secured("ROLE_USER")
    fun userMethod() {
        println("User method accessed")
    }

    @Secured("ROLE_USER", "ROLE_ADMIN")
    fun userOrAdminMethod() {
        println("User or Admin method accessed")
    }

}
```

**Различия между @PreAuthorize и @Secured:**\
Аннотации @PreAuthorize и @Secured в Spring Security имеют схожую цель — ограничивать доступ к методам на основе условий безопасности. Однако они различаются по функциональности, гибкости и способу использования.

**@Secured**\
Простота использования: @Secured используется для проверки наличия одной или нескольких ролей у текущего пользователя.\
Поддержка ролей: Проверяет только роли и не поддерживает более сложные условия.\
Меньше возможностей: Поддерживает только простые проверки ролей, что делает её менее гибкой.\
Анотации: Работает с простыми списками строковых значений, представляющих роли.

<span id="PreAuthorize"></span>

**@PreAuthorize**\
Гибкость: @PreAuthorize использует выражения SpEL (Spring Expression Language) для проверки условий безопасности, что делает её более гибкой.\
Поддержка сложных условий: Может проверять не только роли, но и другие атрибуты, такие как имя пользователя, параметры метода и т.д.\
Широкие возможности: Поддерживает сложные логические выражения и позволяет проверять различные атрибуты безопасности.\
Способность к настройке: Может использоваться для настройки более сложных условий доступа.

<span id="Column-в-JPA"></span>

**@Column в JPA**\
используется в Java Persistence API (JPA) для указания отображения поля сущности на столбец таблицы в базе данных. Эта аннотация предоставляет гибкость в конфигурировании соответствия полей класса и столбцов базы данных, позволяя указать имя столбца, его тип, ограничение на уникальность и другие атрибуты.

**Основные атрибуты аннотации @Column:**

**name:**\
Имя столбца в таблице. Если не указано, используется имя поля.

**nullable:**\
Указывает, может ли столбец содержать NULL значения. По умолчанию true.

**unique:**\
Указывает, должно ли значение столбца быть уникальным. По умолчанию false.

**length:**\
Длина столбца. Применимо только к строковым типам данных. По умолчанию 255.

**precision:**\
Точность для числовых столбцов (общее количество цифр). Применимо к типам BigDecimal и BigInteger.

**scale:**\
Масштаб для числовых столбцов (количество цифр после запятой). Применимо к типам BigDecimal и BigInteger.

**insertable:**\
Указывает, должен ли столбец участвовать в SQL-операциях вставки. По умолчанию true.

**updatable:**\
Указывает, должен ли столбец участвовать в SQL-операциях обновления. По умолчанию true.

**columnDefinition:**\
SQL выражение, которое определяет тип данных столбца.

**table:**\
Имя таблицы, если оно отличается от таблицы по умолчанию.

```java
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column
```

```kotlin
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id


@Entity
data class Person(

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    val id: Long? = null,

    @Column(name = "person_name", nullable = false, length = 100)
    val name: String,

    @Column(name = "person_age", nullable = false)
    val age: Int,

    @Column(name = "email", unique = true, length = 150)
    val email: String?

)
```

Поле name отображается на столбец person_name, который не может быть NULL и имеет максимальную длину 100 символов.\
Поле age отображается на столбец person_age, который не может быть NULL.\
Поле email отображается на столбец email, который должен быть уникальным и имеет максимальную длину 150 символов.

<span id="PostConstruct"></span>

**@PostConstruct**\
это аннотация, предоставляемая пакетом javax.annotation, которая используется для обозначения метода, который должен быть выполнен после завершения инициализации зависимостей бина и до того, как бин будет доступен для использования.

```java
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface PostConstruct
```

```kotlin
import org.springframework.stereotype.Service
import javax.annotation.PostConstruct


@Service
class ExampleService {

    private lateinit var someData: String

    @PostConstruct
    fun init() {
        // Инициализация данных после создания бина
        someData = "Инициализированные данные"
        println("ExampleService инициализирован с данными: $someData")
    }

    fun getData(): String {
        return someData
    }

}
```

<span id="PreDestroy"></span>

**@PreDestroy**\
аннотация из Java Specification Request (JSR) 250, которая используется в Java EE и Spring для указания метода, который должен быть выполнен перед уничтожением бина. Эта аннотация обычно применяется к методу, который выполняет операции очистки, такие как освобождение ресурсов, закрытие соединений и другие завершающие действия.

**Пример использования @PreDestroy в Spring:**

В Spring, бины могут управляться контейнером Spring, и иногда необходимо выполнить некоторые действия перед уничтожением бина. Это может быть полезно для завершения соединений с базой данных, закрытия файловых потоков и других операций очистки.

```kotlin
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration


@Configuration
class AppConfig {

    @Bean
    fun exampleBean(): ExampleBean {
        return ExampleBean()
    }

}
```

```kotlin
import javax.annotation.PreDestroy


class ExampleBean {

    fun start() {
        println("Bean is starting")
    }

    @PreDestroy
    fun cleanup() {
        println("Bean is being destroyed")
        // Здесь можно освободить ресурсы
    }

}
```

```kotlin
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.ConfigurableApplicationContext


@SpringBootApplication
class Application


fun main(args: Array<String>) {
    val context: ConfigurableApplicationContext = SpringApplication.run(Application::class.java, *args)
    val bean = context.getBean(ExampleBean::class.java)
    bean.start()
    // Приложение закрывается и Spring вызывает метод cleanup()
    context.close()
}
```

**Как это работает:**

**Инициализация:** \
Когда Spring контейнер создает бин ExampleBean, он вызывает метод start, если это предусмотрено в коде.

**Уничтожение:** \
Когда приложение закрывается (например, при вызове context.close()), Spring контейнер вызывает метод cleanup, помеченный аннотацией @PreDestroy.

**Важные замечания:**\
Метод, помеченный @PreDestroy, не должен принимать аргументов и не должен возвращать значение.\
Он должен быть публичным или защищенным, чтобы быть доступным контейнеру Spring.\
Аннотация @PreDestroy может использоваться как с компонентами Spring, так и с бинами, определенными в конфигурационных файлах.

**@EnableJdbcRepositories**\
Используется в Spring Data для включения поддержки репозиториев JDBC. Она автоматически настраивает инфраструктуру Spring Data JDBC и сканирует пакет на наличие интерфейсов репозиториев, которые будут превращены в реализации на основе JDBC.

**Основные функции @EnableJdbcRepositories:**

**Автоматическая настройка репозиториев JDBC:**\
Включает механизм репозиториев Spring Data JDBC. Автоматически настраивает необходимые бины для работы с JDBC.

**Сканирование пакетов:**\
Сканирует указанные пакеты на наличие интерфейсов репозиториев и создает их реализации.

**Настройка бинов инфраструктуры:**\
Настраивает JdbcTemplate, DataSource и другие необходимые компоненты для работы с базой данных.

**@Transient**\
используется в контексте Java и некоторых фреймворков для указания, что определенное поле не должно быть сериализовано или сохранено в базу данных. Она может применяться в разных контекстах, таких как JPA (Java Persistence API) и стандартная сериализация Java. Рассмотрим подробнее использование этой аннотации в каждом из этих контекстов.

<span id="Transient-в-JPA"></span>

**@Transient в JPA**\
В JPA аннотация @Transient указывает, что поле не должно быть персистентным, то есть не должно сохраняться в базу данных. Это полезно для временных или вычисляемых полей, которые не требуют хранения в базе данных.

<span id="Transient-в-стандартной-сериализации-Java"></span>

**@Transient в стандартной сериализации Java**\
В контексте стандартной сериализации Java аннотация @Transient указывает, что поле не должно быть сериализовано, когда объект сериализуется.

<span id="MappedCollection"></span>

**@MappedCollection**\
используется в Spring Data JDBC для обозначения коллекции связанных сущностей в основной сущности. Она позволяет указывать, что поле в основной сущности должно быть отображено на соответствующие записи в связанной таблице. Это полезно для моделирования отношений “один-ко-многим” и “многие-ко-многим” в базах данных с использованием Spring Data JDBC.

**Основные особенности @MappedCollection:**

**Коллекции связанных сущностей:**\
Указывает, что поле является коллекцией связанных сущностей.

**Поддержка сложных структур данных:**\
Позволяет легко работать с коллекциями внутри основной сущности.

**Сопоставление с внешними ключами:**\
Автоматически управляет внешними ключами для связанных сущностей.

```kotlin
import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.MappedCollection
import org.springframework.data.relational.core.mapping.Table


@Table("users")
data class User(
    @Id
    val id: Long? = null,
    val email: String,
    val username: String,
    @MappedCollection(idColumn = "user_id")
    val addresses: List<Address> = listOf()
)


@Table("addresses")
data class Address(
    val street: String,
    val city: String,
    val country: String
)
```

**User:**\
Основная сущность, аннотированная @Table(“users”).

**Address:**\
Связанная сущность, аннотированная @Table(“addresses”).

**@MappedCollection**\
Указывает, что addresses является коллекцией связанных сущностей Address. Атрибут idColumn указывает на столбец внешнего ключа в таблице addresses

<span id="PayloadRoot"></span>

**@PayloadRoot**\
используется в Spring Web Services для определения метода-обработчика в классе, который будет обрабатывать входящие SOAP-сообщения с определенным корневым элементом в теле (payload) сообщения

<span id="Endpoint"></span>

**@Endpoint**\
используется для обозначения класса как Spring Web Service Endpoint (конечная точка веб-сервиса)

<span id="RequestPayload"></span>

**@RequestPayload**\
указывает, что параметр метода (request) должен быть привязан к телу входящего SOAP-запроса

<span id="ResponsePayload"></span>

**@ResponsePayload**\
Аннотация указывает, что возвращаемое значение метода должно быть преобразовано в тело SOAP-ответа

<span id="XmlRootElement"></span>

**@XmlRootElement**\
используется для указания, что класс представляет собой корневой элемент XML-документа. Эта аннотация применяется в контексте Java Architecture for XML Binding (JAXB) и позволяет объекту быть маршалированным (преобразованным в XML) и демаршалированным (преобразованным из XML) как корневой элемент\
В контексте Spring Web Services @XmlRootElement используется для аннотирования классов, которые будут автоматически маршалироваться и демаршалироваться в качестве XML сообщений.

**Основные аспекты @XmlRootElement:**

**Пространство имен (namespace):**\
Пространство имен XML (namespace) может быть указано с помощью атрибута namespace.

**Локальное имя (name):**\
Локальное имя корневого элемента может быть указано с помощью атрибута name.

```xml
<HelloRequest xmlns="http://example.com/helloworld">
    <name>John</name>
</HelloRequest>
```

```kotlin
import javax.xml.bind.annotation.XmlRootElement


@XmlRootElement(
    namespace = "http://example.com/helloworld",
    name = "HelloRequest"
)
data class HelloRequest(
  var name: String = ""
)
```

<span id="SpringBootApplication"></span>

**@SpringBootApplication**\
является комбинацией трех аннотаций: @Configuration, @EnableAutoConfiguration и @ComponentScan. Она обычно используется для обозначения основного класса конфигурации приложения Spring Boot.\
Рекомендуется иметь только один класс с аннотацией @SpringBootApplication, который будет главным классом конфигурации для всего приложения. Если необходимо разделить конфигурацию на несколько частей, лучше использовать другие аннотации, такие как @Configuration, для создания отдельных конфигурационных классов

```kotlin
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication
```

```kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication


@SpringBootApplication
class DemoApplication

fun main(args: Array<String>) {
    runApplication<DemoApplication>(*args)
```

Также- application.properties

```properties
my.property=Hello, Spring!
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.jpa.hibernate.ddl-auto=update
```

## Чем @Component отличается от @Service {#Чем-Component-отличается-от-Service}

В Spring Framework, аннотации @Component и @Service используются для обозначения классов в качестве бинов Spring. Хотя технически они функционируют одинаково и имеют одинаковую роль в процессе создания и управления бинами, их использование связано с различными семантическими значениями, что помогает лучше организовать и документировать ваш код. Вот основные различия:

**@Component:**\
Используется для общего назначения, когда класс не подходит под другие специализированные аннотации (@Service, @Repository, @Controller).

**@Service:**\
Используется для сервисных классов, которые содержат бизнес-логику.

**Чтение и поддержка кода:**\
Использование специализированных аннотаций, таких как @Service, помогает лучше организовать код и сделать его более понятным для других разработчиков. Они сразу понимают, что этот класс используется для бизнес-логики.

**Применение аспектов (AOP):**\
В некоторых случаях специализированные аннотации, такие как @Service, могут быть использованы для применения аспектов (AOP) более специфичным образом.

## Чем @Component отличается от @Bean {#Чем-Component-отличается-от-Bean}

@Component и @Bean — это два различных способа определения бинов (компонентов) в Spring, но они используются в разных контекстах и имеют свои особенности.

**@Component:**\
аннотация, которая используется для маркировки класса как компонента Spring.

Используется в сочетании с механизмом сканирования классов (component scanning). Spring автоматически обнаруживает классы, аннотированные как @Component, и регистрирует их как бины в контексте приложения.

Также существуют специализированные версии @Component, такие как @Service, @Repository, и @Controller, которые делают то же самое, но добавляют семантическое значение для разработчиков и инструментария.

```kotlin
import org.springframework.stereotype.Component


@Component
class MyComponent {

    fun doSomething() {
        println("Doing something")
    }

}
```

**Использование @Component и @Autowired:**

```kotlin
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
import org.springframework.stereotype.Service


@Component
class MyComponent {

    fun doSomething() {
        println("Doing something")
    }

}


@Service
class MyService(@Autowired private val myComponent: MyComponent) {

    fun serve() {
        myComponent.doSomething()
    }

}
```

**@Bean:**\
аннотация, которая используется для определения метода, который возвращает объект, который должен быть зарегистрирован как бин в контексте Spring.

Обычно используется в конфигурационных классах, аннотированных как @Configuration.

Позволяет явным образом создать и настроить бин с определенными параметрами или логикой инициализации.

```kotlin
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration


@Configuration
class MyConfig {

    @Bean
    fun myBean(): MyBean {
        return MyBean()
    }

}


class MyBean {

    fun doSomething() {
        println("Doing something")
    }

}
```

**Использование @Bean в конфигурационном классе:**

```kotlin
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration


class MyBean {

    fun doSomething() {
        println("Doing something")
    }

}


class MyService(
  private val myBean: MyBean
) {

    fun serve() {
        myBean.doSomething()
    }

}


@Configuration
class MyConfig {

    @Bean
    fun myBean(): MyBean {
        return MyBean()
    }

    @Bean
    fun myService(myBean: MyBean): MyService {
        return MyService(myBean)
    }

}

```

**Сравнение @Component и @Bean:**

**Механизм:**

**@Component:**\
используется в сочетании с механизмом сканирования классов (component scanning). Это означает, что Spring автоматически обнаруживает классы, аннотированные @Component, и регистрирует их как бины в контексте приложения.

**@Bean:**\
используется для определения метода, который возвращает объект, который должен быть зарегистрирован как бин в контексте Spring. Обычно эта аннотация применяется в конфигурационных классах, аннотированных @Configuration.

**Использование:**

**@Component:**\
применяется к классу, чтобы автоматически обнаружить и зарегистрировать его как бин.

**@Bean:**\
используется для создания и настройки бинов через методы, что позволяет более явным образом контролировать процесс создания бинов.

**Контекст:**

Класс, аннотированный @Component, автоматически становится бином в контексте Spring.

Метод в конфигурационном классе, аннотированный @Bean, возвращает объект, который становится бином в контексте Spring.

**Дополнительные аннотации:**

Для @Component существуют специализированные версии, такие как @Service, @Repository, и @Controller. Эти аннотации делают то же самое, что и @Component, но добавляют семантическое значение для разработчиков и инструментария.

Для @Bean нет дополнительных аннотаций, но он используется в контексте конфигурационных классов для явного определения бинов.

Используйте @Component (или его специализированные версии) для классов, которые должны быть автоматически обнаружены и зарегистрированы как бины.

Используйте @Bean для явного определения бинов в конфигурационных классах, особенно когда нужна дополнительная настройка или логика инициализации.

[Copyright: Roman Kryvolapov](https://t.me/RomanKryvolapov)
