Lombok
📌 Java의 보일러플레이트 코드(반복적이고 지루한 코드)를 줄여주는 라이브러리입니다.
- 간단한 어노테이션으로 getter, setter, equals, hashCode, toString, logger 생성 등을 자동으로 생성하여 코드의 간결성을 높이고 가독성을 향상시킵니다.
import lombok.ToString;
@ToString
public class Example {
private String name;
private int age;
}
=
@Override
public String toString() {
return "Example(name=" + name + ", age=" + age + ")";
}
Lombok의 장점
- 코드 간소화:
- getter, setter, equals, toString 등 반복적인 코드를 줄여줍니다.
- 가독성 향상:
- 핵심 로직에만 집중할 수 있어 코드가 더 읽기 쉬워집니다.
- 유지보수성 개선:
- 코드 중복이 줄어들어 수정할 곳이 줄어듭니다.
Lombok 사용 시 주의사항
- 의존성 문제:
- Lombok은 컴파일 시점에 코드를 생성하므로, IDE와 빌드 환경이 Lombok을 지원해야 합니다.
- 타인의 코드 리뷰:
- Lombok을 사용하면 실제 코드가 IDE에서 보이지 않아, 팀원이 Lombok을 모른다면 코드 리뷰가 어려울 수 있습니다.
- Java 표준 아님:
- Lombok은 Java 표준 라이브러리가 아니기 때문에, 프로젝트 환경에 따라 사용을 제한할 수 있습니다.
@Slf4j
📌 Lombok에서 제공하는 어노테이션으로, SLF4J(Simple Logging Facade for Java) 기반의 로깅(Logger) 객체를 자동으로 생성합니다.
- 로깅은 애플리케이션 개발에서 로그 메시지를 기록하여 디버깅, 모니터링, 운영 상태를 파악하는 데 매우 중요한 도구입니다.
- Slf4j는 인터페이스이고 그 구현체로 Logback같은 라이브러리를 선택한다. 실제 개발에서는 Spring Boot가 기본으로 제공하는 Logback을 대부분 사용한다. (Slf4j는 껍데기 실제 로깅은 구현체가 한다.)
- 헷갈릴까봐 기술하면, Logback이 Slf4j의 구현체 중 하나로, Spring Boot에서 기본 로깅 프레임워크로 사용된다.
Logging
- Thread 정보, 클래스 이름과 같은 부가 정보를 함께 확인할 수 있다.
- 실제 운영 환경에서는 System.out.println();을 사용하여 Console에 정보를 출력하지 않고, 별도의 로깅 라이브러리를 사용하여 로그를 출력한다.
- Log Level 설정을 통하여 Error 메세지만 출력하도록 하도록 하기도 하고 로그 메세지를 일자별로 모아서 저장하여 외부 저장소에 보관하기도 한다.
- Log Level
- TRACE > DEBUG > INFO > WARN > ERROR
- Log Level
- 이게 왜 있나 싶을 수 있는데, 서버는 출력을 터미널에 띄울 수 없다보니 따로 서버내에서 기록하게 한다. 실제로 개발자 환경에 console에서 그 결과를 확인할 수 있다. 더 나아가 오류를 미리 기록하여 모니터링을 돕는다. 서버에 적재하지 않는 프로그램이면 이렇게 하지 않겠지만 서버는 24시간 돌아가니 사람이 24시간 감시할거 아니면 저런 장치가 필요하다.
사용시 주의점
package com.example.springbasicannotation.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@Slf4j
@RestController
public class Slf4jController {
@RequestMapping("/logging")
public String logging() {
String sparta = "Sparta";
// TRACE -> DEBUG -> INFO -> WARN -> ERROR
log.trace("문자 trace={}", sparta);
log.debug("문자 debug={}", sparta);
// default
log.info("문자 info={}", sparta);// 문자 연산을 진행하지 않는다.
log.warn("문자 warn={}", sparta);
log.error("문자 error={}", sparta);
log.info("문자 info " + sparta); // 문자 연산을 먼저 해버린다.
return "success";
}
}
# com.example.springbasicannotation 하위 경로들의 로그 레벨을 설정한다.
logging.level.com.example.springbasicannotation=TRACE
- Postman 호출
Default Level(INFO) API 호출
출력결과
level=TRACE
@Controller VS @RestController
📌 Annotation 기반의 Spring에서 Controller(Handler)를 만들 때 사용하는 어노테이션
- 둘이 기능은 같지만, 데이터 반환 방식과 응답 처리 방식이 다르다.
주요 차이점
특징 | @Controller | @RestController |
주요 용도 | 페이지(View) 기반 웹 애플리케이션 | RESTful API 개발 |
기본 반환 타입 | View 이름(HTML, JSP 등) | JSON, XML 등 데이터 |
View Resolver | View Resolver를 통해 뷰 파일로 매핑 | 사용하지 않음 |
응답 내용 | HTML 페이지를 렌더링하여 반환 | 데이터 자체를 HTTP 응답으로 반환 |
애너테이션 결합 | 단일 어노테이션 | @Controller + @ResponseBody |
언제 사용해야 할까?
- @Controller:
- HTML, JSP 같은 페이지 기반 웹 애플리케이션 개발.
- 템플릿 엔진(Thymeleaf, JSP)과 함께 사용.
- @RestController:
- JSON, XML 데이터를 반환하는 RESTful API 개발.
- 클라이언트(브라우저, 앱 등)가 데이터를 요청하고 처리하는 백엔드 서비스 개발.
@Controller
📌MVC(Model-View-Controller) 아키텍처에서 사용되는 컨트롤러.
- 클라이언트 요청을 처리하고, **View(HTML, JSP 등)**를 반환하는 데 사용.
- View가 있는 경우에 사용한다.
- 주로 페이지 기반의 웹 애플리케이션 개발에 적합.
- 즉, Template Engine인 Thymeleaf, JSP 등을 사용하는 경우
특징
- View Resolver와 함께 사용:
- @Controller는 뷰 이름을 반환하며, Spring의 View Resolver가 이 이름을 실제 뷰 파일 경로로 변환.
- 예: return "home"; → /WEB-INF/views/home.jsp
- 주요 반환 타입:
- 문자열(String): 뷰 이름.
- ModelAndView: 데이터와 뷰 정보를 함께 반환.
@Controller
public class WebController {
@GetMapping("/hello")
public String hello(Model model) {
model.addAttribute("message", "Hello, World!");
return "hello"; // 뷰 이름 반환 (예: hello.jsp)
}
}
응답 흐름
- 클라이언트가 /hello로 요청.
- hello() 메서드가 실행되고, 뷰 이름 "hello" 반환.
- View Resolver가 "hello"를 실제 뷰 파일 경로(/WEB-INF/views/hello.jsp)로 매핑.
- 해당 JSP 파일이 렌더링되어 클라이언트에게 HTML 응답 반환.
- @Target(ElementType.Type)
- Class, Interface, Annotation, Enum, Record Declaration(Java16) 에 적용할 수 있다.
- @Retention(RetentionPolicy.RUNTIME)
- 클래스 파일(.class)에 저장되고, JVM에 의해 런타임 시점에 읽을 수 있다.
- @Document
- Javadoc 등의 문서화 도구에 의해 문서화되어야 함을 나타낸다.
- @Component
- Spring Bean에 등록한다.
- 싱글톤으로 관리된다.
더보기
Thymeleaf 예시
- SpringBoot build.gradle 의존성 추
- main/resources/templates 가 기본 경로로 설정된다.
- resources/templates/sparta.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Hello</title>
</head>
<body>
<h2>Thymeleaf Template Sample</h2>
</body>
</html>
- 동작 순서
- return 값이 String이면 ThymeleafViewResolver 에 의해 View Name으로 인식된다.
- 호출결과
- http://localhost:8080/view
@RestController
📌 RESTful 웹 서비스를 개발하기 위해 사용되는 컨트롤러.
- 응답할 Data가 있는 경우에 사용한다.
- 클라이언트 요청을 처리하고, JSON, XML 등 데이터 포맷으로 응답.
- 페이지 대신 **데이터(API)**를 반환하는 데 사용.
- 현재는 대부분 @RestController를 사용하여 API가 만들어진다. (Restful API)
- return 값으로 View를 찾는것이 아니라 HTTP Message Body에 Data를 입력한다.
특징
- 데이터 반환에 특화:
- 메서드의 반환값은 **자동으로 HTTP 응답 본문(body)**에 직렬화되어 클라이언트에 전달.
- JSON이 기본 반환 포맷(SPRING BOOT에서는 기본적으로 Jackson 라이브러리를 사용).
- 주요 반환 타입:
- 객체 또는 컬렉션: JSON으로 변환.
- 문자열(String): 텍스트 응답.
- @Controller + @ResponseBody의 결합:
- @RestController는 내부적으로 @Controller와 @ResponseBody를 합친 것과 같음.
코드 예제
@RestController
public class ApiController {
@GetMapping("/api/hello")
public Map<String, String> hello() {
Map<String, String> response = new HashMap<>();
response.put("message", "Hello, World!");
return response; // JSON으로 변환되어 반환
}
}
응답 흐름
- 클라이언트가 /api/hello로 요청.
- hello() 메서드가 실행되고, Map<String, String> 객체 반환.
- Spring Boot가 반환된 객체를 JSON으로 변환.
- JSON 응답을 클라이언트로 전달.
- @Controller에 @ResponseBody가 결합된 어노테이션
- @RestController는 @Controller와 달리 각 메서드마다 @ResponseBody를 추가하지 않아도 된다
결론
- @Controller는 View를 반환하는 데 초점을 맞추고 있고, @RestController는 데이터(API 응답)를 반환하는 데 사용됩니다.
- 개발 목적에 따라 적절한 어노테이션을 선택하여 사용하면 됩니다.
예를 들어:- HTML 페이지 제공: @Controller + View Resolver.
- REST API 제공: @RestController.
Spring Annotation 자세히 보기
@Component
- Spring Bean에 등록하는 역할을 수행한다.
- Spring Bean은 애플리케이션의 구성 요소를 정의하는 객체이다.
- WAS가 Servlet 코드를 읽어 컨테이너에 등록했던 것을 떠올려 봅시다.
- Servlet Container(네트워크 기초 자료)
더보기
- Servlet Container(네트워크 기초 자료)
- 📚 Servlet을 지원하는 WAS 내부에는 서블릿 컨테이너가 있다. 서블릿 컨테이너는 서블릿을 초기화, 생성, 관리, 호출, 종료하는 역할을 수행한다.
- Servlet의 생명주기
- Servlet은 서블릿 컨테이너가 생성 및 관리한다.
- 즉, WAS(서블릿 컨테이너 포함)가 종료될 때 Servlet도 함께 종료된다.
- Servlet 객체 생성시점
- 개발자가 직접 인스턴스화 하여 사용하는것이 아닌, 코드만 작성하면 서블릿 컨테이너가 생성한다.
- Servlet의 생명주기
서블릿 예시 코드
@WebServlet(name="ExampleServlet", urlPatterns = "/example")
public class ExampleServlet extends HttpServlet { // HttpServlet을 상속받아 구현한다.
@Override
protected void service(
HttpServletRequest request, // HTTP 요청 정보를 쉽게 사용할 수 있게 만드는 Servlet
HttpServletResponse response // HTTP 응답 정보를 쉽게 제공할 수 있게 만드는 Servlet
) {
// application logic
}
}
@WebServlet(name="Example2Servlet", urlPatterns = "/example2")
// 위와 같은 코드
@WebServlet(name="Example3Servlet", urlPatterns = "/example3")
// 위와 같은 코드
@WebServlet(name="Example4Servlet", urlPatterns = "/example4")
// 위와 같은 코드
- Servlet Container가 하는 일
- 서블릿을 초기화, 생성, 관리, 호출, 종료하는 역할을 수행
- Servlet 객체를 싱글톤으로 관리한다.
- 동시 요청에 대한 처리를 위해 Multi Thread를 지원한다.
- 서블릿을 초기화, 생성, 관리, 호출, 종료하는 역할을 수행
💬 Q. 싱글톤이 무엇인가요? A. 싱글톤은 객체를 하나만 생성하여 생성된 인스턴스를 공유하여 사용하는것을 의미합니다. 특정 클래스의 인스턴스가 여러개 생성되지 않도록 하여 자원의 낭비를 방지하고, 인스턴스를 공유함으로써 상태를 일관되게 유지하기 위함입니다. 하지만, 공유 변수 사용을 주의해야 합니다. |
- @Indexed
- 클래스가 컴포넌트 스캔의 대상으로 Spring Bean에 더 빠르게 등록되도록 도와준다.
- Spring Bean, 컴포넌트 스캔에 대해서는 숙련주차 강의에서 자세히 다룰 예정
@Target
- @Target 이 선언된 하위 어노테이션이 어떤 범위에 적용되는지 설정한다.
- ElementType Enum 속성
- 각각의 Enum마다 적용되는 범위가 상단에 주석으로 설명되어 있다.
@Retention
- @Retention 하위의 어노테이션이 얼마나 오래 유지되는지를 결정한다.
- RetentionPolicy Enum 속성
- SOURCE
- 소스 코드(.java)에서만 유지된다.
- 컴파일러에 의해 클래스 파일로 저장되지 않는다.
- CLASS
- 컴파일된 클래스 파일(.class)에 저장되지만, JVM이 실행 시 읽지 않는다. (주석과 같음)
- Default 값이다.
- RUNTIME
- 클래스 파일(.class)에 저장되고, JVM에 의해 런타임 시점에 읽을 수 있다.
- 즉, 실제 런타임 시점의 코드에 반영되어 영향을 준다.
@Documented
- Javadoc 등의 문서화 도구에 의해 문서화되어야 함을 나타낸다.
'Back-End (Web) > Spring' 카테고리의 다른 글
[Spring] @RequestParam & @ModelAttribute (0) | 2024.12.17 |
---|---|
[Spring] Request Mapping (1) | 2024.12.16 |
[Spring] Spring MVC 패턴 (1) | 2024.12.14 |
[Spring] Spring Boot (0) | 2024.12.10 |
[Spring] Spring Framework (2) | 2024.12.09 |