Spring

Spring Boot 어노테이션 완전 정복: 알기 쉬운 상세 설명과 예제

Written by 개발자서동우 · 8 min read >
스프링 부트 어노테이션

안녕하세요! Devloo입니다 🙂 이번 시간에는 Spring Boot에서 많이 사용하는 어노테이션들을 살펴보려고 합니다.

Spring Boot 어노테이션은 Spring 애플리케이션에 대한 정보를 제공하는 메타데이터로, 애플리케이션 설정을 간편하게 해줍니다.

Spring Boot는 모든 기능을 포괄하는 프레임워크로, 설정과 설치의 번거로움을 최소화하여 개발자가 로직에 집중할 수 있도록 도와줍니다. 이러한 특징 덕분에 개발자들 사이에서 빠르게 인기를 얻고 있습니다.

또한, Spring Boot는 마이크로서비스 기반의 프레임워크로, 최소한의 시간과 노력으로 프로덕션 준비가 된 애플리케이션을 만들 수 있게 해줍니다.

Spring Boot의 주요 기능은 다음과 같습니다:

  • Spring에서 흔히 볼 수 있는 복잡한 XML 설정을 피할 수 있습니다.
  • REST 엔드포인트의 유지보수와 생성을 쉽게 할 수 있는 기능을 제공합니다.
  • 내장된 Tomcat 서버를 포함하고 있습니다.
  • WAR 및 JAR 파일을 Tomcat 서버에 쉽게 배포할 수 있어 배포가 매우 간편합니다.

Spring Boot 어노테이션은 주로 org.springframework.boot.autoconfigureorg.springframework.boot.autoconfigure.condition 패키지에 있으며, Spring Boot를 사용할 때 필수적입니다.

>> 목차

주요 Spring Boot 어노테이션 및 사용 예제

1. @SpringBootApplication

이 어노테이션은 Spring Boot 애플리케이션을 시작하는 데 사용됩니다. @Configuration, @EnableAutoConfiguration, @ComponentScan의 세 가지 어노테이션을 결합합니다.

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}
2. @RestController

이 어노테이션은 해당 클래스가 RESTful 컨트롤러임을 나타내며, @Controller@ResponseBody를 결합한 것입니다.

예시:

@RestController
public class MyController {
    @GetMapping("/hello")
    public String hello() {
        return "Hello, World!";
    }
}

Spring 4에서 도입된 이 어노테이션은 컨트롤러 클래스의 각 요청 처리 메서드에 @ResponseBody를 사용하지 않아도 되도록 해줍니다.

한번 비교해 보겠습니다:

@Controller
@RequestMapping("/api/v1")
public class EmployeeController {
    @Autowired
    private EmployeeRepository employeeRepository;

    @GetMapping("/employees")
    public @ResponseBody List<Employee> getAllEmployees() {
        return employeeRepository.findAll();
    }

    @GetMapping("/employees/{id}")
    public @ResponseBody ResponseEntity<Employee> getEmployeeById(@PathVariable(value = "id") Long employeeId)
        throws ResourceNotFoundException {
        Employee employee = employeeRepository.findById(employeeId)
          .orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
        return ResponseEntity.ok().body(employee);
    }

    @PostMapping("/employees")
    public @ResponseBody Employee createEmployee(@Valid @RequestBody Employee employee) {
        return employeeRepository.save(employee);
    }

    @PutMapping("/employees/{id}")
    public @ResponseBody ResponseEntity<Employee> updateEmployee(@PathVariable(value = "id") Long employeeId,
         @Valid @RequestBody Employee employeeDetails) throws ResourceNotFoundException {
        Employee employee = employeeRepository.findById(employeeId)
        .orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));

        employee.setEmailId(employeeDetails.getEmailId());
        employee.setLastName(employeeDetails.getLastName());
        employee.setFirstName(employeeDetails.getFirstName());
        final Employee updatedEmployee = employeeRepository.save(employee);
        return ResponseEntity.ok(updatedEmployee);
    }

    @DeleteMapping("/employees/{id}")
    public @ResponseBody Map<String, Boolean> deleteEmployee(@PathVariable(value = "id") Long employeeId)
         throws ResourceNotFoundException {
        Employee employee = employeeRepository.findById(employeeId)
       .orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));

        employeeRepository.delete(employee);
        Map<String, Boolean> response = new HashMap<>();
        response.put("deleted", Boolean.TRUE);
        return response;
    }
}

이 예제에서는 각 반환 값이 @ResponseBody로 어노테이션되어 있습니다.

위 예제에서 @RestController를 사용하려면 @Controller@RestController로 교체하고 각 메서드의 @ResponseBody를 제거하면 됩니다. 수정된 클래스는 다음과 같습니다:

@RestController
@RequestMapping("/api/v1")
public class EmployeeController {
    @Autowired
    private EmployeeRepository employeeRepository;

    @GetMapping("/employees")
    public List<Employee> getAllEmployees() {
        return employeeRepository.findAll();
    }

    @GetMapping("/employees/{id}")
    public ResponseEntity<Employee> getEmployeeById(@PathVariable(value = "id") Long employeeId)
        throws ResourceNotFoundException {
        Employee employee = employeeRepository.findById(employeeId)
          .orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
        return ResponseEntity.ok().body(employee);
    }

    @PostMapping("/employees")
    public Employee createEmployee(@Valid @RequestBody Employee employee) {
        return employeeRepository.save(employee);
    }

    @PutMapping("/employees/{id}")
    public ResponseEntity<Employee> updateEmployee(@PathVariable(value = "id") Long employeeId,
         @Valid @RequestBody Employee employeeDetails) throws ResourceNotFoundException {
        Employee employee = employeeRepository.findById(employeeId)
        .orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));

        employee.setEmailId(employeeDetails.getEmailId());
        employee.setLastName(employeeDetails.getLastName());
        employee.setFirstName(employeeDetails.getFirstName());
        final Employee updatedEmployee = employeeRepository.save(employee);
        return ResponseEntity.ok(updatedEmployee);
    }

    @DeleteMapping("/employees/{id}")
    public Map<String, Boolean> deleteEmployee(@PathVariable(value = "id") Long employeeId)
         throws ResourceNotFoundException {
        Employee employee = employeeRepository.findById(employeeId)
       .orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));

        employeeRepository.delete(employee);
        Map<String, Boolean> response = new HashMap<>();
        response.put("deleted", Boolean.TRUE);
        return response;
    }
}

