Now Loading ...
-
🍃[Spring] `.addAttribute()` 메서드.
🍃[Spring] .addAttribute() 메서드.
1️⃣ .addAttribute() 메서드.
.addAttribute()는 Spring MVC에서 Model 또는 ModelMap객체의 메서드로, 컨트롤러에서 뷰로 전달할 데이터를 추가하는 데 사용됩니다.
이 메서드를 사용하여 컨트롤러가 처리한 결과를 뷰에 전달하고, 뷰는 이 데이터를 사용해 동적으로 콘텐츠를 렌더링합니다.
2️⃣ 주요 기능.
모델에 데이터 추가
addAttribute()를 사용하여 키-값 쌍 형태로 데이터를 모델에 추가합니다.
이 데이터는 이후 뷰에서 사용될 수 있습니다.
뷰 랜더링에 데이터 전달
모델에 추가된 데이터는 뷰 템플릿(예: Thymeleaf, JSP)에서 접근 가능하며, 이를 통해 클라이언트에게 동적으로 생성된 HTML을 반환할 수 있습니다.
3️⃣ 사용 예시.
@Controller
public class HomeController {
@GetMapping("/home")
public String home(Model model) {
// 모델에 데이터를 추가
model.addAttribute("message", "Welcome to the Home Page!");
model.addAttribute("date", LocalDate.now());
// "home"이라는 뷰 이름을 반환
return "home";
}
}
위 코드에서 home() 메서드는 /home URL로 GET 요청이 들어오면 실행됩니다.
Model 객체를 사용하여 "message"와 "date"라는 두 개의 속성을 추가합니다.
이 속성들은 “home”이라는 뷰(예: home.html 또는 home.jsp)에서 사용됩니다.
4️⃣ 뷰에서의 사용 예시(Thymeleaf)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Home Page</title>
</head>
<body>
<h1 th:text="${message}">Default Message</h1>
<p>Today's date is: <span th:text="${date}">01/01/2024</span></p>
</body>
</html>
위의 Thymeleaf 템플릿에서 ${message}와 ${date}는 컨트롤러에서 addAttribute()를 통해 추가된 데이터를 나타냅니다.
컨트롤러에서 제공한 "Welcome to the Home Page!" 와 현재 날짜가 뷰에 렌더링됩니다.
5️⃣ .addAttribute()의 다양한 사용 방법.
1. 키와 값 쌍으로 사용
가장 기본적인 사용 방법으로, 첫 번째 인수로 속성의 이름을, 두 번째 인수로 속성의 값을 지정합니다.
model.addAttribute("username", "JohnDoe");
2. 키 없이 값만 전달
키를 생략하고 값만 전달할 수도 있습니다.
이 경우 Spring은 전달된 객체의 클래스 이름을 기본 키로 사용합니다.(첫 글자는 소문자로).
User user = new User("John", "Doe");
model.addAttribute(user);
// "user"라는 키로 모델에 추가됩니다.
3. 체이닝(Chaining)
addAttribute()는 메서드 체이닝이 가능하여, 여러 개의 속성을 한 번에 추가할 수 있습니다.
model.addAttribute("name", "Jane")
.addAttribute("age", 30)
.addAttribute("city", "New York");
.addAttribute()는 Spring MVC에서 컨트롤러와 뷰 사이의 데이터를 전달하는 중요한 역할을 하며, 동적인 웹 애플리케이션 개발에 필수적인 요소입니다.
-
🍃[Spring] Spring MVC에서 `View` 객체.
🍃[Spring] Spring MVC에서 View 객체.
1️⃣ View 객체.
Spring MVC에서 View 객체는 클라이언트에게 응답을 생성하는 데 사용되는 최종 출력을 담당하는 구성 요소입니다.
View 객체는 주어진 모델 데이터를 사용하여 HTML, JSON, XML, PDF 등 다양한 형태로 응답을 렌더링 합니다.
Spring MVC의 View 객체는 추상화된 인터페이스를 통해 다양한 템플릿 엔진이나 출력 형식을 지원합니다.
2️⃣ View 객체의 주요 역할.
1. 모델 데이터 렌더링
View 객체는 컨트롤러에서 전달된 Model 데이터를 이용해 클라이언트가 볼 수 있는 형식으로 변환합니다.
예를 들어, HTML 템플릿 엔진을 사용하여 웹 페이지를 생성하거나, JSON으로 데이터를 변환해 API 응답으로 보낼 수 있습니다.
2. 응답 생성
클라이언트에게 전송될 최종 응답을 생성합니다.
이는 브라우저에 표시될 HTML 페이지일 수도 있고, RESTful API의 JSON 응답일 수도 있습니다.
3. 컨텐츠 타입 설정
View 객체는 생성된 응답 컨텐츠 타입(예: text/html, application/json, application/pdf 등)을 설정하여 클라이언트가 올바르게 해석할 수 있도록 합니다.
3️⃣ View 객체의 종류.
Spring MVC에서는 여러 가지 유형의 View 객체를 지원합니다.
이들은 다양한 응답 형식을 처리할 수 있도록 설계되었습니다.
1. JSP(JavaServer Page)
Spring MVC에서 가장 전통적으로 사용되는 뷰 기술입니다.
JSP는 HTML과 Java 코드를 혼합하여 동적인 웹 페이지를 생성합니다.
2. Thymeleaf
최근 많이 사용되는 템플릿 엔진으로, HTML 파일을 템플릿으로 사용하여, HTML 태그에 특수한 속성을 추가하여 동적인 콘텐츠를 생성할 수 있습니다.
3. FreeMarker
HTML뿐만 아니라 텍스트 기반의 다양한 문서를 생성할 수 있는 템플릿 엔진입니다.
4. Velocity
Apache 프로젝트에서 제공하는 템플릿 엔진으로, FreeMarker와 유사하게 다양한 텍스트 기반 응담을 생성할 수 있습니다.
5. JSON/XML View
MappingJackson2JsonView 와 같은 JSON 또는 XML 뷰를 사용하여 데이터를 JSON 또는 XML 형식으로 변환하여 RESTful API 응답을 생성할 수 있습니다.
6. PDF/Excel View
AbstractPdfView, AbstractXlsView 와 같은 뷰를 사용하여 PDF나 Excel 파일을 생성하여 응답으로 반환할 수 있습니다.
4️⃣ View 객체 사용 예시
컨트롤러에서 View 객체를 명시적으로 사용할 수도 있고, 뷰 리졸버(View Resolver)가 자동으로 처리할 수도 있습니다.
@Controller
public class GreetingController {
@GetMapping("/greeting")
public ModelAndView greeting() {
ModelAndView mav = new ModelAndView("greeting");
mav.addObject("message", "Hello welcome to our website!");
return mav;
}
}
위의 예제에서 ModelAndView 객체를 사용하여 View를 명시적으로 지정했습니다.
greeting이라는 뷰 이름은 보통 JSP나 Thymeleaf 템플릿 파일과 매핑되며, 이 템플릿 파일이 렌더링 됩니다.
5️⃣ 뷰 리졸버(View Resolver)
Spring MVC에서 뷰 리졸버(View Resolver)는 컨트롤러가 반환한 뷰 이름을 실제 View 객체로 변환해주는 역할을 합니다.
일반적으로 뷰 리졸버는 템플릿 엔진이나 뷰 파일의 경로를 관리하고, 클라이언트에게 응답할 적절한 View 객체를 결정합니다.
예를 들어, 다음과 같은 뷰 리졸버 설정이 있을 수 있습니다.
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
위 설정에서는 컨트롤러가 greeting이라는 뷰 이름을 반환하면, InternalResourceViewResolver는 /WEB-INF/views/greeting.jsp 라는 JSP 파일을 찾아서 렌더링합니다.
6️⃣ 요약.
View 객체는 Spring MVC에서 클라이언트에게 응답을 생성하고 렌더링하는 역할을 합니다.
이 객체는 모델 데이터를 사용하여 최종 응답을 생성하며, 다양한 형식의 출력을 지원합니다.
Spring MVC는 View 객체를 직접 사용하거나 뷰 리졸버를 통해 간접적으로 사용하여, 클라이언트에게 최종 결과를 전달합니다.
-
🍃[Spring] `@ModelAttribute` 애노테이션
🍃[Spring] @ModelAttribute 애노테이션.
1️⃣ @ModelAttribute
@ModelAttribute는 Spring Framework에서 주로 사용되는 애노테이션으로, Spring MVC에서 모델 데이터와 요청 데이터를 바인딩하거나, 컨트롤러에서 반환된 데이터를 뷰에 전당하는 데 사용됩니다.
@ModelAttribute는 두 가지 주요 용도로 사용됩니다.
1️⃣ 메서드 파라미터에서 사용(@ModelAttribute 파라미터 바인딩)
@ModelAttribute를 메서드 파라미터에 적용하면, Spring은 요청 파라미터 또는 폼 데이터로부터 객체를 자동으로 생성하고, 그 객체의 필드를 요청 파라미터 값으로 바인딩합니다.
이렇게 생성된 객체는 컨트롤러 메서드 내부에서 사용할 수 있습니다.
예시.
@Controller
public class UserController {
@PostMapping("/register")
public String registerUser(@ModelAttribute User user) {
// User 객체는 폼 데이터로부터 자동으로 생성되고 바인딩됩니다.
// 이제 user 객체를 사용할 수 있습니다.
System.out.println("User Name: " + user.getName());
return "registrationSuccess";
}
}
위 예시에서 @ModelAttribute는 User 객체를 폼 데이터로부터 생성하고, name, email 등의 필드 요청 파라미터 값으로 바인딩합니다.
2️⃣ 메서드에 사용(@ModelAttribute 메서드)
@ModelAttribute를 메서드 레벨에 적용하면, 해당 메서드는 컨트롤러의 모든 요청 전에 실행되어, 반환된 객체를 모델에 추가합니다.
이 객체는 이후 뷰에서 사용될 수 있습니다.
```java
@Controller
public class UserController {
@ModelAttribute(“userTypes”)
public List populateUserTypes() {
// 이 메서드는 컨트롤러의 모든 요청 전에 실행됩니다.
// 이 리스트는 모델에 추가되어 뷰에서 사용될 수 있습니다.
return Arrays.asList("Admin", "User", "Guest");
}
@GetMapping(“/register”)
public String showRegistrationForm(Model model) {
model.addAttribute(“user”, new User());
return “register”;
}
}
```
위 예시에서 populateUserTypes() 메서드는 @ModelAttribute("userTypes")로 선언되어, 이 메서드가 반환하는 리스트는 userTypes라는 이름으로 모델에 추가됩니다.
이 값은 뷰(예: JSP, Thymeleaf 템플릿 등)에서 접근할 수 있습니다.
3️⃣ @ModelAttribute 의 주요 기능 요약.
1. 파라미터 바인딩 : 클라이언트의 요청 데이터를 객체로 변환하고, 이 객체를 컨트롤러 메서드에서 사용하도록 해줍니다.
2. 모델 추가 : 메서드의 반환 값을 모델에 추가하여, 해당 데이터가 모든 뷰에서 사용될 수 있도록 합니다.
이 두가지 기능을 통해 @ModelAttribute는 Spring MVC에서 데이터 바인딩과 뷰에 전당되는 데이터의 관리를 간소화하는 데 중요한 역할을 합니다.
-
🍃[Spring] Spring MVC에서 `Model` 객체.
🍃[Spring] Spring MVC에서 Model 객체.
1️⃣ Model 객체.
Spring MVC에서 Model 객체는 컨트롤러와 뷰 사이에서 데이터를 전달하는 역할을 합니다.
컨트롤러에서 생성된 데이터를 Model 객체에 담아두면, 이 데이터는 뷰 템플릿(예: Thymeleaf, JSP)에서 사용될 수 있습니다.
Model 객체는 요청에 대한 응답으로 어떤 데이터를 뷰로 보내야 하는지 결정하는 데 사용됩니다.
2️⃣ Model 객체의 주요 기능.
1. 데이터 저장 및 전달.
Model 객체에 데이터를 저장하면, 해당 데이터는 뷰에 전달되어 클라이언트에게 표시됩니다.
예를 들어, 사용자의 이름이나 리스트와 같은 데이터를 뷰에 전달할 수 있습니다.
2. 키-값 쌍 형태로 데이터 관리.
Model 객체는 데이터를 키-값 쌍 형태로 관리합니다.
뷰에서 이 데이터를 사용할 때는 키를 통해 접근합니다.
3. 뷰 템플릿에서 데이터 사용.
Model에 추가된 데이터는 뷰 템플릿에서 변수로 사용됩니다.
뷰 템플릿 엔진(예: Thymeleaf, JSP)은 이 데이터를 이용해 동적인 HTML을 생성하고, 이를 클라이언트에게 반환합니다.
3️⃣ Model 객체의 사용 예.
@Controller
public class GreetingController {
@GetMapping("/greeting")
public String greeting(Model model) {
model.addAttribute("name", "John");
model.addAttribute("message", "Hello welcome to our website!");
// "greeting"이라는 뷰 이름을 반환
return "greeting";
}
}
위 예제에서 greeting() 메서드는 Model 객체에 "name" 과 "message" 라는 두 가지 데이터를 추가합니다.
이 데이터는 뷰 이름 "greeting"에 전달되며, 해당 뷰 템플릿에서 사용될 수 있습니다.
4️⃣ 뷰 템플릿에서의 사용(Thymeleaf)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Greeting Page</title>
</head>
<body>
<h1 th:text="${message}">Default Message</h1>
<p>Hello, <span th:text="${name}">User</span>!</p>
</body>
이 Thymeleaf 템플릿에서 ${message} 와 ${name} 은 Model 객체에 담긴 데이터를 사용해 동적으로 콘텐츠를 생성합니다.
컨트롤러에서 Model에 추가된 "Hello, welcome to our website!"와 "John"이 뷰에 렌더링됩니다.
5️⃣ Model, ModelMap, ModelAndView
Spring MVC에서 Model 외에도 ModelMap과 ModelAndView라는 유사한 객체들이 있습니다.
Model : 간단한 인터페이스로, 데이터 저장 및 전달을 위한 가장 기본적인 방법을 제공합니다.
ModelMap : Model의 구현체로, 데이터를 맵 형식으로 관리합니다.
ModelAndView : 모델 데이터와 뷰 이름을 함께 반환할 때 사용됩니다. 한 번에 모델과 뷰 정보를 모두 설정할 수 있습니다.
6️⃣ 요약.
Model 객체는 Spring MVC에서 컨트롤러가 뷰에 데이터를 전달하는 데 사용되는 중요한 구성 요소입니다.
이를 통해 동적인 웹 페이지를 쉽게 생성할 수 있으며, 애플리케이션의 응답 결과를 클라이언트에게 효과적으로 전달할 수 있습니다.
-
🍃[Spring] Spring MVC에서 `Controller` 객체.
🍃[Spring] Spring MVC에서 Controller 객체.
1️⃣ Controller 객체.
Spring MVC에서 Controller 객체는 애플리케이션에서 HTTP 요청을 처리하고, 해당 요청에 대해 적절한 응답을 생성하는 역할을 하는 구성 요소입니다.
Controller는 사용자 입력을 처리하고, 비즈니스 로직을 수행한 후, 뷰를 선택하여 결과를 클라이언트에게 반환합니다.
Spring MVC에서 Controller는 주로 @Controller 또는 @RestController 애노테이션으로 정의됩니다.
1️⃣ 주요 역할.
1. HTTP 요청 처리
Controller 객체는 특정 URL 경로와 매핑된 HTTP 요청(GET, POST, PUT, DELETE 등)을 처리합니다.
각 요청은 컨트롤러의 특정 메서드와 연결되며, 메서드는 요청 매개변수를 처리하고, 필요한 작업을 수행합니다.
2. 비즈니스 로직 수행
요청을 처리하는 동안, Controller는 서비스 계층이나 비즈니스 로직을 호출하여 필요한 처리를 수행합니다.
이는 데이터베이스에서 데이터를 가져오거나, 계산을 수행하거나, 다른 복잡한 작업을 포함할 수 있습니다.
3. 모델 데이터 준비
Controller는 뷰에 전달할 데이터를 준비하고, 이를 Model 객체에 담아 뷰로 전달합니다.
이 데이터는 뷰 템플릿에서 사용되어 클라이언트에게 보여질 콘텐츠를 동적으로 생성합니다.
4. 뷰 선택 및 응답 생성
Controller는 처리 결과에 따라 어떤 뷰를 사용할지 결정합니다.
일반적으로 뷰의 이름을 반환하거나, ModelAndView 객체를 통해 뷰와 모델 데이터를 함께 반환합니다.
@RestController를 사용하면 JSON, XML 등의 형식으로 직접 데이터를 반환할 수도 있습니다.
2️⃣ Controller 객체의 정의.
Spring MVC에서 Controller는 @Controller 애노테이션으로 정의됩니다.
이 애노테이션은 클래스가 컨트롤러 역할을 한다는 것을 Spring에게 알리며, HTTP 요청을 처리할 수 있게 합니다.
예제: 기본 컨트롤러
@Controller
public class GreetingController {
@GetMapping("/greeting")
public String greeting(Model model) {
model.addAttribute("message", "Hello, welcome to our website!");
return "greeting";
}
}
위 코드에서 GreetingController 클래스는 @Controller 애노테이션을 통해 컨트롤러로 정의됩니다.
/greeting 경로로 GET 요청이 들어오면 greeting() 메서드가 호출되며, "message" 라는 데이터를 모델에 추가하고, "greeting" 이라는 뷰 이름을 반환합니다.
Spring MVC는 이 뷰 이름을 기반으로 실제 뷰를 랜더링합니다.
3️⃣ @RestController 사용.
@RestController는 @Controller와 @ResponseBody를 결합한 애노테이션입니다.
이 애노테이션이 적용된 클래스는 JSON이나 XML과 같은 데이터 형식으로 직접 응답을 반환하는 RESTful 웹 서비스의 컨트롤러로 동작합니다.
예제: REST 컨트롤러
@RestController
public class ApiController {
@GetMapping("/api/greeting")
public Map<String, String> greeting() {
Map<String, String> response = new HashMap<>();
response.put("message", "Hello, welcome to our API!");
return response;
}
}
위 코드에서 ApiController 클래스는 @RestController 애노테이션을 사용하여 정의됩니다.
/api/greeting 경로로 GET 요청이 들어오면 greeting() 메서드는 JSON 형식의 응답을 반환합니다.
4️⃣ 요청 매핑.
Controller는 URL 경로 및 HTTP 메서드와 매핑된 메서드를 통해 요청을 처리합니다.
Spring MVC는 이를 위해 @RequestMapping, @GetMapping, @PostMapping 등 다양한 매핑 애노테이션을 제공합니다.
예제: 요청 매핑.
@Controller
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public String getUser(@PathVariable("id") Long id, Model model) {
User user = userService.findUserById(id);
model.addAttribute("user", user);
return "userProfile";
}
@PostMapping("/create")
public String createUser(@ModelAttribute User user) {
userService.saveUser(user);
return "redirect:/users/" + user.getId();
}
}
위 예제에서 UserController는 /users 경로와 관련된 요청을 처리합니다.
/users/{id} 경로로 GET 요청이 들어오면, 해당 사용자의 프로필 정보를 조회하여 "userProfile" 뷰에 전달합니다.
/users/create 경로로 POST 요청이 들어오면, 새로운 사용자를 생성하고, 해당 사용자의 프로필 페이지로 리다이렉트합니다.
5️⃣ 요약.
Spring MVC에서 Controller 객체는 클라이언트의 HTTP 요청을 처리하고, 비즈니스 로직을 실행한 후, 적절한 응답을 생성하는 핵심 구성 요소입니다.
Controller는 요청과 비즈니스 로직, 그리고 뷰 렌더링을 연결하는 역할을 하며, Spring MVC 애플리케이션에서 중요한 역할을 수행합니다.
-
🍃[Spring] `@Transactional` 애노테이션
🍃[Spring] @Transactional 애노테이션.
@Transactional 애노테이션은 Spring Framework에서 제공하는 애노테이션으로, 메서드나 클래스에 적용하여 해당 범위 내의 데이터베이스 작업을 하나의 트랜잭션으로 관리할 수 있도록 해줍니다.
즉, @Transactional을 사용하면 지정된 메서드 또는 클래스 내의 데이터베이스 작업이 모두 성공해야만 커밋(commit)되고, 그렇지 않으면 롤백(rollback)됩니다.
1️⃣ 주요 기능.
1. 트랜잭션 관리.
@Transactional 애노테이션이 적용된 메서드 내에서 수행되는 모든 데이터베이스 작업(예: INSERT, UPDATE, DELETE)은 하나의 트랜잭션으로 관리됩니다.
만약 메서드 실행 중 예외가 발생하면, 해당 트랜잭션 내의 모든 변경 사항이 롤백됩니다.
2. 적용 범위.
@Transactional은 클래스나 메서드에 적용할 수 있습니다.
클래스에 적용하면 해당 클래스의 모든 메서드가 트랜잭션 내에서 실행됩니다.
메스트에 적용되면 해당 메서드만 트랜잭션으로 관리됩니다.
3. 트랜잭션 전파(Propagation)
@Transactional은 여러 전파(Propagation) 옵션을 제공하여 트랜잭션이 다른 트랜잭션과 어떻게 상호작용할지를 정의할 수 있습니다.
REQUIRED : 기본값으로, 현재 트랜잭션이 존재하면 이를 사용하고, 없으면 새로운 트랜잭션을 생성합니다.
REQUIRES_NEW : 항상 새로운 트랜잭션을 생성하고, 기존 트랜잭션을 일시 정지합니다.
MANDATORY : 현재 트랜잭션이 반드시 존재해야 하며, 없으면 예외가 발생합니다.
SUPPORT : 현재 트랜잭션이 있으면 이를 사용하고, 없으면 트랜잭션 없이 실행합니다.
기타 : NOT_SUPPORT, NEVER, NESTED 등.
4. 트랜잭션 격리 수준(Isolation Level)
데이터베이스 트랜잭션의 격리 수준을 설정할 수 있습니다.
이는 동시에 실행되는 여러 트랜잭션 간의 상호작용 방식을 정의합니다.
READ_UNCOMMITTED : 다른 트랜잭션의 미완료 변경 사항을 읽을 수 있습니다.
READ_COMMITED : 다른 트랜잭션의 커밋된 변경 사항만 읽을 수 있습니다.
REPEATABLE_READ : 트랜잭션 동안 동일한 데이터를 반복적으로 읽어도 동일한 결과를 보장합니다.
SERIALIZABLE : 가장 엄격한 격리 수준으로, 트랜잭션이 완전히 순차적으로 실행되도록 보장합니다.
5. 롤백 규칙(Rollback Rules)
기본적으로 @Transactional 은 RuntimeException 또는 Error 가 발생하면 트랜잭션을 롤백합니다.
특정 예외에 대해 롤백을 강제하거나, 롤백을 방지하도록 설정할 수 있습니다.
rollbackFor 또는 noRollbackFor 속성을 사용하여 이 동작을 커스터마이징할 수 있습니다.
6. 읽기 전용(Read-Only)
@Transactional(readOnly = true)로 설정하면 트랜잭션이 데이터 읽기 전용으로 동작하며, 이 경우 데이터 수정 작업이 최적화될 수 있습니다.
주로 SELECT 쿼리에서 사용됩니다.
2️⃣ 예시 코드
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
@Transactional
public void performTransaction() {
// 데이터베이스에 새로운 엔티티 추가
myRepository.save(new MyEntity("Data1"));
// 다른 데이터베이스 작업 수행
myRepository.updateEntity(1L, "UpdatedData");
// 예외 발생 시, 위의 모든 작업이 롤백됨
if (someConditionFails()) {
throw new RuntimeException("Transaction failed, rolling back...");
}
}
@Transactional(readOnly = true)
public List<MyEntity> getEntities() {
return myRepository.findAll();
}
}
3️⃣ 요약.
@Transactional 은 데이터베이스 트랜잭션을 쉽게 관리할 수 있도록 해주는 Spring의 핵심 애노테이션입니다.
이 애노테이션을 사용하면 메서드나 클래스의 데이터베이스 작업을 하나의 트랜잭션으로 처리하며, 실패 시 자동으로 롤백됩니다.
또한, 트랜잭션 전파, 격리 수준, 롤백 규칙 등을 통해 세부적으로 트랜잭션의 동작을 제어할 수 있습니다.
이러한 기능 덕분에 @Transactional은 Spring 애플리케이션에서 데이터 일관성과 무결성을 유지하는 데 중요한 역할을 합니다.
-
🍃[Spring] `@SpringBootTest` 애노테이션
🍃[Spring] @SpringBootTest 애노테이션.
@SpringBootTest 애노테이션은 Spring Boot 애플리케이션에서 통합 테스트를 수행하기 위해 사용하는 애너테이션입니다.
이 애노테이션은 테스트 클래스에서 Spring Application Context를 로드하고, 실제 애플리케이션의 전체 또는 부분적인 환경을 시뮬레이션하여 테스트할 수 있게 합니다.
주로 애플리케이션의 전반적인 기능을 테스트하거나 여러 레이어(예: 서비스, 레포지토리 등) 간의 상호작용을 검증할 때 사용됩니다.
1️⃣ 주요 기능 및 사용 방식.
1. Spring Application Context 로드
@SpringBootTest 는 기본적으로 애플리케이션의 전체 컨텍스트를 로드합니다.
이 컨텍스트는 실제 애플리케이션을 구동할 때와 동일하게 설정되어, 테스트 환경에서 애플리케이션이 어떻게 동작하는지 검증할 수 있습니다.
2. 테스트 환경 설정
@SpringBootTest 애노테이션은 다양한 속성을 통해 테스트 환경을 설정할 수 있습니다.
예를 들어, 특정 프로파일을 활성화하거나, 테스트용 설정 파일을 사용할 수 있습니다.
@SpringBootTest(properties = "spring.config.name=test-application")와 같이 속성을 지정할 수 있습니다.
3. 웹 환경 설정
@SpringBootTest는 다양한 웹 환경 모드를 지원합니다.
WebEnviroment.MOCK : 기본값으로, 웹 환경 없이 MockMvc를 사용해 서블릿 환경을 모킹합니다.
WebEnviroment.RANDOM_PORT : 테스트에 임의의 포트를 사용하여 내장 서버를 시작합니다.
WebEnviroment.DEFINED_PORT : 애플리케이션이 구성된 기본 포트를 사용합니다.
WebEnviroment.NONE : 웹 환경 없이 애플리케이션 컨텍스트만 로드합니다.
예시
@SpringBootTest(webEnvironment = SpringBootTest.WebEnviroment.RANDOM_PORT)
4. 통합 테스트
이 애노테이션은 단위 테스트와 달리, 애플리케이션의 여러 계층이 통합된 상태에서 테스트를 수행합니다.
이는 데이터베이스, 웹 서버, 서비스 레이어 등이 실제로 어떻게 상호작용하는지를 확인할 수 있게 해줍니다.
5. TestConfiguration 클래스 사용 가능
@SpringBootTest 와 함께 @TestConfiguration 을 사용하여 테스트를 위해 특별히 구성된 빈(Bean)이나 설정을 정의할 수 있습니다.
2️⃣ 예시 코드
@SpringBootTest
public class MyServiceIntegrationTest {
@Autowired
private MyService myService;
@Test
public void testServiceMethod() {
// Given
// Setup initial conditions
// When
String result = myService.performAction();
// Then
assertEquals("ExpectedResult", result);
}
}
위의 예시에서 @SpringBootTest 는 MyServiceIntegrationTest 클래스가 Spring Application Context에서 실행될 수 있도록 하고, MyService 빈이 실제로 주입되어 테스트가 실행됩니다.
3️⃣ 요약
@SpringBootTest는 Spring Boot 애플리케이션에서 통합 테스트를 쉽게 수행할 수 있도록 돕는 강력한 애노테이션입니다.
이 애노테이션을 사용하면 애플리케이션의 전체 컨텍스트를 로드한 상태에서 테스트할 수 있으며, 복잡한 애플리케이션 시나리오를 검증하는 데 유용합니다.
-
🍃[Spring] 자바 코드로 직접 스프링 빈 등록하기.
🍃[Spring] 자바 코드로 직접 스프링 빈 등록하기.
스프링에서 자바 코드로 스프링 빈을 직접 등록하는 방법은 주로 @Configuration 애노테이션과 @Bean 애노테이션을 사용하여 이루어 집니다.
이 방식은 XML 설정 파일 대신 자바 클래스를 사용하여 스프링 빈을 정의하고 관리하는 방법입니다.
1️⃣ @Configuration 과 @Bean 을 사용한 빈 등록
@Configuration
이 애노테이션은 해당 클래스가 하나 이상의 @Bean 메서드를 포함하고 있으며, 스프링 컨테이너에서 빈 정의를 생성하고 처리할 수 있는 설정 클래스임을 나타냅니다.
@Bean
이 애노테이션은 메서드 레벨에서 사용되며, 메서드의 리턴값이 스프링 컨테이너에 의해 관리되는 빈(Bean)이 됨을 나타냅니다.
2️⃣ 예시.
아래는 MemoryMemberRepository 클래스를 자바 코드로 스프링 빈으로 등록하는 방법을 보여주는 예시입니다.
1. 빈으로 등록할 클래스 정의
```java
package com.devkobe.hello_spring.repository;
import com.devkobe.hello_spring.domain.Member;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public class MemoryMemberRepository implements MemberRepository {
private static Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L;
@Override
public Member save(Member member) {
member.setId(++sequence);
store.put(member.getId(), member);
return member;
}
@Override
public Optional<Member> findById(Long id) {
return Optional.ofNullable(store.get(id));
}
@Override
public Optional<Member> findByName(String name) {
return store.values().stream()
.filter(member -> member.getName().equals(name))
.findAny();
}
@Override
public List<Member> findAll() {
return new ArrayList<>(store.values());
}
public void clearStore() {
store.clear();
} } ```
2. 자바 설정 파일에서 빈 등록
```java
package com.devkobe.hello_spring.config;
import com.devkobe.hello_spring.repository.MemberRepository;
import com.devkobe.hello_spring.repository.MemoryMemberRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
} } ```
3. 스프링 컨테이너에서 빈 사용
```java
package com.devkobe.hello_spring.service;
import com.devkobe.hello_spring.repository.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
// 비즈니스 로직 메서드들... } ```
3️⃣ 설명.
AppConfig 클래스
@Configuration 애노테이션을 사용하여 이 클래스가 스프링 설정 클래스로 사용될 것임을 명시합니다.
memberRepository() 메서드는 @Bean 애노테이션으로 정의되어 있으며, 이 메서드의 리턴값이 스프링 컨테이너에 의해 관리되는 빈이 됩니다.
이 경우, MemoryMemberRepository 객체가 빈으로 등록됩니다.
빈 사용
MemberService 클래스에서 MemberRepository 타입의 빈이 생성자 주입 방식으로 주입됩니다.
이때, AppConfig 클래스에서 등록된 MemoryMemberRepository 빈이 주입됩니다.
4️⃣ 왜 자바 설정을 사용할까?
1. 타입 안정성
자바 코드는 컴파일 시점에 타입을 체크할 수 있으므로, XML보다 타입 안정성이 높습니다.
2. IDE 지원
자바 기반 설정은 IDE의 자동 완성 기능과 리팩토링 도구를 잘 지원받을 수 있습니다.
3. 코드 재사용성
자바 설정 클래스는 일반 자바 코드처럼 재사용 사능하며, 상속과 조합 등을 활용할 수 있습니다.
5️⃣ 결론
스프링에서 자바 코드로 빈을 등록하는 방법은 @Configuration 과 @Bean 애노테이션을 사용한 방법입니다.
이 방식은 XML 기반 설정보다 더 타입 안전하고, 유지보수하기 쉬우며, 현대적인 스프링 애플리케이션에서 자주 사용됩니다.
-
🍃[Spring] 스프링 컨테이너(Spring Container)란?
🍃[Spring] 스프링 컨테이너(Spring Container)란?
1️⃣ 스프링 컨테이너(Spring Container)란?
스프링 컨테이너(Spring Container)는 스프일 프레임워크의 핵심 구성 요소로, 애플리케이션에서 사용되는 객체들은 관리하고 조정하는 역할을 합니다.
이 컨테이너는 객체의 생성, 초기화, 의존성 주입, 설정 및 라이프사이클을 관리하여 애플리케이션의 주요 컴포넌트들이 잘 협력할 수 있도록 돕습니다.
스프링 컨테이너는 종종 IoC(Inversion of Control) 컨테이너 또는 DI(Dependency Injection) 컨테이너 라고도 불립니다.
2️⃣ 스프링 컨테이너의 주요 기능.
1. 빈(Bean) 관리
스프링 컨테이너는 애플리케이션에 필요한 모든 빈(Bean)을 정의하고 생성합니다.
이 빈들은 XML 설정 파일, 자바 설정 클래스, 또는 애노테이션을 통해 정의될 수 있습니다.
빈의 라이프사이클(생성, 초기화, 소멸)을 관리하고, 의존성을 자동으로 주입하여 빈 간의 결합도를 낮추어 줍니다.
2. 의존성 주입(Dependency Injection)
스프링 컨테이너는 객체 간의 의존성을 자동으로 주입하여, 객체들이 직접 다른 객체를 생성하거나 관리하지 않도록 합니다.
이를 통해 코드의 유연성과 재사용성을 높입니다.
의존성 주입은 생성자 주입, 세터 주입, 필드 주입 등 다양한 방법으로 이루어질 수 있습니다.
3. 설정 관리
컨테이너는 애플리케이션의 설정 정보를 관리합니다.
이는 빈의 정의뿐만 아니라, 데이터베이스 연결 설정, 메시지 소스, 트랜잭션 관리 등의 다양한 설정을 포함합니다.
4. 라이프사이클 인터페이스 지원
컨테이너는 빈의 라이프사이클 인터페이스(InitializingBean, DisposableBean)을 통해 빈의 초기화 및 소명 작업을 쉽게 구현할 수 있도록 지원합니다.
또한 @PostConstruct, @PreDestroy 애노테이션을 통해 라이프사이클 콜백을 간단하게 구현할 수 있습니다.
5. AOP(Aspect-Oriented Programming) 지원
스프링 컨테이너는 AOP 기능을 지원하여, 애플리케이션 전반에 걸쳐 공통적으로 사용되는 로직(예: 로깅, 트랜잭션 관리)을 비즈니스 로직과 분리하여 모듈화할 수 있게 합니다.
3️⃣ 스프링 컨테이너의 종류.
스프링에는 다양한 컨테이너 구현체가 있으며, 대표적으로 다음과 같은 종류가 있습니다.
1. BeanFactory
스프링의 가장 기본적인 컨테이너로, 빈의 기본적인 생성과 의존성 주입을 제공합니다.
하지만 BeanFactory는 지연 로딩(lazy loading) 방식으로 동작하므로, 빈이 실제로 요청될 때 생성됩니다.
2. ApplicationContext
BeanFactory의 확장판으로, 대부분의 스프링 애플리케이션에서 사용되는 컨테이너입니다.
ApplicationContext 는 BeanFactory의 기능을 포함하면서도, 다양한 기능(예: 이벤트 발행, 국제화 메시지 처리, 환경 정보 관리)을 추가로 제공합니다.
ApplicationContext 의 구현체에는 ClassPathXmlApplicationContext, FileSystemXmlApplicationContext, AnnotationConfigApplicationContext 등이 있습니다.
4️⃣ 스프링 컨테이너의 동작 과정.
1. 빈 정의 로드
컨테이너가 시작되면, XML 파일, 자바 설정 파일, 애노테이션 등을 통해 빈의 정의를 읽어들입니다.
2. 빈 생성 및 초기화
컨테이너는 필요한 빈들을 생성하고 초기화 작업을 수행합니다.
이때 의존성이 있는 경우, 필요한 빈들을 먼저 생성하여 주입합니다.
3. 의존성 주입
빈의 생성 과정에서 필요한 의존성들이 주입됩니다.
이 과정에서 생성자 주입, 세터 주입 등이 사용됩니다.
4. 빈 제공
컨테이너는 요청 시 빈을 제공하며, 애플리케이션은 이 빈을 통해 다양한 작업을 수행할 수 있습니다.
5. 빈 소멸
애플리케이션이 종료되거나 컨테이너가 종료될 때, 컨테이너는 빈의 소멸 작업을 처리합니다.
스프링 컨테이너는 이 모든 과정을 자동으로 처리하며, 이를 통해 개발자는 비즈니스 로직에 집중할 수 있게됩니다.
-
🍃[Spring] 계층형 아키텍처(Layered Architecture), 3계층 아키텍처(Three-Tier Architecture)
🍃[Spring] 계층형 아키텍처(Layered Architecture), 3계층 아키텍처(Three-Tier Architecture)
Controller를 통해 외부의 요청을 받고, Service에서 비즈니스 로직을 처리하며, Repository에서 데이터를 저장하고 관리하는 패턴은 “계층형 아키텍처(Layered Architecture)” 또는 “3계층 아키텍처(Three-Tier Architecture)” 라고 부릅니다.
1️⃣ 계층형 아키텍처(Layered Architecture)
이 아키텍처 패턴은 애플리케이션을 여러 계층으로 나누어 각 계층이 특정한 역할을 담당하도록 구조와합니다.
이 방식은 소프트웨어의 복잡성을 줄이고, 코드의 유지보수성을 높이며, 테스트하기 쉽게 만들어줍니다.
스프링 프레임워크에서 이 패턴은 자주 사용됩니다.
2️⃣ 각 계층별 역할.
1. Presentation Layer(프레젠테이션 계층) - Controller
사용자 인터페이스와 상호작용하는 계층입니다.
외부의 요청을 받아서 처리하고, 응답을 반환합니다.
스프링에서는 주로 @Controller 또는 @RestController 를 사용하여 이 계층을 구현합니다.
2. Business Logic Layer(비즈니스 로직 계층) - Service
비즈니스 로직을 처리하는 계층입니다.
데이터의 처리, 계산, 검증 등 핵심적인 애플리케이션 로직이 구현됩니다.
스프링에서는 주로 @Service 애노테이션을 사용하여 이 계층을 구현합니다.
3. Data Access Layer(데이터 접근 계층) - Repository
데이터베이스나 외부 데이터 소스와 상호작용하는 계층입니다.
데이터의 CRUD(Create, Read, Update, Delete) 작업을 처리합니다.
스프링에서는 주로 @Repository 애노테이션을 사용하여 이 계층을 구현하며 JPA, MyBatis, Hibernate 등의 ORM(Object-Relational Mapping) 도구와 함께 사용됩니다.
3️⃣ 이 패턴의 주요 장점.
모듈화
각 계층이 독립적으로 관리되므로, 각 계층의 코드가 명확히 분리됩니다.
유지보수성
비즈니스 로직, 데이터 접근, 그리고 프레젠테이션 로직이 분리되어 있어, 각 부분을 독립적으로 수정하거나 확장하기 쉽습니다.
테스트 용이성
각 계층을 독립적으로 테스트할 수 있어, 단위 테스트와 통합 테스트가 용이합니다.
유연성
특정 계층을 변경하거나 대체할 때, 다른 계층에 미치는 영향을 최소화할 수 있습니다.
이 계층형 아키텍처는 스프링 프레임워크를 사용하는 대부분의 애플리케이션에서 채택하는 일반적인 구조이며, 소프트웨어 설계의 베스트 프랙티스 중 하나로 널리 인정받고 있습니다.
-
🍃[Spring] 의존성 주입(Dependency Injection)을 통한 느슨한 결합(Loose Coupling) 유지.
🍃[Spring] 의존성 주입(Dependency Injection)을 통한 느슨한 결합(Loose Coupling) 유지.
아래의 코드에서 @Autowired 로 MemberService 클래스의 생성자에 MemberRepository 인터페이스를 주입받는 이유는 의존성 주입(Dependency Injection) 을 통해 느슨한 결합(Loose Coupling) 을 유지하기 위합입니다.
이는 객체지향 설계에서 매우 중요한 원칙 중 하나로, 클래스 간의 결합도를 낮춰 코드의 유연성과 확장성을 높이는 데 기여합니다.
1️⃣ 전체 코드.
// MemberRepository
import com.devkobe.hello_spring.domain.Member;
import java.util.List;
import java.util.Optional;
public interface MemberRepository {
Member save(Member member);
Optional<Member> findById(Long id);
Optional<Member> findByName(String name);
List<Member> findAll();
}
// MemoryMemberRepository
import com.devkobe.hello_spring.domain.Member;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.springframework.stereotype.Repository;
@Repository
public class MemoryMemberRepository implements MemberRepository {
private static Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L;
@Override
public Member save(Member member) {
member.setId(++sequence);
store.put(member.getId(), member);
return member;
}
@Override
public Optional<Member> findById(Long id) {
return Optional.ofNullable(store.get(id));
}
@Override
public Optional<Member> findByName(String name) {
return store.values().stream()
.filter(member -> member.getName().equals(name))
.findAny();
}
@Override
public List<Member> findAll() {
return new ArrayList<>(store.values());
}
public void clearStore() {
store.clear();
}
}
// MemberService
import com.devkobe.hello_spring.domain.Member;
import com.devkobe.hello_spring.repository.MemberRepository;
import com.devkobe.hello_spring.repository.MemoryMemberRepository;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
/*
* 회원 가입
*/
public Long join(Member member) {
validateDuplicateMember(member); // 중복 회원 검증
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
memberRepository.findByName(member.getName())
.ifPresent(m -> {
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
}
/*
* 전체 회원 조회
*/
public List<Member> findMembers() {
return memberRepository.findAll();
}
public Optional<Member> findOne(Long memberId) {
return memberRepository.findById(memberId);
}
}
2️⃣ 구체적인 이유.
1. 인터페이스를 통한 유연성 확보.
MemberRepository 는 인터페이스로, MemoryMemberRepository 와 같은 구현체들이 이 인터페이스를 구현합니다.
인터페이스를 통해 MemberService 는 특정 구현체에 의존하지 않으며, MemberRepository 인터페이스에 의존하게 됩니다.
이는 MemberService 가 MemoryMemberRepository 나 다른 MemberRepository 구현체(JdbcMemberRepository, JpaMemberRepository 등)에 쉽게 교체될 수 있음을 의미합니다.
예를 들어, 나중에 메모리가 아닌 데이터베이스에 회원 정보를 저장하는 방식으로 전환하고 싶다면, MemoryMemberRepository 대신 새로운 구현체를 주입하면 됩니다.
2. 느슨한 결합.
MemberService 는 MemberRepository 인터페이스에만 의존하기 때문에, 어떤 구현체가 실제로 사용될지는 스프링 컨테이너가 결정합니다.
이렇게 하면 MemberService 는 구현체가 무엇인지 알 필요가 없으므로, 구현체가 변경되더라도 MemberService 를 수정할 필요가 없습니다.
이 방식은 유지보수성을 크게 향상시킵니다.
새로운 저장소 방식이 도입되더라도, 기존 비즈니스 로직에 영향을 주지 않고 새로운 기능을 추가할 수 있습니다.
3. 스프링의 의존성 주입 메커니즘 활용.
스프링은 자동으로 @Autowired 를 사용하여 적절한 MemberRepository 구현체를 찾아 주입합니다.
MemoryMemberRepository 클래스에 @Repository 애노테이션이 붙어 있기 때문에, 스프링 컨테이너는 이 클래스를 MemberRepository 타입의 빈으로 인식하고 관리하게 됩니다.
스프링은 MemberRepository 인터페이스 타입의 빈을 주입해야 하는 경우, 해당 인터페이스를 구현한 클래스 중 하나를 선택해 주입합니다.
이 예제에서는 MemoryMemberRepository 가 주입됩니다.
3️⃣ 결론.
이러한 설계는 코드의 유연성과 테스트 용이성을 크게 향상시킵니다.
인터페이스를 사용함으로써, MemberService 는 특정 구현체에 구애받지 않고 다양한 환경에서 재사용될 수 있습니다.
또한, 이는 스프링의 DI 원칙에 따라, 컴포넌트 간의 결합도를 낮추고, 애플리케이션이 변화에 잘 대응할 수 있도록 설계하는 방법입니다.
-
🍃[Spring] `@Controller` 애너테이션 사용시 일어나는 일.
🍃[Spring] @Controller 애너테이션 사용시 일어나는 일.
1️⃣ 스프링 프레임워크에서 @Controller 애노테이션 사용시 어떤 일이 일어날까요?
스프링 프레임워크에서 @Controller 애노테이션을 사용하면, 해당 클래스가 스프링 MVC의 웹 컨트롤러로 동작하도록 설정됩니다.
@Controller 는 기본적으로 웹 요청을 처리하고, 적절한 응답을 생성하는 역할을 담당하는 클래스를 정의할 때 사용됩니다.
@Controller 애노테이션을 사용하면 다음과 같은 일들이 벌어집니다.
1. 스프링 빈으로 등록.
@Controller 애노테이션이 적용된 클래스는 스프링의 컴포넌트 스캔 메커니즘에 의해 자동으로 스프링 컨텍스트에 빈으로 등록됩니다.
이는 @Component 와 유사하게 동작하며, 스프링이 이 클래스를 관리하도록 만듭니다.
2. 요청 처리 메서드 매핑.
@Controller 가 달린 클래스 내의 메서드들은 @RequestMapping, @GetMapping, @PostMapping 등과 같은 요청 매핑 애노테이션을 통해 특정 HTTP 요청을 처리하는 메서드로 매핑될 수 있습니다.
이러한 매핑을 통해 특정 URL로 들어오는 요청이 어떤 메서드에 의해 처리될지 결정됩니다.
3. 모델과 뷰.
@Controller 는 주로 모델과 뷰를 처리합니다.
요청이 컨트롤러에 도달하면, 컨트롤러는 필요한 데이터를 모델에 담고, 적절한 뷰(예: JSP, Thymeleaf 템플릿)를 반환하여 사용자에게 응답을 보냅니다.
스프링은 이 작업을 쉽게 할 수 있도록 다양한 기능을 제공합니다.
4. 비즈니스 로직과 서비스 계층.
컨트롤러는 보통 직접 비즈니스 로직을 처리하지 않고, 서비스 계층을 호출하여 필요한 처리를 위임합니다.
컨트롤러는 사용자 입력을 받아 서비스로 전달하고, 서비스의 결과를 받아 사용자에게 반환하는 역할을 합니다.
5. 예외 처리.
@Controller 애노테이션을 사용하는 클래스는 또한 @ExceptionHandler 를 사용하여 특정 예외를 처리할 수 있습니다.
이를 통해 컨트롤러 내에서 발생하는 예외를 잡아 특정 응답을 반환하거나 에러 페이지를 보여줄 수 있습니다.
요약하면, @Controller 애노테이션은 해당 클래스를 스프링 MVC에서 요청을 처리하는 컨트롤러로 정의하며, HTTP 요청을 처리하고 적절한 응답을 생성하는데 중요한 역할을 합니다.
-
🍃[Spring] 빈(Bean)이란?
🍃[Spring] 빈(Bean)이란?
1️⃣ 빈(Bean)이란?
스프링 프레임워크에서 빈(Bean) 이란, 스프링 IoC(Inversion of Control) 컨테이너에 의해 관리되는 객체를 의미합니다.
스프링 빈은 애플리케이션 전반에서 사용될 수 있도록 스프링 컨텍스트에 등록된 인스턴스입니다.
빈은 보통 애플리케이션의 핵심 로직이나 비즈니스 로직을 수행하는 객체들로, 스프링은 이러한 빈들을 효율적으로 관리하고 주입합니다.
빈의 정의와 동작은 스프링의 핵심 개념인 의존성 주입(Dependency Injection, DI) 과 밀접한 관련이 있습니다.
2️⃣ 스프링 빈의 주요 특징.
1. 싱글톤(Singleton) 스코프
기본적으로 스프링 빈은 싱글톤 스코프로 관리됩니다.
즉, 특정 빈 타입에 대해 스프링 컨테이너는 하나의 인스턴스만을 생성하고 애플리케이션 내에서 재사용합니다.
물론, 필요에 따라 프로토타입, 요청, 세션 등 다른 스코프로 빈을 정의할 수도 있습니다.
2. 의존성 관리
스프링 컨테이너는 빈의 의존성을 자동으로 주입합니다.
즉, 빈이 생성될 때 필요한 의존성(다른 빈이나 리소스)을 스프링이 자동으로 주입해줍니다.
이 과정에서 생성자 주입, 세터 주입, 필드 주입 등 다양한 방법이 사용될 수 있습니다.
3. 라이프사이클 관리
스프링은 빈의 생성부터 소멸까지의 라이프사이클을 관리합니다.
빈이 생성될 때 초기화 작업을 하거나, 빈이 소멸될 때 클린업 작업을 수행할 수 있도록 다양한 훅(Hook)을 제공하며, 이 과정에서 @PostConstruct, @PreDestroy 같은 애노테이션을 사용할 수 있습니다.
4. 설정 및 구성
빈은 XML 설정 파일이나 자바 설정 클래스에서 정의될 수 있습니다.
또한, @Component, @Service, @PostConstruct, @PreDestroy 같은 애노테이션을 사용할 수 있습니다.
5. 느슨한 결합(Loose Coupling)
스프링 빈을 사용하면 객체 간의 의존성을 직접 설정하는 것이 아니라, 스프링이 관리하므로 코드가 더욱 유연하고 테스트하기 쉬워집니다.
이는 애플리케이션의 유지보수성과 확장성을 높여줍니다.
3️⃣ 스프링 빈의 정의 예시.
다음은 빈이 어떻게 정의되고, 스프링 컨테이너가 이를 관리하는지에 대한 간단한 예시입니다.
@Component
public class MyService {
public void performService() {
System.out.println("Service is being performed.")
}
}
위 코드에서 @Component 애노테이션이 적용된 MyService 클래스는 스프링 빈으로 등록됩니다.
스프링 컨테이너는 이 빈을 관리하고, 필요할 때 의존성을 주입합니다.
빈을 스프링 컨텍스트에서 가져와 사용하는 예시는 다음과 같습니다.
```java
@Autowired
private MyService myService;
public void useService() {
myService.performService();
}
```
여기서 @Autowired 애노테이션은 MyService 타입의 빈을 스프링 컨테이너에서 주입받아 useService 메서드에서 사용할 수 있도록 합니다.
결론적으로, 스프링 빈은 스프링 애플리케이션에서 핵심적인 역할을 하는 객체로, 스프링 컨테이너가 관리하는 인스턴스이며, 이를 통해 애플리케이션의 구성 요소들이 유연하고 효율적으로 동작하도록 돕습니다.
-
-
🍃[Spring] 일반적인 웹 애플리케이션 계층 구조와 클래스 의존관계.
🍃[Spring] 일반적인 웹 애플리케이션 계층 구조와 클래스 의존관계.
1️⃣ 일반적인 웹 애플리케이션 계층 구조.
Controller : 웹 MVC의 Controller 역할.
사용자의 요청을 받아 이를 처리할 비즈니스 로직(서비스 레이어)에 전달하고, 그 결과를 다시 사용자에게 응답하는 역할을 합니다.
주로 HTTP 요청을 처리하고, 올바른 응답을 생성합니다.
컨트롤러는 사용자로부터 입력을 받아 해당 입력을 서비스 레이어로 전달하고, 서비스 레이어에서 처리된 결과를 사용자에게 반환합니다.
이는 주로 웹 애플리케이션의 엔트포인트(예: '/login', '/signup' 와 같은 URL)에 대응됩니다.
Service : 핵심 비즈니스 로직 구현.
비즈니스 로직을 처리하는 계층입니다.
컨트롤러와 리포지토리 사이에서 중간 역할을 하며, 여러 리포지토리로부터 데이터를 가져오거나 가공하고, 이를 다시 컨트롤러에 전달합니다.
서비스 계층은 애플리케이션의 핵심 비즈니스 로직이 위치하는 곳입니다.
예를 들어, 사용자 인증, 결제 처리, 이메일 전송 등의 주요 기능이 이 계층에서 처리됩니다.
Repository: 데이터베이스에 접근, 도메인 객체를 DB에 저장하고 관리.
데이터베이스와 상호작용하는 계층입니다.
데이터의 저장, 검색, 갱신, 삭제 등의 작업을 처리하며, 데이터베이스와의 직접적인 통신을 담당합니다.
리포지토리는 데이터를 처리하기 위한 SQL 쿼리나 ORM(Object-Relational Mapping) 작업을 담당합니다.
이 계층은 서비스 계층에서 필요한 데이터를 가져오거나, 새 데이터를 저장하는 역할을 합니다.
Domain: 비즈니스 도메인 객체.
예를 들어 회원, 주문 쿠폰 등등 주로 데이터베이스에 저장하고 관리됨.
애플리케이션의 핵심 엔티티(Entity)와 비즈니스 규칙을 정의하는 계층입니다.
보통 객체로 표현되며, 비즈니스 로직의 일부를 캡슐화합니다.
도메인 계층은 애플리케이션에서 중요한 객체들(예: 'User', 'Product', 'Order' 등)을 정의하고, 이 객체들이 어떤 방식으로 상호작용하는지를 나타냅니다.
이는 애플리케이션이 어떤 비즈니스 문제를 해결하는지에 대한 모델을 나타냅니다.
2️⃣ 클래스 의존관계.
회원 비즈니스 로직에는 회원 서비스가 있다.
회원을 저장하는 것은 인터페이스로 설계 되어있다.
그 이유는 아직 데이터 저장소가 선정되지 않았음을 가정하고 설계했기 때문이다.
그리고 구현체를 우선은 메모리 구현체로 만들것이다.
그 이유는 일단 개발은 해야하므로 굉장히 단순한 메모리 기반의 데이터 저장소를 사용하여 메모리 구현체로 만든다.
향후에 메모리 구현체를 구체적인 기술이 선정이 되면(RDB, NoSQL 등) 교체할 것이다.
교체하려면 Interface가 필요하므로 Interface를 정의한 것이다.
아직 데이터 저장소가 선정되지 않아서, 우선 인터페이스로 구현 클래스를 변경할 수 있도록 설계
데이터 저장소는 RDB, NoSQL 등등 다양한 저장소를 고민중인 상황으로 가정
개발을 진행하기 위해서 초기 개발 단계에서는 구현체로 가벼운 메모리 기반의 데이터 저장소 사용
-
-
-
-
🍃[Spring] slf4j와 logback.
🍃[Spring] slf4j와 logback.
1️⃣ slf4j
'SLF4J(Simple Logging Facade for Java)' 는 Java 애플리케이션에서 로그 기록을 쉽게 관리하고 다른 로깅 프레임워크와 통합할 수 있도록 도와주는 로깅 인터페이스입니다.
'SLF4J' 는 다양한 로깅 프레임워크(e.g, Log4j, Logback, java.util.logging 등)에 대해 공통된 인터페이스를 제공하여 개발자가 특정 로깅 프레임워크에 종속되지 않고 유연하게 로그를 관리할 수 있도록 합니다.
1️⃣ slf4j의 주요 기능.
로깅 프레임워크와의 추상화
slf4j는 여러 로깅 프레임워크에 종속되지 않게 합니다.
예를 들어, 코드에서 slf4j 인터페이스를 사용하면 나중에 로깅 프레임워크를 쉽게 교체할 수 있습니다.
로깅 성능 최적화
slf4j는 문자열 병합에 따른 성능 문제를 피할 수 있도록 지원합니다.
예를 들어, slf4j는 로그 메시지의 문자열 결합을 지연시켜, 로그가 실제로 기록될 때만 결합이 발생하도록 합니다.
API 일관성
slf4j를 사용하면 로깅을 위한 일관된 API를 제공받을 수 있으며, 이를 통해 로깅을 표준화할 수 있습니다.
2️⃣ 사용 방법.
slf4j를 사용하기 위해서는, 우선 slf4j 인터페이스와 이를 구현한 로깅 프레임워크(예: Logback)를 프로젝트에 포함시켜야 합니다.
코드는 일반적으로 아래와 같이 사용됩니다.
```java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyClass {
// Logger 생성
private static final Logger logger = LoggerFactory.getLogger(MyClass.class);
public void doSomthing() {
// 로그 메시지 기록
logger.info("This is an info message");
logger.debug("This is a debug message");
} } ``` - 이 코드는 **`'slf4j'`** 를 이용해 로그를 기록하는 예로, 로깅 메시지는 설정된 로깅 프레임워크를 통해 출력됩니다.
✏️ 요약.
slf4j는 Java 애플리케이션에서 로깅 프레임워크 간의 추상화 레이어를 제공하며, 코드가 특정 로깅 프레임워크에 종속되지 않도록 합니다.
이를 통해 유연한 로깅 관리가 가능해집니다.
2️⃣ logback
'logback' 은 Java 애플리케이션에서 사용되는 고성능 로깅 프레임워크로, slf4j의 권장 구현체 중 하나입니다.
'logback' 은 slf4j를 통해 접근할 수 있으며, 뛰어난 성능과 유연한 설정, 다양한 기능을 제공하는 것이 특징입니다.
1️⃣ logback의 주요 구성 요소.
Logback Classic
slf4j와 직접 통합되는 logback의 핵심 모듈입니다.
'Logback Classic' 은 Java 애플리케이션에서 로깅 기능을 수행하며, 다양한 로그 레벨(INFO, DEBUG, WARN, ERROR 등)을 지원합니다.
Logback Core
Logback Classic과 Logback Access(웹 애플리케이션용)를 기반으로 하는 일반적인 로깅 기능을 제공합니다.
'Logback Core' 는 Appender, Layout, Filter 등과 같은 기본 구성 요소를 포함합니다.
Logback Access
웹 애플리케이션에서 HTTP 요청과 응답을 로깅할 수 있도록 지원하는 모듈입니다.
주로 Java Servlet 환경에서 사용됩니다.
3️⃣ logback의 특징.
높은 성능
'logback' 은 빠른 로깅 성능을 제공하며, 특히 대규모 애플리케이션에서 효과적입니다.
유연한 구성
'logback' 은 XML 또는 Groovy 스크립트로 로깅 설정을 구성할 수 있습니다.
이를 통해 다양한 조건에 따라 로깅 동작을 세밀하게 제어할 수 있습니다.
조건부 로깅
'logback' 은 특정 조건에서만 로깅을 수행하도록 설정할 수 있어, 불필요한 로그 기록을 줄이고 성능을 최적화할 수 있습니다.
이전 로그 프레임워크와의 호환성
'logback' 은 기존의 'Log4j' 설정 파일을 사용할 수 있는 기능을 제공하여, 기존 'Log4j' 사용자가 쉽게 'logback' 으로 전환할 수 있도록 돕습니다.
다양한 출력 형식
'logback' 은 콘솔, 파일, 원격 서버, 데이터베이스 등 다양한 출력 대상으로 로그를 기록할 수 있으며, 출력 형식을 자유롭게 정의할 수 있습니다.
4️⃣ logback 사용 예제.
<configuration>
<!-- 콘솔에 로그를 출력하는 Appender -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 파일에 로그를 기록하는 Appender -->
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>mylog.log</file>
<append>true</append>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 루트 로거 설정 -->
<root level="debug">
<appender-ref ref="STDOUT" />
<appender-red red="FILE" />
</root>
</configuration>
이 예시는 콘솔과 파일에 로그를 출력하도록 설정하는 간단한 예시입니다.
logback은 이외에도 복잡한 요구 사항을 충족할 수 있는 다양한 기능을 제공하고 있습니다.
✏️ 요약.
logback은 Java 애플리케이션에서 사용되는 고성능 로깅 프레임워크로, slf4j와 함께 사용됩니다.
logback은 유연한 설정과 높은 성능, 다양한 기능이 있습니다.
Touch background to close