---
title: "Java Spring — Анотації Spring"
url: "https://romankryvolapov.com/uk/java-spring-annotations/"
description: "Довідник анотацій Spring з прикладами на Kotlin: @Component, @Bean, @Transactional, мапінг запитів, JPA та різниця між @Component і @Bean."
language: uk
updated: 2026-01-21
---
## Які основні анотації є у 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

У Spring Framework анотації @Component і @Service використовуються для позначення класів як бінів Spring. Хоча технічно вони функціонують однаково і мають однакову роль у процесі створення та керування бінами, їх використання пов'язане з різними семантичними значеннями, що допомагає краще організувати та задокументувати ваш код. Ось основні відмінності:

**@Component:**\
Використовується для загального призначення, коли клас не підходить під інші спеціалізовані анотації (@Service, @Repository, @Controller).

**@Service:**\
Використовується для сервісних класів, які містять бізнес-логіку.

**Читання та підтримка коду:**\
Використання спеціалізованих анотацій, таких як @Service, допомагає краще організувати код і зробити його зрозумілішим для інших розробників. Вони одразу розуміють, що цей клас використовується для бізнес-логіки.

**Застосування аспектів (AOP):**\
У деяких випадках спеціалізовані анотації, такі як @Service, можуть бути використані для застосування аспектів (AOP) специфічнішим чином.

## Чим @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)
