Java

[TIL] JAVA : @Bean, IoC 컨테이너, 의존성 주입

손가든 2024. 1. 3. 10:15

어제 하루종일 CRUD 노가다를 마무리하고 JWT를 저녁에 입문했는데, 애들 장난이라고 생각하고 공부하면 절대 스프링의 제작 의도대로 Spring security 디펜던시를 사용할 수 없을 것 같다고 생각됬다.

 

오늘부터는 정말 약한 의지가 아니라 뇌빼고 모르는거 다 찾아본다는 마인드로 security 정복에 나선다.

 

 

오늘 할일

1. @Bean 어노테이션의 의미는 무엇인가 ?

 

2. Filter Chain Froxy의 동작 방법 + HttpFilterChain의 내부 구조에 대해 이해하고 보안에 관한 원하는 코드 짜는 방법 공부하기

 

3. spring jpa 는 어떻게 DB 서버와 통신하는가?

 

 


 

@Bean 어노테이션의 의미

 

spring security가 바뀌면서 지원해주던 config를 직접 개발자가 커스텀하여 사용하도록 바꼈다.

 

그래서 spring security에 대한 난이도가 올라가고 그것을 자유롭게 다루는 것이 매우 하드한 챌린지가 된 것 같다.

 

그래서 이제 spring security filterChain에 대한 config 코드를 @Bean 어노테이션이라는 것의 명명하에 작성해야 하는데,

 

이 @Bean 어노테이션의 의미가 무엇인지도 모르고 코드를 들여다보니 아무것도 이해되지 않았던 것 같다.

 

 

근데 이 @Bean이라는 어노테이션을 공부해보고 나니 스프링에서 매우 중요한 용어라는 것을 알게 되었다. 한번 살펴보자.

 

 

스프링에는 스프링 컨테이너(ApplicationContext 클래스) 라는 스프링 프레임워크 내부 관리소가 존재한다.

 

이 관리소 내부에는 @bean 이나 XML 로 작성된 <bean> 요소 안에 추가하여 등록된 메소드의 결과값이 들어있다.

 

@Bean은 메소드 수준의 어노테이션으로, Spring Bean에 등록되는데, 이는 스프링 자체가 관리하는 오브젝트로, 스프링 프레임워크 컨테이너에 의해 인스턴스화되고, 구성되고 관리되는 하나의 객체이다.

 

이 빈들은 스프링 애플리케이션의 구성 요소로서, 유연하고 전역적으로 프로젝트에 적용된다.

 

등록된 @Bean 메소드들은 전역 환경 설정이나 특정한 기능을 제공하는 서비스(Spring Security도 포함), 라이브러리 등을 정의하며, 서로 다른 Bean들이 주입받아 사용될 수도 있다.

 

 

자 그럼 생각을 해보자.

 

@Bean 컨테이너 라는것을 이해해보니 스프링은 그냥 기계 안에 작은 시스템 프레임워크일 뿐인데,

 

뭔가 본인의 소유를 가진다는 용어가 나온다는 둥, 주체적으로 프레임워크가 가지고 있는 인스턴스가 존재하고 내가 모르는 것도 관리도 해주는 것 같다.

 

이걸 제어의 역전(IoC) 이라고 한다.

 

 

Inversion of Control 이라는 제어의 역전이라는 용어는 객체의 생성, 생명 주기의 관리까지,

 

모든 객체에 대한 제어권이 개발자 -> 프레임워크 로 역전되고, 결과적으로 개발자는 오브젝트의 의 생명주기에 신경쓰지 않고 소스코드의 작성에 집중할 수 있다.

 

이러한 프레임워크를 사용하여 설계하는 것을 제어의 역전이라고 한다.

 

스프링 컨테이너는 객체의 생명주기를 관리하기 때문에 이를 IoC 컨테이너 라고 부른다.

 

 

 

Dependency Injection (의존성 주입)

 

자바를 공부하면서 의존성 주입이라는 말을 많이 들어왔는데, 무슨 의미인지 정확하게 이해하지 못한채로 남겨뒀다.

 

오늘 그 의미에 대해 이해하고자 개념에 대해 작성해보겠다.(개인적이고 무지몽매한 지식이 첨가되었을 수 있음,,)

 

 

Java Class에서 Dependency(의존관계)란 무슨 의미일까

 

의존 관계란 'A가 B에 의존'하면 -> '의존대상 B가 변할때, A에 영향을 미친다.'

 

OOP 프로그래밍 언어인 Java에서는 의존성을 낮추는 것을 지향한다.

 

그 이유는 코드의 재가독성과 테스트, 유지보수 등 코드의 리팩토리 지속성과 관계가 있다.

 

만약 A코드가 잘못되어 버그를 수정해야 할 때, 의존성이 높은 코드는 A코드의 수정을 위해 프로젝트 전체를 수정해야 할 수도 있다.

 

따라서 이는 Java의 interface라는 연결관계를 통해 의존성이 추상화될 수 있는데,

 

선언된 interface의 메소드를 다른 클래스가 직접 구현부에 가져와 customize 하며 결합도를 낮추는 방식이다.

 

 

그럼 DI(의존성 주입)은 무엇일까.

 

Spring 프레임워크는 3가지 핵심 프로그래밍 모델을 지원하고 있는데, 그 중 하나가 바로 의존성 주입이다. 

 

DI란 외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로, 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 동적으로 주입하여 유연성을 확보하며 결합도를 낮출 수 있게 해준다.

 

인터페이스가 실제 자바 인터페이스 클래스를 얘기하는 것이 아니라 생성자, 필드 수정자 등 다양한 매개체들을 말한다.

 

따라서 생성자 주입, 필드 주입, 수정자 주입등 다양한 방법이 있고, 이러한 방법으로 두 객체 간의 의존성을 맺어주는 것을 의존성 주입이라고 한다.

 

스프링 4에서부터 생성자 주입을 강력히 권장하고 있고

 

따라서 Spring JPA에서 사용되는 '@Autowired' 어노테이션으로 MVC 클래스를 필드로 주입시키는 방법은 지양되고 있다.

 

/* 지양되는 필드 주입 */
@Service
public class Service{
	@Autowired
	Repository repository;
}



/* 권장하는 생성자 주입 */
@Service
public class Service{
	Repository repository;
    
    public Service(Repository repository){
    	this.repository = repository;
    }
}

 

별 차이가 없어보이는 이 생성자 주입을 권장하는 이유는 다음과 같다.

 

1. 순환 참조를 방지하여 어플리케이션이 뻗어 버리는 것을 방지

2. final 선언이 가능해짐 -> 불변성 확보