난 도대체 왜 Spring을 사용하고 있는건가....
그래서 한번 적어보고 싶었다.
"spring" 이란?
JAVA의 웹 프레임워크로 JAVA 언어를 기반으로 사용한다.
JAVA로 다양한 어플리케이션을 만들기 위한 프로그래밍 틀(Framework)이다.
그럼 이제 Spring의 특징을 알아보겠다.
특징은 크게 4가지가 있다!
자바를 사용하다 보면, 이런 코드들을 사용한다.
User user1 = new User();
대충 새로운 유저를 만든다는 뜻인데..
이처럼 JAVA는 new 연산자, 인터페이스 호출, 데이터 클래스 호출 방식으로 객체를 생성 & 소멸한다.
Inversion: 반전
즉, Inversion of Control: 제어 반전 이다.
우리(개발자)가 객체들을 생성 & 소멸을 IoC가 대신 관리해준다.
제어권이 IoC에 있다. (제어 반전)
의존성 주입
컨테이너에서 Bean을 먼저 생성해두고 생성한 객체를 지정한 객체에 주입하는 방식
객체가 코드에서 객체 생성에 관여하지 않아도 되기 때문에, 객체 사이의 의존도를 낮출 수 있다.
스프링 컨테이너에서 객체의 생명주기뿐만 아니라, 의존관계도 정리해 준다.
고로 어어어어어어엉어어어어엉어어어어어엄청 중요한 얘기다.
의존성 주입 방식은 크게 3가지다.
1. 필드 주입(Field Injection)
필드 주입은 클래스에 선언된 필드에 생성된 객체를 주입해주는 방식이다.
@Controller
public class PetController{
@Autowired
private PetService petService;
}
스프링에서 제공하는 @Autowired 어노테이션을 주입할 필드 위에 명시한다.
2. 수정자 주입(Setter Based Injection)
@Controller
public class PetController{
private PetService petService;
@Autowired
public void setPetService(PetService petService){
this.petService = petService;
}
}
클래스의 수정자를 통해서 의존성을 주입해주는 방식이다.
3. 생성자 주입(Constructor Based Injection)
@Controller
public class PetController{
// final 키워드 필수!!
private final PetService petService;
@Autowired
// spring framework 4.3부터 생성자가 하나일 경우 생략 가능
public PetController(PetService petService){
this.petService = petService;
}
}
클래스의 생성자를 통해서 의존성을 주입해주는 방식이다.
생성자 주입은 인스턴스가 생성될 때, 1회 호출되는 것이 보장된다.
물론! 우리의 아주 좋은 친구 Lombok을 이용하면 코드가 아주 간단해진다.
@RequiredArgsConstructor을 이용하면 생성자, @Autowired 생략 가능!!
@Controller
@RequiredArgsConstructor
public class PetController{
private final PetService petService;
}
근데....
스프링에서는 3. 생성자 주입(Constructor Based Injection)을 권장하고 있다.
크게 두 가지 이유가 있는데,
불변(immutable) 객체를 보장
객체가 생성되는 시점에만 생성자를 1회만 호출하기 때문이다.
순환 참조 문제 방지 가능
순환 참조: A,B 두 객체가 각각 서로를 필드에 포함하여 참조하고 있는 상태
필드주입, 수정자주입
실제 메소드가 호출되었을 때, runtime 에러와 함께 수정자 주입 문제가 불거지게 된다.
그러면 난 정상인 줄 알고 컴파일 하고... 서비스 하다가.... 갑자기 내 코드가 펑!
생성자 주입
스프링 어플리케이션이 구동되는 순간에 에러가 발생한다.
그리고 단위 테스트를 진행할때 순수 자바 코드로 테스트가 가능하다.
관점 지향 프로그래밍: 관점을 기준으로 묶어 개발하는 방식
-> 핵심 기능 과 부가 기능으로 구분
예를 한번 들어보겠다. 회원가입 기능이 있다고 가정해보자.
얘네들이 핵심 기능 이다.
그럼 이 기능들에 대한 수 많은 부가적인 기능들을 넣게 되면, 그 로직마다 중복되는 코드들을 넣게 된다.
그럼 매우 지저분하고 쓸데없이 반복되게 된다.
흠.... 이게 무슨 소리냐....🤔
Advice에 대해 알면 된다.
Advice
관점의 구체적인 동작을 정의하는 부분으로 언제 어떤 동작을 수행할지를 결정
어노테이션 | 동작 시기 |
---|---|
@Before | 메소드 실행 전에 동작 |
@After | 메서드 실행 후에 동작 |
@AfterReturning | 메서드가 성공적으로 반환된 후에 동작 |
@AfterThrowing | 메서드에서 예외가 발생한 후에 동작 |
@Around | 메서드 실행 전후에 동작을 수행, 메서드 실행을 직접 제어 |
// 출처: https://velog.io/@dkwktm45/Spring-AOP%EB%A5%BC-%EC%95%8C%EA%B3%A0-%EC%82%AC%EC%9A%A9-%EB%B0%A9%EB%B2%95%EC%9D%84-%EC%95%8C%EC%9E%90
// @Before 사용 예시
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.UserService.getUser(..))")
public void logBeforeUserGet() {
System.out.println("Getting user...");
}
}
더욱 더 상세하게는 요기로!
직역하면... 순수한 구형 자바 객체...? 🤔
POJO(Plain Old Java Object)
Java EE 등의 중량 프레임워크들을 사용하게 되면서 해당 프레임워크에 종속된 무거운 객체를 만들게 된 것에 반발해서 사용되게 된 용어
출처: https://dev-coco.tistory.com/82 [슬기로운 개발생활:티스토리]
보통 자바의 extends 혹은 implements를 Java에서 주로 사용하게 된다.
근데, 저기서 기능을 하나 바꿀려면 코드 전체를 바꿔야 하지 않는가?
그래서! 새로운 개념인 POJO가 나왔다.
// 출처: 내 깃허브
public class User {
private String name;
private int age;
public String getName() { return name; }
public String getAge() { return age; }
public void setName(String name) { this.name = name; }
public void setAge(int age) { this.age = age; }
}
Spring으로 개발을 해봤다면 무조건 아는 Getter, Setter 이다.
(물론 Lombok을 통해 @Getter, @Setter을 사용함 난..)
결론: Getter와 Setter로 구성된 가장 순수한 형태의 기본 클래스를 POJO!
그리고 이 POJO를 이용한 프레임워크 Hibernate가 등장하게 된다.
이건 다음 기회에 따로 포스팅하겠다.
객체 지향적이고 모듈화된 코드 작성, IoC와 AOP를 통한 유연성 및 편리한 데이터 액세스와 트랜잭션 관리 등의 기능으로 웹 애플리케이션 개발이 더 효율적이고 유지보수가 용이
하다는 큰 장점이 있다.