STUDY/Java

[OOP] Chap 7. 스프링 삼각형과 설정 정보

seonyounggg 2021. 2. 26. 14:48

스프링을 입문을 위한 자바 객체 지향의 원리와 이해 를 읽고 정리한 글입니다.


스프링을 이해하는 데에는 스프링의 삼각형이라고 불리는 3대 프로그래밍 모델,

IoC/DI, AOP, PSA에 대한 이해가 필수다.

 

IoC/DI - 제어의 역전/의존성 주입

자바에서의 의존성을 단순히 정의하면 new 다.

전체가 부분에 의존한다고 표현할 수 있다.

 

사실상 변수에 값을 할당하는 모든 곳에 의존관계가 생긴다. 의존 대상이 내부에 있을 수도, 외부에 있을 수도 있다.

DI는 외부에 있는 의존 대상을 주입하는 것을 말한다.

의존 대상을 구현, 배치할 때 SOLID와 "응집도는 높이고 결합도는 낮추라"는 기본원칙에 충실해야 한다.

 

(참고)

의존하는 객체와 의존되는 객체 사이에 집합 관계와 구성 관계로 구분된다.

집합 관계 : 부분이 전체와 다른 생명주기를 가질 수 있다.

구성 관계 : 부분은 전체와 같은 생명주기를 갖는다.

public class Car{
    Tire tire;
    public Car(){
    	tire = new KoreaTire();
    }
}

위 코드에서 Car 객체는 Tire 객체에 의존성을 갖는다.

이 때, Car객체가 Tire를 직접 생산하여 생성자에서 객체를 주입함으로써 의존성을 자체적으로 해결하고 있다.

 

스프링 없이 의존성 주입1 - 생성자를 통한 의존성 주입

Tire tire = new KoreaTire();
Car car = new Car(tire);
public Car{
    Tire tire
    public Car(Tire tire){
    	this.tire = tire
    }
}

외부에서 생산된 tire 객체를 생성자의 인자로 주입하는 형태이다.

이제 Tire 인터페이스의 구현체가 변경되어도 Car 클래스는 변경할 일이 없어져 코드의 유연성이 높아졌다.

 

스프링 없이 의존성 주입2 - 속성을 통한 의존성 주입

Tire tire = new KoreaTire();
Car car = new Car();
car.setTire(tire);
public Car{
    Tire tire
    public setTire(Tire tire){
    	this.tire = tire
    }
}

위 코드에서는 속성을 통해 의존성을 직접 주입하고 있다.

원할 때 의존하고 있는 객체를 변경하는 것인데, 실제 프로그램에서 그럴 일은 적으므로 한번 주입된 의존성을 계속 사용하는 생성자 주입 방식이 주로 쓰인다.

 

스프링을 통한 의존성 주입1 - XML 파일 이용

스프링을 통한 의존성 주입은 위에 언급한 두 가지의 방식을 모두 지원하는데, 속성을 통한 의존성 주입을 살펴보겠다.

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml", Driver.class);
Tire tire = (Tire)Context.getBean("tire");
Car car = (Car)Context.getBean("car");
car.setTire(tire);

applicationContext.xml 파일(스프링 빈 설정파일)을 살펴보면 다음과 같다.

...

<bean id="tire" class="example.KoreaTire"></bean>
<bean id="car" class="example.Car"></bean>
</beans>

각 객체를 구분하기 위한 id속성와 어떤 클래스를 인스턴스화할 것인지 나타내는 class 속성을 사용한다.

이를 main()에서 getBean(id)의 형태로 객체를 얻어오고 있다.

스프링을 도입한 결과로, Tire의 구현체를 변경하게 되면 xml 파일만 수정할 뿐 기존 파일은 수정/재컴파일/배포 하지 않아도 실행결과를 바꿀 수 있다.

 

위 코드를, 스프링 설정 파일에서 속성을 주입하도록 변경해보겠다.

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml", Driver.class);
Tire tire = (Tire)Context.getBean("tire");
Car car = (Car)Context.getBean("car");
...

<bean id="koreTire" class="example.KoreaTire"></bean>
<bean id="car" class="example.Car">
	<property name="tire" ref="koreaTire"></property>
</bean>
</beans>

Setter함수에서 하던 작업을 property 태그로 대체하였다.

id가 koreaTire인 객체가 속성에 대입되는 것이다.

 

스프링을 통한 의존성 주입1 - @Autowired

public Car{
    @Autowired
    Tire tire
}
...
<context:annotation-config/>

<bean id="tire" class="example.KoreaTire"></bean>
<bean id="car" class="example.Car"></bean>
</beans>

@Autowired를 통해 car의 property를 자동으로 엮어줄 수 있으므로(자동 의존성 주입) property가 생략되었다.

우선적으로 타입을 기준으로 매칭되며, 같은 타입을 구현한 클래스가 여러개 있다면 Bean 태그의 id로 구분하여 매칭한다.

만약 id로도 구분할 수 없는 경우에는 에러가 발생한다.

 

스프링을 통한 의존성 주입1 - @Resource

@Autowired는 스프링의 어노테이션이고, (org.springframework.beans.factory.annotation.Autowired)

@Resource는 자바 표준 어노테이션이다. (javax.annotation.Resource)

@Autowired는 type과 id 중 type의 우선순위가 높은 반면에

@Resource는 id가 더 높다.

 

비교 - @Autowired, @Resource, <property>

프레임워크가 교체될 경우에 대비하면 자바 표준인 @Resource가 낫다.

개발 생산성은 @Resource가 낫지만 유지보수성 측면에서는 <property>가 좋다.

프로젝트의 규모와 팀의 특성에 따라 선택하여 사용하도록 한다.

 

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