이 어노테이션을 사용하면 코드의 가독성이 크게 향상됩니다.

3. @RequestMapping

@RequestMapping 어노테이션은 웹 요청을 특정 핸들러 메서드에 매핑할 때 사용됩니다. 클래스 또는 메서드 수준에서 적용할 수 있습니다.

예시:

@RestController
@RequestMapping("/api")
public class MyController {
    @GetMapping("/hello")
    public String hello() {
        return "Hello, World!";
    }
}
4. @Autowired

@Autowired 어노테이션은 Spring 빈에서 자동으로 의존성을 주입할 때 사용됩니다. 필드, 생성자 또는 메서드에 적용할 수 있습니다.

간단히 말해서, 이 어노테이션은 두 가지 기능을 합니다:

  • 빈을 자동으로 주입합니다.
  • 생성자 주입, 세터 주입, 필드 주입에 사용됩니다.

예시:

@Service
public class MyService {
    private final MyRepository repository;

    @Autowired
    public MyService(MyRepository repository) {
        this.repository = repository;
    }
}

또 다른 예시:

@Autowired
private EmployeeRepository employeeRepository;
5. @Component

@Component 어노테이션은 Spring 프레임워크에서 클래스가 Spring이 관리하는 컴포넌트임을 나타냅니다.

Spring은 이 어노테이션을 통해 해당 클래스를 자동으로 스캔하고 인스턴스화하여 애플리케이션에서 의존성 주입을 통해 사용할 수 있게 합니다.

일반적으로 비즈니스 로직 계층, 데이터 접근 계층, 컨트롤러 등을 나타내며, Spring이 이들의 생명 주기를 관리하고 의존성을 주입할 수 있게 합니다.

예시:

@Component
public class MyComponent {
    // ...
}
6. @Service

@Service 어노테이션은 클래스가 비즈니스 로직을 처리하는 서비스 계층의 Spring 빈임을 나타냅니다.

예시:

@Service
public class MyService {
    // ...
}
7. @Repository

@Repository 어노테이션은 클래스가 데이터베이스 접근을 처리하는 특별한 유형의 Spring 빈임을 나타냅니다.

예시:

import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {

    public void saveUser(User user) {
        // 사용자 정보를 데이터베이스에 저장하는 로직 구현
    }

    public User getUserById(Long id) {
        // ID로 사용자 정보를 데이터베이스에서 조회하는 로직 구현
        return null;
    }

    // 기타 데이터 접근 메서드...
}

이 예시에서 UserRepository 클래스는 @Repository로 어노테이션되어 있으며, 이는 해당 클래스가 사용자 데이터와 관련된 영속성 작업을 수행하는 데이터 접근 컴포넌트임을 나타냅니다.

이 어노테이션은 다소 낯설 수 있지만, @Repository@Controller, @Service, @Component와 마찬가지로 객체가 Spring에 의해 관리되어야 함을 나타냅니다.

@Repository는 데이터 접근 계층 인터페이스에 사용되며, Spring이 관리할 구현 클래스 중 하나를 할당합니다.

이는 MyBatis의 @Mapper와 매우 유사합니다. MyBatis는 컴파일 시점에 해당 매퍼를 찾아 데이터베이스 쿼리 기능을 구현하는 프록시 클래스를 생성해야 합니다.

@Mapper@Repository는 모두 데이터 접근 계층 인터페이스에 사용됩니다.

종종 이 어노테이션이 없어도 오류가 발생하지 않는데, 이는 Spring 설정 파일에 MapperScannerConfigurer 빈이 포함되어 데이터 접근 계층 인터페이스를 스캔하고 Spring이 관리할 구현 클래스를 생성하기 때문입니다.

마찬가지로, 메인 애플리케이션 클래스에 @MapperScan을 추가하면 MapperScannerConfigurer와 동일한 효과를 얻을 수 있습니다.

8. @Configuration

@Configuration 어노테이션은 클래스를 설정 클래스(Configuration Class)로 선언할 때 사용됩니다. 주로 @Bean 어노테이션과 함께 사용됩니다.

예시:

import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.companyname.projectname.customer.CustomerService;
import com.companyname.projectname.order.OrderService;

@Configuration
public class Application {

    @Bean
    public CustomerService customerService() {
        return new CustomerService();
    }

    @Bean
    public OrderService orderService() {
        return new OrderService();
    }
}

AppConfig 클래스는 다음 Spring XML과 동일합니다:

<beans>
    <bean id="customerService" class="com.companyname.projectname.CustomerService"/>
    <bean id="orderService" class="com.companyname.projectname.OrderService"/>
</beans>

이 어노테이션은 주로 Swagger나 MyBatis와 같은 설정에 사용됩니다.

9. @Value

@Value 어노테이션은 프로퍼티 파일이나 다른 소스에서 값을 가져와 Spring 빈에 주입할 때 사용됩니다.

예시:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class MyComponent {

    @Value("${my.property}")
    private String myProperty;

    public void displayPropertyValue() {
        System.out.println("The value of my.property is: " + myProperty);
    }
}

이 예시에서 @Value("${my.property}")는 Spring 프로퍼티의 값을 myProperty 필드에 주입합니다. 애플리케이션의 설정 파일에 “my.property”라는 프로퍼티가 있다면, 그 값이 myProperty 필드에 주입됩니다. 이 어노테이션은 코드 생성기에서 값을 하드코딩하지 않도록 자주 사용됩니다.

10. @EnableAutoConfiguration

@EnableAutoConfiguration 어노테이션은 Spring Boot의 자동 설정 메커니즘을 활성화합니다. 클래스패스 종속성과 프로퍼티를 기반으로 애플리케이션을 설정합니다.

예시:

@SpringBootApplication
@EnableAutoConfiguration
public class MyApplication {
    // ...
}

