Spring 핵심 기능
- IoC/DI, AOP, PSA
- Spring Boot, Spring Data, Spring Batch, Spring Cloud, Spring Security에 중점
- 필요하나 모듈만 선택하여 사용 가능
- 마이크로서비스 아키텍처로 변환 중
- "테스트의 용이성"과 "느슨한 결함"에 중점을 두고 개발
IoC, DI
- IoC(제어의 역전): Spring Container가 객체를 관리
- DI(의존성 주입): 객체 사용을 위해 외부에서 주입을 받음. 순환 참조 방지. 코드테스트 유리
AOP
- AOP(Aspect Oriented Programming): 관점지향 프로그램
- Spring Application의 MVC Web Application에서는 Web Layer + Business Layer, Data Layer로 정의
- Web Layer: REST API 제공. 클라이언트 중심 로직 적용
- Business Layer: 내부 정책에 따른 로직 개발
- Data Layer: 데이터 베이스 및 외부와 연동 처리
(주요 Annotation)
Annotation | Descriptoion |
@Aspect | AOP를 정의하는 Class에 할당 |
@Pointcut | 기능을 어디에 적용시킬지 AOP 적용 지점 설정 |
@Before | 메소드 실행하기 이전 실행 |
@After | 메소드가 성공/예외 발생 모든 경우에 실행 |
@AfterReturning | 메소드 호출 성골시 실행 |
@AfterThrowing | 메소드 호출 실패/예외 발생시 실행 |
@Around | Before/After 모두 제어 |
(AOP 실습)
1) Spring Initializr 생성 후 프로젝트 실행
2) build.gradle의 dependencies에 implementation 'org.springframework.boot:spring-boot-starter-aop' 추가
3) API 설계 후 구현
(Class: RestApiController.java)
@RestController
@RequestMapping("/api")
public class RestApiController {
@GetMapping("/get/{id}")
public String get(@PathVariable Long id, @RequestParam String name) {
return id + " " + name;
}
@PostMapping("/post")
public User post(@RequestBody User user) {
return user;
}
@Decode
@PostMapping("/put")
public User put(@RequestBody User user) {
return user;
}
@Timer
@DeleteMapping("/delete")
public void delete() throws InterruptedExecution {
Thread.sleep(1000 * 2);
}
}
(Class: User)
public class User {
private String id;
private Interger password;
// getter
//setter
public String toString() {
return "User{" +
"id= '" + id + '\'' +
", pw='" + pw + '\'' +
'}';
}
}
(Class: ParameterAop)
@Aspect
@Component
public class ParameterAop {
@Pointcut("execution(* com.example.aop.controller..*.*(..))")
private void cut() {
}
@Before("cut()")
public void before(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
System.out.println(method.getName());
Object[] args = joinPoint.getArgs();
for(Object obj: args) {
System.out.println("type: " + obj.getClass().getSimpleName());
}
}
@AfterReturning("value = cut()", returning = "returnObj")
public void afterReturn(JoinPoint joinPoint, Object returnObj) {
}
}
(Class: TimerAop)
@Aspect
@Component
public class TimerAop {
@Pointcut("execution(* com.example.aop.controller..*.*(..))")
private void cut() {
}
@Pointcut("@annotation(com.example.aop.annotation.Timer)")
private void enableTimer() {
}
@Around("cut() && enableTimer()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
Stopwatch.stopWatch = new StopWatch();
stopWatch.start();
Object result = joinPoint.proceed(); // 메서드 실행후 객체 리턴
stopWatch.stop();
System.out.println("total time : " + stopWatch.getTotalTimeSeconds());
}
}
(Annotation: Timer)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Timer {
}
(Class: DecodeAop)
@Aspect
@Component
public class DecodeAop {
@Pointcut()
private void cut() {
}
@Pointcut("@annotation(com.example.aop.annotation.Decode)")
private void enableDecode(){
}
@Before("cut() && enableDecode()")
public void before(JoinPoint joinPoint) throws UnsupportedEncodingException {
Object[] args = joinPoint.getArgs();
for (Object arg : args) {
if (arg instanceof User) {
User user = User.class.cast(arg);
String base64Email = user.getEmail();
String email =new String(Base64.getDecoder().decode(base64Email), "UTF-8");
user.setEmail(email);
}
}
}
@AfterReturning(value = "cut() && enableDecode()", returning = "returnObj")
public void afterReturn(JoinPoint joinPoint, Object returnObj) {
if (returnObj instanceof User) {
User user = User.class.cast(returnObj);
String email = user.getEmail();
String base64Email = Base64.getEncoder().encodeToString(email.getBytes());
user.setEmail(base64Email);
}
}
}
(Interface: Decode)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Decode {
}
ObjectMapper
- Text/Json → Object
- Object → Text/Jsson
var objectMapper = new ObjectMapper();
var user = new User(...);
var text = objectMapper.writeValueAsString(user);
var objectUser = objectMapper.readValue(text, User.class);
(JSON 파싱)
String json = objectMapper.writeValueAsString(user);
JsonNode jsonNode = jsonNode.get("name").asText();
String _name = jsonNode.get("name").asText();
int _age = jsonNode.get("age").asInt();
JsonNode cars = jsonNode.get("cars");
ArrayNode arrayNode = (ArrayNode)cars;
// Object를 특정 Type으로 변경
List<Car> _cars = objectMapper.convertValue(arrayNode, new TypeReference<List<Car>>(){});
ObjectNode objectNode = (ObjectNode) jsonNode;
objectNode.put("names", "lee");
objectNode.put("age", 30);
System.println(objectNode.toPrettyString());
- Object Mapper로 JSON 접근
- ObjectMapper는 Java Library
자주 사용하는 Spring Annotation
(Spring)
Annotation | Descriptioin |
@SpringBootApplication | Spring Boot Application으로 설정 |
@Controller | View를 제공하는 Controller로 설정 |
@Valid | POJO Java Class 검증 |
@Configuration | 1개 이상의 Bean을 등록 |
@Component | 1개의 Class를 Bean 등록시 사용 |
@Bean | 1개의 외부 library로부터 생성한 객체 등록시 사용. 메서드에 사용 |
@Autowired | DI를 위한 곳에 사용 |
@Qualifier | 2개 이상의 Bean이 있을 때 어떤 Bean을 사용할지 명시적으로 지정 |
@Resource | @Autowired + @Qualifier의 개념 |
@Aspect | AOP 적용시 사용 |
@Before | AOP 메서드 이전 호출 지정 |
@After | AOP 메서드 호출 이후 지정 (예외 발생 포함) |
@Around | AOP 이전/이후 모두 포함(예외 발생 포함) |
@AfterReturning | AOP 이후 정상일 때 실행 |
@AfterThrowing | AOP 이후 에러 발생시 실행 |
(Rest API)
Annotation | Descriptoin |
@RestController | REST API를 제공하는 controller로 설정 |
@RequestMapping | URL 주소를 매핑 |
@GetMapping | HTTP Get 메서드 URL 주소 매핑 |
@PostMapping | HTTP Post 메서드 URL 주소 매핑 |
@PutMapping | HTTP Put 메서드 URL 주소 매핑 |
@DeleteMapping | HTTP Delete 메서드 URL 주소 매핑 |
@RequestParam | URL Query Parameter 매핑 |
@RequestBody | HTTP Body를 Parsing해서 매핑 |
'백엔드 자료집 > Spring' 카테고리의 다른 글
[Spring] Spring 기능 (1) | 2025.03.05 |
---|---|
[Spring] 참고자료 (0) | 2025.03.03 |