Spring MVC - 의존성 주입

ehdrms2034·2020년 8월 19일
3

본 글은 스프링 MVC에 대해 지식을 정리하고 나중에 헷갈릴 때 다시 보기 위한 글입니다 👀

본 게시글은 Spring MVC Quick Start를 참조하여 정리한 글입니다. 📖 👀

본 게시글은 Spring MVC Documentation를 참조하여 정리한 글입니다  📚 👀

의존성 관리

사실 어떻게 보면 스프링 프레임워크에서 가장 중요한 특징 중 하나라고 보면 된다.
지금의 스프링의 위치를 있게 만든 장본인이라 보면 된다.

스프링 프레임워크에서 가장 중요한 특징은 객체의 생성과 의존관계를 스프링 컨테이너가 자동으로 관리한다는 점이다. 이 말이 Ioc(Inverse Of Converse)이다.

스프링은 IoC를 2가지 형태로 지원을 한다

  • Dependency LookUp
  • Dependency Injection

(사실 하도 DI,DI 하니까 DI는 말하지 않아도 이미 알고 있었다..)

Dependency LookUp

컨테이너가 어플리케이션 운용에 필요한 객체를 생성하고 클라이언트는 컨테이너가 생성한 객체를 검색하여 사용하는 방식을 말한다.

앞 전의


AbstractApplicationContext beanFactory = new GenericXmlApplicationContext("~~~.xml");

beanFactory.getBean("classA");

하던 방식을 Dependency Look up 방식이라 보면 된다.

Dependency Injection

객체사이의 의존관계를 스프링 설정 파일에 등록된 정보를 바탕으로 컨테이너가 자동으로 처리 하는 것을 말한다. 따라서 의존성 설정을 바꾸고 싶을떄, 프로그램 코드를 수정하지 않더라도 변경이 가능하다.

즉 코드간의 결합도를 낮춰, 유지보수하기 편한 코드가 된다 이말인것이다~

Spring DI 종류

Spring에서 지원하는 의존성 주입(Dependency Injection) 방법은 총 3가지가 있는 것으로 안다.

생성자 Injection 사용하기

스프링 컨테이너는 기본적으로 객체를 생성할때, 매개변수가 없는 기본 생성자를 생성한다.
컨테이너가 기본 생성자 말고 매개변수를 가지는 다른 생성자를 호출할 수 있도록 설정할 수 있도록 하는 것.
이것을 생성자 인젝션이라고 한다.

  • applicationContext.xml
<bean class="~~" id="carA">
  <constructor-arg ref="speakerA"/>
</bean>

<bean class="~~" id="speakerA"/>
<bean class="~~" id="speakerB"/>

예를 들어서 내가 carA의 speaker를 A에서 B로 교체하고싶다. 그럼 소스코드 수정없이, xml 파일만 수정하면 된다.

참 쉽쥬?!

생성자 Injection - 다중 변수 매핑

예를들어서, carA의 의존관계가 스피커와 차에 대한 가격이 있다고 치자.
그럼 생성자 Injection은 다음과 같이 정의할 수 있다.

<bean class="~~" id="carA">
  <constructor-arg index="0" ref="speakerA"/>
  <constructor-arg index="1" value="2000"/>
</bean>

물론 자바 클래스는 다음과 같은 생성자가 존재해야할것이다

class CarA {
	
    public CarA(Speaker speaker,int price){
    ~~~
    }
    
}

음, 개인적으로 생성자에 대해서 인젝션을 주입하는 것은, 확장성을 고려했을때 비용이 많이 들어서 내가 선호하는 방식은 아니다 😁 아 XML을 좋아하지 않는다 ㅎㅎ

Setter 인젝션 이용하기

Setter 인젝션은 이름에서 알 수 있듯이 Setter 메소드를 호출하여 의존성을 주입하는 방식이다.

<bean id="carA" class="~~">
  <property name="speaker" ref="speakerA"/>
  <property name="price" value="2000"/>
</bean>

이쪽이 더 확장성에 대응하기 편하다.

