자바 스프링 IoC, DI, AOP

휘Bin·2023년 6월 14일
0
post-thumbnail

제어 역전(IoC=Inversion of Control)

자바 개발을 할 때 일반적으로객체를 사용하기 위해 사용하려는 객체를 선언하고 해당 객체의 의존성을 생성해 객체에서 제공하는 기능을 사용한다.
즉, 객체를 생성하고 사용하는 과정을 개발자가 직접 제어하는 구조이다.

Ex)

@RestController
public class PracController{
	private Service service = new MyServiceImpl();
    
    @GetMapping("/")
    public String Hello(){
    	return service.getHello();
    }
}

하지만 제어역전(IoC)이라는 특징을 가진 스프링은 기존 자바 개발 방식과 다르게 작동한다.
IoC를 적용한 환경에서는, 사용할 객체를 직접 생성하지 않고 객체의 생명주기 관리를 외부에 위임한다.
위에서 말한 '외부'는 스프링 컨테이너(Spring Container) 또는 IoC컨테이너를 의미한다.
즉, 객체의 관리를 컨테이너에 맡겨 제어권이 넘어간 것을 제어 역전이라고 부르고, 제어 역전을 통해 의존성 주입(DI=Dependency Injection), 관점 지향 프로그래밍(AOP=Aspect-Oriented Programming) 등이 가능해진다.

이렇듯 객체의 제어권을 컨테이너로 넘기기 때문에 개발자는 비즈니스 로직을 작성하는데 더 집중할 수 있다.

의존성 주입(DI = Dependency Injection)

의존성 주입(DI)는 제어 역전의 방법 중 하나이다.
사용할 객체를 직접 생성하지 않고 외부 컨테이너가 생성한 객체를 주입받아 사용하는 방식을 의미한다.

스프링에서 의존성을 주입받는 방식을 3가지가 있다.

  • '생성자'를 통한 의존성 주입
  • '필드 객체 선언'을 통한 의존성 주입
  • 'setter 메서드'를 통한 의존성 주입

스프링에서는 @Autowired라는 어노테이션을 통해 의존성을 주입할 수 있다. 4.3 이후 버전에서는 생성자를 통한 의존성을 주입할 때는 위 어노테이션을 생략할 수도 있긴하다. 하지만 가독성을 위해 초반에는 어노테이션을 쓰는게 좋다.

Ex)

  • '생성자'를 통한 의존성 주입
@RestController
public class PracController{

	Service serivce;
    
    @Autowired
    public PracController(Service service){
    	this.Service = service;
    }
    
    @GetMapping("/")
    public String Hello(){
    	return service.getHello();
    }
    
}
  • '필드 객체 선언'을 통한 의존성 주입
@RestController
public class PracController{
	@Autowired
    private Service service;
}
  • 'setter 메서드'를 통한 의존성 주입
@RestController
public class PracController{
	
    Service service;
    
    @Autowired
    public void setService(Service serivce){
    	this.serivce = serivce;
        }
}

스프링 공식 문서에서는 '생성자를 통한 의존성 주입 방식'을 권장한다.
다른 방식과 다르게 생성자를 통한 의존성 주입 방식은 레퍼런스 객체 없이는 객체를 초기화할 수 없게 설계할 수 있기 때문이다.

관점 지향 프로그래밍(AOP = Aspect-Oriented Programming)

이는 스프링에서 아주 중요한 특징 중 하나이다.
'객체지향 프로그램밍(OOP= Object-Oriented Programming)'이라는 말은 들어봤을 것이다. AOP는 OOP를 더 잘 사용할 수 있도록 돕는다고 보면 좋다.

AOP는 '관점'을 기준으로 묶어 개발하는 방식을 의미한다.
여기서 '관점'이란, 어떤 기능을 구현할 때 그 기능을 '핵심 기능'과 '부가 기능'으로 구분해 각각을 하나의 관점으로 보는 것을 의미한다.

'핵심 기능'이란, 비즈니스 로직을 구현하는 과정에서 비즈니스 로직이 처리하려는 목적 기능을 말한다.
ex) 클라이언트로부터 게시글 등록 요청을 받아 데이터베이스에 저장하고, 게시글을 조회하는 비즈니스 로직을 구현한다면, '게시글 정보 데이터베이스에 저장', '저장된 게시글 데이터를 보여주는 코드'가 핵심 기능일 것이다.

'부가 기능'이란, 핵심 기능인 비즈니스 로직 사이에 로깅 처리를 하거나, 트랜잭션을 처리하는 코드라고 생각하면 쉽다.

OOP 방식의 로직에서는 위의 사진처럼 객체마다 핵심 기능을 수행하기 위한 로직과 함께 부가 기능의 코드를 작성하게 된다.
하지만 유지보수나 데이터베이스 접근을 위해 작성된 로깅과 트랜잭션 영역은 게시글 등록이나 조회할 때, 동일한 기능을 수행할 확률이 높다. 즉, 핵심 기능을 구현한 두 로직에 '동일한 코드'가 포함된다는 것을 알 수 있다.

AOP의 관점에서는 부가 기능은 핵심 기능과는 무관하게 로직이 수행되기 전 또는 후에 수행되기만 하면 된다. 따라서 위와 같은 그림으로 구성이 된다.

이처럼 여러 비즈니스 로직에서 반복되는 부가 기능을 하나의 공통 로직으로 처리하도록 모듈화해 삽입하는 방식을 AOP라고 한다.

AOP를 구현하는 방법은 크게 3가지가 있다.

  • 컴파일 과정에 삽입하는 방식
  • 바이트코드를 메모리에 로드하는 과정에서 삽입하는 방식
  • 프락시 패턴을 이용한 방식

이 중에 스프링은 디자인 패턴 중 하나인 '프락시 패턴'을 통해 AOP 기능을 제공하고 있다.

스프링 AOP의 목적은 OOP와 마찬가지로 모듈화해서 재사용 가능한 구성을 만드는 것이고, 모듈화된 객체를 편하게 적용할 수 있게 하여 개발자가 비즈니스 로직을 구현하는 데만 집중할 수 있게 도와준다.

profile
One-step, one-step, steadily growing developer

0개의 댓글