@EnableAutoConfiguration을 사용하면:

  • Spring Boot가 프로젝트의 종속성과 설정을 기반으로 다양한 애플리케이션 구성 요소를 자동으로 설정합니다.
  • MyService 클래스가 자동으로 스캔되고 Spring 컨테이너에 의해 관리됩니다.

@EnableAutoConfiguration이 없으면:

  • 개발자가 다양한 애플리케이션 구성 요소를 수동으로 설정해야 하므로 개발 부담이 증가합니다.
  • MyService 클래스는 자동으로 스캔되지 않으며, Spring 컨테이너 관리에 명시적으로 구성해야 합니다.

특정 자동 설정 클래스를 제외하려면, @EnableAutoConfigurationexclude 속성을 사용할 수 있습니다:

예시:

@EnableAutoConfiguration(excludeName = {
    "org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration",
    "org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"
})
11. @GetMapping, @PostMapping, @PutMapping, @DeleteMapping

이 어노테이션들은 특정 HTTP 메서드를 핸들러 메서드에 매핑할 때 사용됩니다. 해당 HTTP 메서드의 단축키입니다.

예시:

@RestController
@RequestMapping("/api")
public class MyController {
    @GetMapping("/hello")
    public String hello() {
        return "Hello, World!";
    }

    @PostMapping("/data")
    public void saveData(@RequestBody Data data) {
        // Save data
    }
}
12. @PathVariable

@PathVariable 어노테이션은 메서드 매개변수를 URL 경로 변수에 바인딩할 때 사용됩니다.

메서드 매개변수 이름과 URL 변수 이름이 일치하는 예시:

@RestController
@RequestMapping("/api")
public class MyController {
    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Long id) {
        // Retrieve user by given ID
    }
}

메서드 매개변수 이름과 URL 변수 이름이 다른 예시:

@RestController
@RequestMapping("/api")
public class MyController {
    @GetMapping("/users/{id}")
    public User getUser(@PathVariable("id") Long userId) {
        // Retrieve user by given ID
    }
}
13. @RequestParam

@RequestParam 어노테이션은 메서드 매개변수를 요청 파라미터에 바인딩할 때 사용됩니다.

예시:

@RestController
@RequestMapping("/api")
public class MyController {
    @GetMapping("/users")
    public List<User> getUsers(@RequestParam("status") String status) {
        // Retrieve users by given status
    }
}

@RequestParam@PathVariable의 차이점:

  • @RequestParam
    • 쿼리 파라미터에서 값을 가져옵니다.
    • 쿼리 파라미터는 일반적으로 URL의 ? 기호 뒤에 전달됩니다 (예: ?name=John&age=25).
    • 메서드 매개변수에 사용되며, Spring이 해당 값을 자동으로 주입합니다.
    • 간단한 데이터 타입과 GET 또는 POST 요청에서 주로 사용됩니다.

예시:

@GetMapping("/users")
public String getUserByName(@RequestParam("name") String name) {
    // Retrieve user by name
    return "User name: " + name;
}

요약:

  • @PathVariable: URL 경로에서 값을 추출할 때 사용합니다.
  • @RequestParam: URL 쿼리 매개변수에서 값을 추출할 때 사용합니다.
14. @RequestBody

@RequestBody 어노테이션은 요청 본문을 메서드 매개변수에 바인딩할 때 사용됩니다. 주로 RESTful API에서 JSON 또는 XML 페이로드를 받을 때 사용됩니다.

예시:

@RestController
@RequestMapping("/api")
public class MyController {
    @PostMapping("/users")
    public void createUser(@RequestBody User user) {
        // Create a new user
    }
}

이 예시에서 Spring은 요청 본문을 User 객체로 자동 변환합니다. 요청의 Content-Type이 application/json인 경우, 요청 본문은 다음과 같습니다:

{
  "name": "xiaou",
  "age": 25
}

@RequestParam@RequestBody의 차이점:

  • @RequestParam
    • 쿼리 파라미터에서 값을 가져옵니다.
    • 주로 간단한 데이터 타입에 사용됩니다.
    • GET 요청과 쿼리 파라미터가 있는 POST 요청을 처리할 때 적합합니다.

예시:

@GetMapping("/users")
public String getUserByName(@RequestParam("name") String name) {
    // Retrieve user by name
    return "User name: " + name;
}
  • @RequestBody
    • 요청 본문에서 값을 가져옵니다.
    • 주로 JSON 또는 XML과 같은 복잡한 데이터 타입에 사용됩니다.
    • 큰 페이로드나 복잡한 페이로드가 있는 POST 요청을 처리할 때 적합합니다.

예시:

@PostMapping("/users")
public String createUser(@RequestBody User user) {
    // Process received user object
    return "User created: " + user.toString();
}

요약:

  • @PathVariable: URL 경로에서 매개변수를 가져옵니다.
  • @RequestParam: URL 쿼리 문자열에서 매개변수를 가져옵니다.
  • @RequestBody: HTTP 요청 본문에서 매개변수를 가져옵니다.
15. @Qualifier

@Qualifier 어노테이션은 동일한 타입의 여러 빈이 있을 때, 어떤 빈을 주입할지 지정할 때 사용됩니다.

예시:

@Component("fooFormatter")
public class FooFormatter implements Formatter {
    public String format() {
        return "foo";
    }
}

@Component("barFormatter")
public class BarFormatter implements Formatter {
    public String format() {
        return "bar";
    }
}

@Component
public class FooService {
    @Autowired
    @Qualifier("fooFormatter")
    private Formatter formatter;

    // Additional code
}

이 예시에서 @Qualifier("fooFormatter")fooFormatter 빈이 FooService에 주입되도록 보장합니다.

16. @ConditionalOnProperty

@ConditionalOnProperty 어노테이션은 프로퍼티 값에 따라 빈 또는 설정을 조건부로 활성화하거나 비활성화할 때 사용됩니다.

예시:

@Configuration
@ConditionalOnProperty(name = "my.feature.enabled", havingValue = "true")
public class MyConfiguration {
    // Configuration that is enabled only if my.feature.enabled is true
}
17. @Scheduled

