---
title: "Java Spring – Анотации на Spring"
url: "https://romankryvolapov.com/bg/java-spring-annotations/"
description: "Справочник на анотациите в Spring с примери на Kotlin: @Component, @Bean, @Transactional, мапинг на заявки, JPA и разликата между @Component и @Bean."
language: bg
published: 2024-07-29
updated: 2026-11-13
---
## Кои са основните анотации в 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**\
се използва за глобална обработка на изключения и за предоставяне на съвети (advice) на контролерите, които работят с 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**\
показва, че методът-съвет (advice) трябва да се изпълни преди извикването на целевия метод. Използва се например за логване на влизането в метода или за проверка на правата за достъп.

<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**\
се използва за настройка на свързващите средства за данни (data binders) на ниво контролер. Те обработват данните, които идват от 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**\
добавя пред url на метода това, което е подадено в нея

```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**\
разрешава междудомейнни (cross-origin) заявки към метод или клас.

```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 са съставни ключове за разделяне (partition key), а 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, не трябва да приема аргументи и не трябва да връща стойност.\
Той трябва да е публичен или защитен (protected), за да е достъпен за контейнера на 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, за създаване на отделни конфигурационни класове

```java
@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)
