Spring Bean은
스프링 IOC컨테이너가 관리하는 객체이다
(여기서 IOC컨테이너는)
- 컨테이너는 보통 객체의 생명주기를 관리,생선된 인스턴스들에게 추가적인 기능을 제공하도록 하는것
- 객체관리 주체가 프레임워크가 되기 때문에 개발자는 로직에 집중할 수 있는 장점이 있다.
- IOC컨테이너는 객체의 생성을 책임지고, 의존성을 관리한다
그리고 Spring Bena에서 Bean에 대한 설명은
공식문서에서 빈은 Sprign IOC 컨테이너에 의해서 관리되는 객체라고 되어있다.
빈의 정의 하는데 Spring IOC컨테이너라는 단어가 사용된다
인을 인스턴스화 하고 구성 및 모으는 책임이 있고
이처럼 빈을 설명하는 데 ioc컨테이가 쓰이고 ioc컨테이너를 설명하는데 빈이 사용되는걸 확인할수 있다.
빈을 사용하는 이유
1 2 3 4 5 6 7 8 | private final Dao dao; public Service(Dao dao){ this.dao=dao; } Service service = new Service(new JdbcDao()); | cs |
위에 코드를 보면 Service를 초기화 하는 service의 생성자로 Dao구현체를 생성해서 넣어주고 있다
만약 Dao 의 구현체가 바뀐다면
서비스를 생성하는곳에서도 변경일 일어나게 된다
서비스를 생성할때dao를 초기화함과 동시에
어떤dao의 구현체를 선택할지 책임이 있기 떄문이다
또한 의존성을 주입할때 여러개의 의존성이 필요하다면 해당 의존성 주입 순서를 알아야한다.
만약 어플리케이션의 규모가 점점 커진다면 의존성을 주입해야할 객체가 늘어나지 않는다는 보장이 없다
그러므로 이 이 의존성을 하나하나 기억하고 관리 해야하는데
이것은 한계가있다
이그림에서 A를 생성하려면 BCD객체가 생성 되어야하고
B를 생성하기위해서는 E,F 가필요하다
C를 생성하기위해서는 E 가 필요하고
D를 생성하기 위해서는 G,F가 필요하다
코드로 의존성을 주입하면 아래와 같아진다
1 2 3 | A a = new A(new B(new C(new H(new M())), new F(new J(new M()), new L())), new C(new E(new H(new M())))), new D(new F(new J(new M()), new L())), new G(new I(new J(new M()), new L()), new K(new L())))); | cs |
직접 의존성을 주입하기 위해서는 의존관계를 모두 파악해야하는 번거로운이 생긴다
또한 많은 객체가 중복 생성이 되버린다
그래서 의존성 주입이 필요한 객체를 빈으로 등록해서
스프링 ioc컨테이너가 객체의 생성과 의존성 주입을 관리하게 한다.
이렇게 구현하면 주입된 의존성을 사용하는데만 집중할수있다
빈은 싱글턴이다 라는 말이 있는데
만약 스프링아닌 객체를 싱글톤으로 만들어서 사용하게 된다면 어떻게 될까?
문제점으로는 객체를 싱글턴으로 만들면
일반적으로 객체에 싱글톤 패턴을 적용하는것이다
싱글턴 패턴에는 단점이 있는데 첫번째로는 다형성을 사용할수가 없다
싱글턴 패턴을 사용하면 생성자의 접근 지정자를 private로 설정해야한다
하지만 이렇게 구현해버리면 해당 객체는 상속을 할수 없게 된다.
그러므로 객체지향의 이점인 다형성을 적용할수가 없어진다
두번재로 안정성이 중요한 어플리케이션에서 필수적인 단위 테스트를 할수가 없다 .
객체를 싱글톤 패턴으로 구현할 경우 해당 객체는 공유 객체가 되므로 단위 테스트를 실행할때 테스트의 순서에
따라서 결과가 달라지게 된다
그렇다면 스프링에서는 이런 단점을 어떻게 해결했을까?
먼저 spring ioc 컨테이너가 생성되면 빈 스코프가 싱글톤인 객체를 생성한다
이때 빈으로 등록하기 위해서 어노테이션 기반 혹은 Java설정 클래스 기반 혹은 XML기반의 다양한 Configuration
메타 데이트를 이용하여 통일된 Bean Definition 을 생성한다.
그리고 빈으로 등록할 POJO와 Bean difinition 정보를 이용하여 빈을 생성한다.
이 과정에서 싱글턴 패턴을 사용하는게 아닌 평범한 자바 클래스를 이용하여 객체를 생성한다.
ioc컨테이너는 싱글턴 레지스트리라는 기능이있는데
레지스트리는 Spring뿐만 아니라 CS 에서 전반적으로 쓰이는 개념으로 Key와 Value 형태로 데이터를 저장하는 방법 이다.
Spring IOC 컨테이너는 빈 스코프가 싱글턴인 객체에 빈의 이름을 Key 객체를 Value로 저장한다
그래서 의존성이 주입되어야하는 객체가 빈으로 등록되어있을때 스프링은 bean의 이름을 이용하여
항상 동일한 Single Object를 반환하게 된다.
이렇게 빈 객체가 생성 되면 IOC컨테이너는 의존성 설정을한다
이때 의존성 자동 주입이 일어나게 되고 객체를 초기화 하는 과정을 진행한다
모든 객체가 다 필요한 것은 아니지만 커넥션 풀처럼 사용전에 초기화 과정이 필요한 객체들은 초기화 과정을 진행한다
초기화가 끝나면 드디어 빈을 사용할수 있게 되고 스프링 컨테이너가 종료 될때
빈 스코프가 싱글톤인 객체들도 함께 소멸된다.
이렇게 편리한 기능이지만 객체를 빈으로 설정하기 위해서 주의해야 될 점이 있는데
예를 들어 싱글톤 스코프의 빈이 value라는 상태를 가질때
thread1은 벨류값을 증가 시킨다고 가정하고
thread2는 value라는 값을 가져와 사용한다고하면 매번 다른 값을 사용할수 있다 .
해당빈의 상태를 항상 예측할 수 없기 때문에 의도한 결과가 나올수 없다.
그러므로 빈 스코프를 싱글톤으로 설정할 경우 상태를 가지면 안된다.
하지만 상태를 가질 수 있는 빈도 있는데
빈은 생성되고 존재하고 적용되는 범위를 조절할수있다.
이를 빈 스코프라고하고 @Scope 어노테이션을 사용하여 설정할 수 있다.
지금까지 사용했던 것은 디폴트로 설정되어 있던 싱글톤 타입인데
이외에도 프로토 타입이라는 스코프가 있다
빈 스코프를 프로토타입으로 설정한다면
IOC컨테이너와 함께 생성되고 소멸되는것이 아닌 요청이 올때마다 객체가 생성이된다.
모든 스레드에서 공유하는것이 아니므로 해당 객체를 상태를 가질수 있다.
또 주의 해야할점이 있는데
의존성을 자동 주입 해야 할 인터페이스에 구현체가 두 개 이상이라면
스프링에서 어떤 구현체를 자동 주입할지 결정하지 못해 충돌이 일어나게된다.
그렇다면 충돌로 인해서 다형성을 이용하지 못할까?
스프링에서 이런문제의 해결방안으로 어노테이션을 사용할수 있다.
어노테이션을 사용하여 의존성 주입시 우선순위를 조정할수 있는데
첫 번째로 의존성을 자동 주입해야하는 구현체가 하나일 경우 해당 구현체에 @Primary 어노테이션을 붙이면
스프링이 우선순위를 파악하고
의존성 주입시 해당 객체를 사용하게 된다
두 번째로 상황에 따라 다른 구현체를 자동 주입 되도록 할 수 있다
의존성 주입이 필요한곳에 @Qualifler 어노테이션을 사용하여 특정 구현체를 주입하도록 설정할 수 있다.
@Qualifier 어노테이션 안에 이름을 넣어 상황에 따라 다른 의존성 주입이 가능하다.
빈의 이름을 따로 설정하지 않는다면 클래스 이름을 카멜케이스로 설정된다
정리
스프링 빈을 사용하는 이유는 스프링IOC컨테이너가 특정 객체의 라이프
사이클을 관리한다는 것을 나타내기 위해서 필요하다
그렇다면 스프링IOC 컨테이너는 왜 빈을 관리 하는 것일까?
의존성을 자동 주입해 개발자들이 해당 의존성을 사용하는 로직에만 집중할수 있게 도와준다
또한 의존성을 주입할 때 사용되는 객체가 항상 동일함을 보장하기 위해서 사용된다.
댓글