@Scheduled 어노테이션은 메서드의 실행을 일정한 간격으로 예약할 때 사용됩니다.

예시:

@Component
public class MyScheduler {
    @Scheduled(fixedDelay = 5000)
    public void doSomething() {
        // Task executed at fixed intervals
    }
}
18. @Cacheable, @CachePut, @CacheEvict

이 어노테이션들은 메서드 결과를 캐싱할 때 사용됩니다. 메서드 반환 값을 캐싱하고, 캐시를 업데이트하거나 캐시에서 항목을 제거할 수 있습니다.

예시:

@Service
public class MyService {
    @Cacheable("users")
    public User getUserById(Long id) {
        // Retrieve user from database
    }

    @CachePut("users")
    public User updateUser(User user) {
        // Update user in database and cache
    }

    @CacheEvict("users")
    public void deleteUser(Long id) {
        // Delete user from database and cache
    }
}

웹 어노테이션 (Web Annotations)

1. @CookieValue

@CookieValue 어노테이션은 HTTP 요청에서 특정 쿠키 값을 추출하는 데 사용됩니다.

예시:

@GetMapping("/showUser")
public String showUser(@CookieValue("username") String username) {
    // 추출된 쿠키 값을 사용하는 로직
    return "User: " + username;
}
2. @ModelAttribute

@ModelAttribute 어노테이션은 요청 매개변수를 모델 객체에 바인딩하는 데 사용됩니다. 주로 폼 데이터를 핸들러 메서드에 전달할 때 유용합니다.

예시:

@PostMapping("/saveUser")
public String saveUser(@ModelAttribute User user) {
    // 사용자 저장 로직
    return "redirect:/users";
}
3. @ResponseStatus

@ResponseStatus 어노테이션은 핸들러 메서드나 예외에 대한 HTTP 상태 코드를 지정하는 데 사용됩니다.

예시:

@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
    // 사용자 정의 예외
}

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public String handleResourceNotFoundException() {
        return "resourceNotFound";
    }
}
4. @ExceptionHandler

@ExceptionHandler 어노테이션은 컨트롤러에서 특정 예외를 처리하는 메서드를 정의하는 데 사용됩니다.

예시:

@Controller
public class MyController {
    @ExceptionHandler(Exception.class)
    public ModelAndView handleException(Exception ex) {
        ModelAndView modelAndView = new ModelAndView("error");
        modelAndView.addObject("errorMessage", ex.getMessage());
        return modelAndView;
    }
}

데이터 어노테이션 (Data Annotations)

1. @Entity

클래스를 JPA 엔티티로 표시하는 어노테이션입니다. 주로 데이터베이스 테이블에 매핑됩니다.

예시:

@Entity
@Table(name = "employees")
public class Employee {
    // 엔티티 속성과 메서드
}
2. @Table

엔티티가 매핑되는 테이블의 세부 정보를 지정하는 어노테이션입니다.

예시:

@Entity
@Table(name = "products", schema = "inventory")
public class Product {
    // 엔티티 속성과 메서드
}
3. @Id

엔티티의 기본 키를 지정하는 어노테이션입니다.

예시:

@Entity
@Table(name = "employees")
public class Employee {
    @Id
    private Long id;
    // 기타 속성과 메서드
}
4. @GeneratedValue

기본 키의 생성 전략을 지정하는 어노테이션입니다.

예시:

@Entity
@Table(name = "employees")
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    // 기타 속성과 메서드
}
5. @Column

필드가 매핑되는 컬럼의 세부 정보를 지정하는 어노테이션입니다.

예시:

@Entity
@Table(name = "employees")
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "emp_name", length = 50, nullable = false)
    private String name;
    // 기타 속성과 메서드
}
6. @Transient

필드가 데이터베이스에 영속되지 않도록 지정하는 어노테이션입니다.

예시:

@Entity
@Table(name = "employees")
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "emp_name", length = 50, nullable = false)
    private String name;

    @Transient
    private String transientField;
    // 기타 속성과 메서드
}
7. @PersistenceContext

엔티티 매니저를 주입하여 엔티티 영속성 작업을 관리하는 어노테이션입니다.

예시:

@Service
public class EmployeeService {
    @PersistenceContext
    private EntityManager entityManager;
    // 기타 메서드
}
8. @Query

커스텀 JPQL(Java Persistence Query Language) 쿼리를 선언하는 어노테이션입니다.

리포지토리 인터페이스 또는 엔티티 클래스의 메서드에 사용할 수 있습니다.

예시:

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
    @Query("SELECT e FROM Employee e WHERE e.department = ?1")
    List<Employee> findByDepartment(Department department);
}
9. @NamedQuery

엔티티 클래스에서 이름이 지정된 쿼리를 선언하는 어노테이션입니다.

이름이 지정된 쿼리는 여러 곳에서 참조할 수 있는 미리 정의된 JPQL 쿼리입니다.

예시:

@Entity
@NamedQuery(name = "Employee.findAll", query = "SELECT e FROM Employee e")
public class Employee {
    // 엔티티 속성과 메서드
}
10. @Param

JPQL 쿼리에서 명명된 매개변수를 참조하는 어노테이션입니다.

@Query 어노테이션 내에서 사용되며, 쿼리 문자열에서 명명된 매개변수와 함께 사용됩니다.

예시:

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
    @Query("SELECT e FROM Employee e WHERE e.department = :dept")
    List<Employee> findByDepartment(@Param("dept") Department department);
}
11. @JoinTable

엔티티 간의 다대다 관계를 위한 조인 테이블의 세부 정보를 지정하는 어노테이션입니다.

예시:

@Entity
public class Student {
    @ManyToMany
    @JoinTable(name = "student_course",
               joinColumns = @JoinColumn(name = "student_id"),
               inverseJoinColumns = @JoinColumn(name = "course_id"))
    private List<Course> courses;
    // 기타 속성과 메서드
}
12. @JoinColumn

일대다 또는 일대일 관계에서 엔티티 연관을 위한 외래 키 컬럼을 지정하는 어노테이션입니다.

예시:

@Entity
public class Employee {
    @ManyToOne
    @JoinColumn(name = "department_id")
    private Department department;
    // 기타 속성과 메서드
}

