- 객체의 생성과 관리 및 의존성 관리를 개발자가 아닌 스프링 프레임워크가 담당하는 디자인패턴
- 객체 간의 결합도를 줄이고 코드를 유연하게 작성할 수 있어, 가독성을 높이고 코드 중복을 줄이며 유지 보수를 편하게 할 수 있게 해준다.
- 기존에는 객체를 클래스 내부에서 생성하고 사용했다면, IoC를 적용하면 미리 생성해놓은 객체를 주입받아 사용하기만 하면 된다
- Resource 로딩 -> Bean 설정 -> Bean 인스턴스화 -> 의존성 주입 -> Bean 초기화 콜백 -> Bean 사용 -> Bean 소멸 콜백 -> Resource 해제
- Resource 로딩설정 파일에 어떤 객체를 생성할지, 객체 간의 의존성을 어떻게 설정할지에 대한 정보가 포함되어 있어, 이를 기반으로 Bean 객체를 정의하게 된다.
- IoC 컨테이너가 사용할 설정 파일을 메모리에 로드한다.
- Bean 설정
- XML, Annotation에서 정의된 Bean 객체를 구성하는 메타데이터를 읽어들여 IoC 컨테이너가 사용할 수 있는 형태로 변환한다.
- Bean 인스턴스화
- Bean 설정 단계에서 변환한 정보를 기반으로 Bean 객체를 만든다.
- 의존성 주입
- IoC 컨테이너가 Bean 객체가 의존하는 다른 Bean 객체를 검색하고, 주입한다.
- Bean 초기화 콜백
- 스프링 컨테이너가 Bean을 생성한 후, 사용하기 전에 수행해야 할 추가 작업을 정의한 메서드를 호출한다.
- Bean 사용
- IoC 컨테이너가 빈을 사용한다.
- Bean 소멸 콜백
- 빈이 더 이상 필요하지 않을 때, IoC 컨테이너는 빈의 소멸 메소드를 호출하고 해당 빈을 제거한다.
- Resource 해제
- Ioc 컨테이너가 종료되어 빈들도 함께 소멸된다.
- 의존성을 외부에서 결정하고 주입시켜준다. IoC를 구현한 방법 중 하나이다.
<의존성을 외부에서 주입 받지 않은 경우>
public class Car {
Tire tire;
public Car() {
tire = new KoreaTire();
// tire = new AmericaTire();
}
}
문제점 : Car 클래스와 Tire 클래스의 결합도가 강해서 코드의 확장성이 떨어진다.
모든 Car가 KoreaTire만 사용 가능, tire를 바꾸고 싶으면 Car 클래스의 생성자를 직접 수정해야 한다. 이를 해결하기 위해 의존성 주입을 사용한다.
- 의존성 주입 방법 3가지
public class Car { Tire tire; public Car(Tire tire) { this.tire = tire; } }
Tire tire = new KoreaTire(); **Car car = new Car(tire); // 생성자 주입**
- → 가장 권장되는 방법! 주입받는 객체를 final로 선언할 수 있어, 해당 객체가 변경되지 않도록 할 수 있다.
- 1. 생성자 주입
public class Car {
Tire tire;
public void setTire(Tire tire) {
this.tire = tire
}
}
Tire tire = new KoreaTire();
Car car = new Car();
car.setTire(tire); // setter 주입
→ setter 에서 tire 를 받아서 tire 필드를 설정
3. 필드 주입
import org.springframework.beans.factory.annotation.Autowired;
public class Car {
@Autowired
@Qualifier("koreaTire")
Tire tire;
}
import org.springframework.stereotype.Component;
@Component
@Qualifier("koreaTire")
public class KoreaTire implements Tire {
// ...
}
import org.springframework.stereotype.Component;
@Component
@Qualifier("americaTire")
public class AmericaTire implements Tire {
// ...
}
→ Tire 구현체가 여러 개라면 어떤 빈을 주입받아야 하는지 알 수 없는 문제가 발생할 수 있는데, 이때 Qualifier를 사용해 빈을 지정해줄 수 있다
여러 모듈에 공통적으로 나타나는 로직에 해당하는 ‘횡단 관심사’(공통 관심 사항)을 각 모듈 별 핵심 로직에 해당하는 ‘핵심 관심 사항’에서 분리해 별도의 모듈로 관리하도록 하고, 이 횡단 관심사를 어디에 적용할지 선택하는 기능을 합한 하나의 모듈
간단히 말하면, 핵심 로직 사이에 부가 로직을 끼워넣는 작업이다.
- 횡단 관심사를 Aspect라는 단위로 분리하고, 애플리케이션의 특정 지점(JoinPoint)에 적용하여 소스 코드의 중복을 줄인다
- 주요 용어
- Aspect : Advice + Pointcut으로, AoP에서 횡단관심사를 aspect로 모듈화한다.
- 언제 어디서 무엇을 할 지 명시되어 있다
- Advice : Target에 제공할 부가 작업을 담고 있는 모듈 (Aspect가 해야 하는 “작업”)
- Target : Advice가 적용될 객체
- Join Point : Advice를 적용할 수 있는 지점들 (method진입시점, 생성자 호출 시점 등 target 객체가 구현한 인터페이스의 모든 메서드)
- Pointcut : JoinPoint 중 Advice가 적용되는 지점을 결정
- 주요 용어
- step 1) @Asepct 어노테이션을 붙여 Aspect를 나타내는 클래스임을 명시 + @Component 어노테이션으로 빈으로 등록하기step 3) Advice 설정
- step 2) Pointcut 설정 (”execution(* 패키지명.interface명.메소드명)”)
ex) com.exmaple.demo 패키지 하위에 있는 메소드의 실행시간 체크하기
@Aspect
@Component
public class TimeTraceAop {
@PointCut("execution(* com.example.demo..*(..)") //com.exmaple.demo 패키지 하위에 있는 것에 다 적용해라
private void Time(){}
@Around("Time()")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable{ //ProceedingJoinPoint : Advice가 적용되는 대상을 가리킨다
long start=System.currentTimeMillis();
System.out.println("Start : "+joinPoint.toString());
Object result=joinPoint.proceed(); //메소드 실행
long finish=System.currentTimeMillis();
long timeMs=finish-start;
System.out.println("Finish :"+joinPoint.toString() + timeMs + "ms" );
}
}
}
- @Before : 대상 메서드가 실행되기 전에 Advice를 실행@Around : 대상 메서드 실행 전, 후 또는 예외 발생 시에 Advice를 실행@AfterThrowing : 대상 메서드에 예외가 발생했을 때 Advice를 실행
- @AfterReturning : 대상 메서드가 “정상적으로 실행”되고 난 뒤 Advice를 실행 (exception 발생했을 때는 수행하지 않음)
- @After : 대상 메소드 실행 후 Advice를 실행 (성공적으로 실행되었든, exception을 던졌든 상관없이 실행된다)
- 다양한 기술들을 인터페이스를 이용해 추상화하여 개발자가 일관된 방식으로 코드를 작성할 수 있도록 하는 추상화 구조
OracleJdbcConnector, MariaDBJdbcConnector, SQLiteJdbcConnector와 같은 구현체에 직접적으로 연결해서 얻는 것이 아니라 JdbcConnector 인터페이스를 통해 간접적으로 연결되어 Connection 객체를 얻기 때문에 일관된 방식으로 기능을 사용할 수 있다.
'백 > spring boot' 카테고리의 다른 글
JPA 관련 문제들 (주로 N+1문제) (0) | 2024.09.29 |
---|---|
스프링 빈 (0) | 2024.09.29 |
Spring Security2 - 로그아웃 (0) | 2024.08.16 |
spring security2 - refresh토큰 서버측 저장 (0) | 2024.08.16 |
spring security2 - refresh토큰으로 access 토큰 재발급 받기 (0) | 2024.08.15 |