물론 각각의 property는 스프링 컨테이너 내에 등록되기 위해선 빈으로 존재해야할 것!

어노테이션 기반 설정

일단 스프링이 xml로만 관리된다면 난, 무적권적으로다가 스프링 안썼다..
어노테이션이라는 편리하고도 간편한 기능을 통해서 xml로만 이루어졌던 작업들을 편리하게 만들어주고있다.

Context NameSpace 추가

대신 스프링 MVC에서는 어노테이션을 사용하기 위해 네임스페이스의 추가를 요구하고 있다.

네임스페이스는 어디다 추가한다규?
<beans>에 추가한다 잊지말자.

Intellij 에서는 필요한 코드 작성하면 알아서 추가 시켜준다.

컴포넌트 스캔 설정

스프링 설정 파일에 어플리케이션에서 사용될 객체들을 <bean>에 등록하지 않고 자동으로 생성하기 위해서는 어떤 패키지의 컴포넌트를 미리 빈에 올려놓을 것인지 선언을 해주어야 한다.

<beans>
	<context:component-scan base-package="com.example.~~~"/>
</beans>

그럼 com.example.~~~이하의 @Component어노테이션을 사용하는 클래스들은 알아서 컨테이너에 등록이 된다.

@Component

@Component를 클래스 위에 설정하면 자동으로 Bean으로 등록해준다.

개발자는 코드로 이야기 해야되니, 간단하게

@Compoent
public class CarA{
}

가 있다면,,

<bean class="com.example.CarA"/>

로 바꿔준단 말씀

@Component("id")를 입력하면 bean에 id가 등록되니 확인 👌

id나 name 속성을 미지정 할 시 컨테이너가 자동으로 CamelCase에 맞춰 생성해준다.🐪

의존성 주입 어노테이션

스프링에서 의존성 주입을 지원하는 어노테이션으로는 크게 4가지가 있다.
@Autowired,@Qualifier,@Inject,@Resource다.

스프링에 종속적인 어노테이션은 Autowired와 Qualifier가 있고,
Inject와 Resource는 자바 자체에서 지원하는 어노테이션이라니 참고 바람.

그 말은, 스프링이 아닌 다른 프레임워크로의 이전가능성이 있다면 Inject 사용

간단하게 표로 정리하자면

| 어노테이션 | 기능 |
|---------|----|
|@Autowired|주로 변수위에 설정하여 해당 타입의 객체를 찾아서 자동으로 할당|
|@Qualifier|특정 객체의 이름을 사용하여 의존성 주입할 때 사용|
|@Inject | @Autowired 와 동일한 기능|
|@Resource| @Autowired와 @Qualifier를 합한 기능이라 보면된다.|

가 될 수 있다.

@Autowired

@Autowired는 생성자나 메소드, 멤버변수 위에 모두 사용가능하다.
스프링 컨테이너는 멤버 변수위에 붙은 @Autowired를 확인하는 순간 해당 변수의 타입을 체크하고 그 타입의 객체가 메모리 상에 존재하면 해당 변수에 객체를 대입한다.

만약 @Autowired가 붙은 객체가 없다면 NoSuchBeanDefinitionException 을 발생.

@Qualifier

해당 객체의 타입이 2개 이상 존재할 때 어떤 객체를 사용할 것인가 명시한 것

음 스프링에서는 Loose Coupling을 위해 전략패턴(Strategy)을 사용하여 주로 서비스를 구현하는 경우가 많다

그러다보면 Interface에 대해 Autowired를 시행했을때, 적절한 Bean을 컨테이너가 찾지 못하는 경우가 발생할 수 있다.

따라서 @Qualifier를 사용함으로써 직접 빈의 이름을 지정하여 컨테이너가 어떤 객체를 주입할 지 선택할 수 있게 해주는 역할을 한다.

Inject나 Resource는 넘어간다. (사용법 같다^_^)

profile
수동적인 과신과 행운이 아닌, 능동적인 노력과 치열함

0개의 댓글