검증 어노테이션 (Validation Annotations)

이 어노테이션들은 일반적으로 Bean Validation(JSR-380) 사양에서 자바 빈 속성을 검증하는 데 사용됩니다.

1. @Valid

이 어노테이션은 중첩된 객체의 속성도 함께 검증해야 함을 나타냅니다. 주로 복잡한 객체의 모든 속성을 검증하기 위해 사용됩니다.

예시:

public class Address {
    @NotNull
    private String street;
    // 기타 속성과 메서드
}

public class User {
    @Valid
    private Address address;
    // 기타 속성과 메서드
}
2. @NotNull

이 어노테이션은 속성 값이 null이 아님을 검증하는 데 사용됩니다. 주로 문자열, 컬렉션, 맵, 기본 데이터 타입에 적용됩니다.

예시:

public class User {
    @NotNull
    private String username;
    // 기타 속성과 메서드
}
3. @Size

이 어노테이션은 속성 값의 크기가 지정된 범위 내에 있는지 검증하는 데 사용됩니다. 문자열, 컬렉션, 맵, 배열 속성에 적용할 수 있습니다.

예시:

public class User {
    @Size(min = 2, max = 50)
    private String name;
    // 기타 속성과 메서드
}
4. @Min

이 어노테이션은 속성 값이 지정된 최소값 이상임을 검증하는 데 사용됩니다. 주로 숫자 속성에 사용됩니다.

예시:

public class User {
    @Min(18)
    private int age;
    // 기타 속성과 메서드
}
5. @Max

이 어노테이션은 속성 값이 지정된 최대값 이하임을 검증하는 데 사용됩니다. 주로 숫자 속성에 사용됩니다.

예시:

public class User {
    @Max(100)
    private int age;
    // 기타 속성과 메서드
}
6. @Email

이 어노테이션은 속성 값이 이메일 주소 형식에 맞는지 검증하는 데 사용됩니다. 주로 문자열 속성에 적용됩니다.

예시:

public class User {
    @Email
    private String email;
    // 기타 속성과 메서드
}
7. @Pattern

이 어노테이션은 속성 값이 지정된 정규 표현식 패턴과 일치하는지 검증하는 데 사용됩니다. 사용자 정의 검증 규칙을 허용합니다.

예시:

public class User {
    @Pattern(regexp = "^[A-Za-z0-9]+$")
    private String username;
    // 기타 속성과 메서드
}

보안 어노테이션 (Security Annotations)

이 어노테이션들은 Spring Security와 OAuth2 프레임워크에서 보안 관련 기능과 인증 메커니즘을 설정하는 데 주로 사용됩니다.

1. @EnableWebSecurity

Spring Security의 웹 보안을 활성화합니다. 일반적으로 설정 클래스에 사용하여 Spring Boot 애플리케이션에서 Spring Security를 사용할 수 있도록 합니다.

예시:

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    // 보안 규칙 등을 설정합니다.
}
2. @Configuration

클래스가 설정 클래스임을 나타냅니다. 다른 어노테이션과 함께 사용되어 빈을 정의하고 애플리케이션의 다양한 기능을 구성합니다.

예시:

@Configuration
public class AppConfig {
    // 빈을 정의합니다.
}
3. @EnableGlobalMethodSecurity

전역 메서드 수준 보안을 활성화합니다. PreAuthorize, PostAuthorize, Secured, RolesAllowed 어노테이션을 구성할 수 있습니다.

예시:

@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    // 메서드 수준 보안 규칙을 설정합니다.
}
4. @PreAuthorize

메서드 실행 전에 인증 검사를 수행하는 데 사용됩니다. Spring Expression Language(SpEL)를 사용하여 접근 규칙을 지정할 수 있습니다.

예시:

@PreAuthorize("hasRole('ROLE_ADMIN')")
public void deleteUser(User user) {
    // 사용자를 삭제하는 로직
}
5. @PostAuthorize

메서드 실행 후에 인증 검사를 수행하는 데 사용됩니다. Spring Expression Language(SpEL)를 사용하여 접근 규칙을 지정할 수 있습니다.

예시:

@PostAuthorize("returnObject.owner == authentication.name")
public Object findDocument() {
    // 문서를 반환하는 로직
}
6. @Secured

특정 역할이 메서드를 호출할 수 있도록 접근을 제한하는 데 사용됩니다.

예시:

@Secured("ROLE_ADMIN")
public void deleteUser(User user) {
    // 사용자를 삭제하는 로직
}
7. @RolesAllowed

특정 역할이 메서드를 호출할 수 있도록 접근을 제한하는 데 사용됩니다.

예시:

@RolesAllowed("ROLE_ADMIN")
public void deleteUser(User user) {
    // 사용자를 삭제하는 로직
}
8. @EnableOAuth2Client, @EnableResourceServer, @EnableAuthorizationServer

이 어노테이션들은 OAuth2 구성을 위해 사용되며, OAuth2 클라이언트, 리소스 서버, 인증 서버 기능을 활성화합니다. 주로 설정 클래스에 사용됩니다.

예시:

@Configuration
@EnableOAuth2Client
public class OAuth2ClientConfig {
    // OAuth2 클라이언트를 설정합니다.
}

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    // 리소스 서버를 설정합니다.
}

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    // 인증 서버를 설정합니다.
}

이렇게 하면, Spring Security와 OAuth2 설정을 더욱 쉽게 관리할 수 있습니다.

테스트 어노테이션 (Testing Annotations)

JUnit과 Spring 프레임워크에서 테스트 관련 기능을 위해 자주 사용하는 어노테이션입니다.

1. @RunWith

JUnit 4에서 테스트 러너를 지정할 때 사용합니다. JUnit 5에서는 @ExtendWith로 대체되었습니다.

예시:

@RunWith(SpringRunner.class)
public class MySpringTest {
    // 테스트 코드
}
2. @SpringBootTest

통합 테스트를 위해 전체 Spring 애플리케이션 컨텍스트를 시작할 때 사용합니다. 애플리케이션 컨텍스트를 자동으로 구성합니다.

예시:

@SpringBootTest
public class MyIntegrationTest {
    // 통합 테스트 코드
}
3. @WebMvcTest

Spring MVC 애플리케이션의 단위 테스트를 수행할 때 사용합니다. 컨트롤러와 필터 같은 웹 관련 컴포넌트만 로드합니다.

예시:

@WebMvcTest(UserController.class)
public class UserControllerTest {
    // 컨트롤러 단위 테스트 코드
}
4. @DataJpaTest

JPA 영속 계층의 단위 테스트를 수행할 때 사용합니다. 메모리 내 데이터베이스(H2 등)를 자동으로 구성하고 @Entity 어노테이션을 스캔합니다.

예시:

@DataJpaTest
public class UserRepositoryTest {
    // JPA 단위 테스트 코드
}
5. @RestClientTest

Spring RestTemplate 또는 WebClient 클라이언트의 단위 테스트를 수행할 때 사용합니다. RestTemplate 또는 WebClient 빈을 자동으로 구성합니다.

예시:

@RestClientTest(MyRestClient.class)
public class MyRestClientTest {
    // Rest 클라이언트 단위 테스트 코드
}
6. @MockBean

모의 객체를 생성하고 이를 Spring 컨텍스트에 주입할 때 사용됩니다. 단위 테스트를 위해 Spring 빈을 대체합니다.

예시:

@SpringBootTest
public class MyServiceTest {
    @MockBean
    private SomeDependency mockDependency;

    // 단위 테스트 코드
}
7. @AutoConfigureMockMvc

Spring MVC 테스트에서 MockMvc를 자동으로 구성할 때 사용됩니다. 컨트롤러에 대한 요청을 시뮬레이션하는 데 사용됩니다.

예시:

@WebMvcTest(UserController.class)
@AutoConfigureMockMvc
public class UserControllerTest {
    @Autowired
    private MockMvc mockMvc;

    // 컨트롤러 테스트 코드
}
8. @Test, @Before, @After, @BeforeEach, @AfterEach, @BeforeAll, @AfterAll:

JUnit 테스트 메서드의 생명주기 관리를 위해 사용됩니다. @Test는 테스트 메서드를 표시하고, 다른 어노테이션은 테스트 메서드 전후에 특정 작업을 실행합니다.

예시:

@Test
public void testSomething() {
    // 테스트 메서드
}

@BeforeEach
public void setUp() {
    // 각 테스트 메서드 전의 작업
}

@AfterEach
public void tearDown() {
    // 각 테스트 메서드 후의 작업
}
9. @DisplayName

테스트 클래스나 테스트 메서드에 사용자 정의 이름을 지정할 때 사용됩니다. 보다 의미 있는 테스트 보고서를 생성하는 데 사용됩니다.

예시:

@Test
@DisplayName("사용자 등록 기능 테스트")
public void testUserRegistration() {
    // 테스트 메서드
}
10. @Disabled

테스트 클래스나 테스트 메서드를 비활성화할 때 사용됩니다. 디버깅 또는 개발 중에 특정 테스트를 일시적으로 건너뛰어야 할 때 사용됩니다.

예시:

@Test
@Disabled("임시 비활성화, 수정 대기 중")
public void testSomething() {
    // 테스트 메서드
}
11. @ParameterizedTest, @ValueSource, @CsvSource

매개변수화된 테스트를 위해 사용되며, 동일한 테스트 메서드를 여러 번 실행할 수 있게 합니다. @ValueSource는 단일 매개변수 값을 지정하고, @CsvSource는 여러 매개변수 값을 지정합니다.

예시:

@ParameterizedTest
@ValueSource(strings = {"apple", "banana", "orange"})
public void testFruit(String fruit) {
    // 다른 과일 매개변수를 사용하는 테스트 메서드
}

@ParameterizedTest
@CsvSource({"apple, 1", "banana, 2", "orange, 3"})
public void testFruit(String fruit, int count) {
    // 과일과 개수 매개변수를 사용하는 테스트 메서드
}
12. @ExtendWith

테스트 런타임의 기능을 확장할 때 사용됩니다. 예를 들어, 매개변수 해석 및 조건 평가와 같은 기능을 추가합니다.

예시:

@ExtendWith(MyExtension.class)
public class MyTest {
    // 테스트 메서드
}

메시지 어노테이션 (Messaging Annotations)

이 어노테이션들은 Spring 프레임워크에서 JMS(Java Message Service) 메시징 기능을 위해 자주 사용되며, JMS 메시지의 생산과 소비를 간단하게 만들어 줍니다.

1. @EnableJms

@EnableJms 어노테이션은 JMS 기능을 활성화합니다. 주로 설정 클래스에 배치하여 JMS 관련 어노테이션의 지원을 활성화합니다.

예시:

@Configuration
@EnableJms
public class AppConfig {
    // 기타 설정 코드
}
2. @JmsListener

@JmsListener 어노테이션은 JMS 메시지를 수신하는 메서드를 선언합니다. 수신할 큐 또는 토픽을 지정할 수 있습니다.

예시:

@JmsListener(destination = "myQueue")
public void receiveMessage(String message) {
    // 수신한 메시지 처리
}
3. @SendTo

@SendTo 어노테이션은 메시지 처리 메서드에서 응답 메시지의 목적지를 지정합니다. 주로 @JmsListener와 함께 사용됩니다.

예시:

@JmsListener(destination = "inputQueue")
@SendTo("outputQueue")
public String handleMessage(String message) {
    // 메시지를 처리하고 결과 반환
}
4. @MessageMapping

@MessageMapping 어노테이션은 특정 목적지의 메시지를 처리하는 메서드를 식별합니다. 주로 Spring의 WebSocket 지원과 함께 WebSocket 메시지를 처리하는 데 사용됩니다.

예시:

@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) {
    // 메시지를 처리하고 결과 반환
}
5. @Payload

@Payload 어노테이션은 JMS 메시지 처리 메서드에서 페이로드 매개변수를 지정하여 JMS 메시지 내용을 가져오는 데 사용됩니다.

예시:

@JmsListener(destination = "myQueue")
public void receiveMessage(@Payload String message) {
    // 메시지 내용 처리
}
6. @Header

@Header 어노테이션은 JMS 메시지 처리 메서드에서 헤더 매개변수를 지정하여 JMS 메시지 헤더 정보를 가져오는 데 사용됩니다.

예시:

@JmsListener(destination = "myQueue")
public void receiveMessage(@Header("X-Custom-Header") String customHeader) {
    // 메시지 헤더 처리
}

이 어노테이션들을 통해 Spring 프레임워크에서 JMS 메시징을 더욱 효율적으로 사용할 수 있습니다.

AOP 어노테이션 (Aspect-Oriented Programming Annotations)

이 어노테이션들은 Spring 프레임워크에서 AOP(관점 지향 프로그래밍)를 위해 자주 사용되며, 여러 곳에서 반복적으로 사용되는 코드를 모듈화하는 데 유용합니다.

1. @Aspect

횡단 관심사를 캡슐화하는 Aspect를 정의합니다. Aspect는 포인트컷과 어드바이스를 포함하는 클래스입니다.

예시:

@Aspect
@Component
public class LoggingAspect {
    // 어스펙트 클래스 구현
}
2. @Pointcut

Aspect 로직이 적용될 지점을 정의합니다. 동일한 포인트컷을 여러 어드바이스에서 재사용할 수 있습니다.

예시:

@Pointcut("execution(* com.example.service.*.*(..))")
private void serviceLayer() {}
3. @Before

메서드 실행 전에 실행되는 ‘before’ 어드바이스를 정의합니다. 조인 포인트 전에 실행됩니다.

예시:

@Before("serviceLayer()")
public void beforeAdvice() {
    // 'before' 어드바이스 로직
}
4. @After

메서드 실행 후에 실행되는 ‘after’ 어드바이스를 정의합니다. 메서드의 결과와 상관없이 조인 포인트 후에 실행됩니다.

예시:

@After("serviceLayer()")
public void afterAdvice() {
    // 'after' 어드바이스 로직
}
5. @AfterReturning

메서드가 정상적으로 반환된 후에 실행되는 ‘returning’ 어드바이스를 정의합니다. 메서드가 정상적으로 반환될 때만 실행됩니다.

예시:

@AfterReturning(pointcut = "serviceLayer()", returning = "result")
public void afterReturningAdvice(Object result) {
    // 'returning' 어드바이스 로직
}
6. @AfterThrowing

메서드가 예외를 던진 후에 실행되는 ‘throwing’ 어드바이스를 정의합니다. 메서드가 예외를 던질 때만 실행됩니다.

예시:

@AfterThrowing(pointcut = "serviceLayer()", throwing = "exception")
public void afterThrowingAdvice(Exception exception) {
    // 'throwing' 어드바이스 로직
}
7. @Around

메서드 실행 전후에 실행되는 ‘around’ 어드바이스를 정의합니다. 이 어드바이스는 메서드 실행을 제어합니다.

예시:

@Around("serviceLayer()")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
    // 실행 전 로직
    Object result = joinPoint.proceed(); // 어드바이스된 메서드 실행
    // 실행 후 로직
    return result;
}

이 어노테이션들은 자주 사용되지는 않지만, 간단히 요약해두었습니다.

엑추에이터 어노테이션 (Actuator Annotations)

Spring Boot Actuator를 활성화하고 맞춤 설정하기 위해 사용하는 어노테이션입니다. 이 어노테이션을 사용하면 애플리케이션의 모니터링과 관리 기능을 제공할 수 있습니다.

@EnableActuator

Spring Boot Actuator 모듈을 활성화하여 애플리케이션 모니터링 및 관리 기능을 제공합니다.

@Endpoint

커스텀 엔드포인트를 생성하여 사용자 정의 모니터링 및 관리 엔드포인트를 노출합니다.

예시:

@Endpoint(id = "customEndpoint")
public class CustomEndpoint {
    @ReadOperation
    public String read() {
        return "Custom Read Operation";
    }
}
@RestControllerEndpoint

REST 스타일의 엔드포인트를 생성하여 REST 컨트롤러로 사용할 수 있게 합니다.

예시:

@RestControllerEndpoint(id = "customRestEndpoint")
public class CustomRestEndpoint {
    @GetMapping("/custom")
    public String custom() {
        return "Custom REST Endpoint";
    }
}
@ReadOperation

엔드포인트에서 GET 요청을 처리하는 메서드를 지정합니다.

@WriteOperation

엔드포인트에서 POST 요청을 처리하는 메서드를 지정합니다.

@DeleteOperation

엔드포인트에서 DELETE 요청을 처리하는 메서드를 지정합니다.

설정 속성 어노테이션 (Configuration Properties Annotations)

설정 파일의 속성을 Java Bean에 매핑하기 위해 사용하는 어노테이션입니다.

@ConfigurationProperties

설정 파일의 속성을 Java Bean에 매핑합니다.

예시:

@ConfigurationProperties(prefix = "app")
public class AppProperties {
    private String name;
    private String version;

    // Getters and setters
}
@ConstructorBinding

설정 속성을 생성자 매개변수에 바인딩합니다. 일반적으로 @ConfigurationProperties와 함께 사용됩니다.

@Validated

설정 속성 클래스를 검증 대상으로 표시합니다. 일반적으로 JSR-380(Bean Validation)과 함께 사용됩니다.

국제화 및 현지화 어노테이션 (Internationalization and Localization)

  • @EnableMessageSource: 메시지 소스 처리를 활성화하며, 주로 국제화와 지역화를 위해 사용됩니다.
  • @EnableWebMvc: Spring MVC 기능을 활성화하며, 주로 설정 클래스에서 Spring MVC 지원을 위해 사용됩니다.
  • @LocaleResolver: 요청에서 로케일 정보를 해석합니다.
  • @MessageBundle: 국제화 메시지 리소스 파일의 기본 이름을 지정합니다.
  • @MessageSource: 메시지 리소스를 가져오며, 주로 @Autowired와 함께 사용됩니다.

로깅 모니터링 어노테이션 (Logging and Monitoring)

@Slf4j, @Log4j2, @Log:
다양한 로깅 프레임워크(SLF4J, Log4j2, JDK Logging)를 위한 로거 생성을 단순화합니다.

예시:

@Slf4j
public class MyService {
    public void doSomething() {
        log.info("Doing something");
    }
}

@Timed, @Counted, @ExceptionMetered:
메서드 실행 시간, 호출 횟수, 예외 등을 모니터링하는 메트릭을 추가합니다.

데이터 검증 어노테이션 (Data Validation)

@NotNull, @NotBlank, @Email, @Size, @Pattern:
필드의 null 아님, 공백 아님, 이메일 형식, 크기 범위, 정규식 패턴 일치를 검증합니다.

@Positive, @PositiveOrZero, @Negative, @NegativeOrZero:
숫자가 양수, 음수가 아닌지, 음수, 음수가 아닌지 검증합니다.

그래프QL 어노테이션 (GraphQL Annotations)

  • @GraphQLApi: 클래스를 GraphQL API 클래스로 표시합니다.
  • @GraphQLQuery, @GraphQLMutation, @GraphQLSubscription: GraphQL 쿼리, 뮤테이션, 구독을 정의합니다.
  • @GraphQLArgument, @GraphQLContext, @GraphQLNonNull, @GraphQLInputType, @GraphQLType: GraphQL 인자, 컨텍스트, null 아님 타입, 입력 타입, 타입을 정의합니다.

통합 어노테이션 (Integration Annotations)

  • @IntegrationComponentScan: 통합 컴포넌트를 스캔합니다.
  • @MessagingGateway, @Transformer, @Splitter, @Aggregator, @ServiceActivator, @InboundChannelAdapter, @OutboundChannelAdapter, @Router, @BridgeTo: 통합 컴포넌트를 구성하고 정의합니다.

Flyway 데이터베이스 관련 어노테이션 (Flyway Database Migration)

  • @FlywayTest: Flyway 데이터베이스 마이그레이션을 테스트합니다.
  • @FlywayTestExtension: Flyway 테스트 기능을 확장합니다.
  • @FlywayTestExtension.Test, @FlywayTestExtension.BeforeMigration, @FlywayTestExtension.AfterMigration: 테스트 메서드를 표시하고 마이그레이션 전후에 실행합니다.

JUnit 5 어노테이션 (JUnit5 Annotations)

  • @ExtendWith: JUnit 5 기능을 확장합니다.
  • @TestInstance: 테스트 인스턴스의 생명 주기를 구성합니다.
  • @TestTemplate: 테스트 템플릿 메서드를 지정합니다.
  • @DisplayNameGeneration: 테스트 표시 이름을 생성하는 전략을 사용자 지정합니다.
  • @Nested: 중첩 테스트 클래스를 생성합니다.
  • @Tag: 태그를 기반으로 테스트를 실행하도록 표시합니다.
  • @DisabledOnOs, @EnabledOnOs, @DisabledIf, @EnabledIf: 조건에 따라 테스트를 활성화하거나 비활성화합니다.

API 문서 어노테이션 (API Documentation Annotations)

  • @Api, @ApiOperation, @ApiParam, @ApiModel, @ApiModelProperty: API 문서화 세부 사항을 정의하고 설명합니다.

예외 처리 어노테이션 (Exception Handling Annotations)

  • @ControllerAdvice: 전역 예외 처리기를 정의합니다.
  • @ExceptionHandler: 특정 예외를 처리합니다.

그래프QA (추가)어노테이션 (GraphQL Annotations (Additional))

  • @GraphQLSchema, @GraphQLQueryResolver, @GraphQLMutationResolver, @GraphQLSubscriptionResolver, @GraphQLResolver: GraphQL 스키마와 리졸버를 정의합니다.

Server-Sent Events (SSE) Annotations

  • @SseEmitter: SSE 이벤트 방출기를 생성합니다.
  • @SseEventSink: SSE 이벤트 수신기를 주입합니다.

웹플럭스 어노테이션 (WebFlux Annotations)

  • @RestController, @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping: WebFlux RESTful 컨트롤러와 요청 매핑을 정의합니다.

미터링 어노테이션 (Metering Annotations)

  • @Timed: 메서드 실행 시간을 측정합니다.
  • @Counted: 메서드 호출 횟수를 셉니다.
  • @Gauge: 메서드를 게이지 메트릭으로 노출합니다.
  • @ExceptionMetered: 메서드 예외 발생률을 측정합니다.

마무리

이 목록은 모든 것을 포함한 것은 아닙니다. Spring Boot는 다양한 모듈과 기능에 걸쳐 수많은 어노테이션을 제공합니다. 포괄적인 목록과 자세한 사용법은 공식 Spring Boot 문서와 모듈별 가이드를 참조하시기 바랍니다.

이 글에서는 일반적으로 많이 사용하는 어노테이션들을 다루고 있으며, 일반적인 프로젝트에서 접할 수 있는 거의 모든 어노테이션을 포함하였습니다.

Spring Boot는 기능이 매우 광범위하므로 필요할 때마다 공식 문서를 참고하여 최신 정보를 확인하는 것이 중요합니다. 어노테이션을 적절히 활용하면 개발 생산성을 크게 높일 수 있으므로, 각 어노테이션의 특징과 용도를 이해하고 프로젝트에 맞게 잘 활용해 보세요.

더 궁금한 점이 있거나 도움이 필요하시면 언제든지 댓글로 남겨주세요. 읽어주셔서 감사합니다! 🙂

Written by 개발자서동우
안녕하세요! 저는 기술 분야에서 활동 중인 개발자 서동우입니다. 명품 플랫폼 (주)트렌비의 창업 멤버이자 CTO로 활동했으며, AI 기술회사 (주)헤드리스의 공동 창업자이자 CTO로서 역할을 수행했습니다. 다양한 스타트업에서 일하며 회사의 성장과 더불어 비즈니스 상황에 맞는 기술 선택, 개발팀 구성 및 문화 정착에 깊은 경험을 쌓았습니다. 개발 관련 고민은 언제든지 편하게 연락주세요 :) https://linktr.ee/dannyseo Profile

Leave a Reply

Your email address will not be published. Required fields are marked *