본문 바로가기

스프링 Spring

Spring IoC 및 DI 21. 03. 26.

모델1 방식 예) 그누보드

문제점

- 프레젠테이션 로직과 비지니스 로직의 혼재로 JSP 복잡성 증가
- 비즈니스 로직과 화면 로직은 분리되어야 함.
- JSP의 목적은 VIEW에 있는데 너무 많은 일을 함
- 유지보수의 어려움

 

Spring IoC 및 DI

전통적으로 각 객체는 협업할 객체의 참조를 취득해야 하는 책임이 있음. 이것이 의존성.
(예. BoardServiceImpl은 BoardDao가 없으면 혼자 일을 못 함.)

이는 결합도가 높으며 테스트하기 어려운 코드를 만들어 냄.

 

빌더

만든 소스파일들을 컴파일 할 때, 의존한 외부 jar 파일들도 포함해야 하는데 이 것을 자동화하는 도구.
어플리케이션을 빌드하는 자동화 도구. 
종류 : 아파치 앤트(최근엔 사용 少), gradle, 메이븐
스프링의 기본 빌더는 Maven, 안드로이드의 기본 빌더는 Gradle

 

 

레거시에 있는 pom.xml 열었을 때 pom.xml탭에서 뭔가를 추가하고 저장했을 때 레거시에 빨간 느낌표가 뜨면 (빌더에 문제가 생기면)

> 해당 태그 버전을 1 낮춰보거나

 

여길 수정해야 함.

 


 

src/main/java 안에 패키지 만드는 것 / 패키지명 : 도메인 거꾸로 쓰고 .ioc 붙이기

 

 

Money.java

package site.levinni.ioc;

public class Money {
	private int amount;

	public Money() {}

	public Money(int amount) {
		this.amount = amount;
	}

	public int getAmount() {
		return amount;
	}

	public void setAmount(int amount) {
		this.amount = amount;
	}
}

 

 

Car.java

package site.levinni.ioc;

public class Car {
	private String name;

	public Car() {}

	public Car(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

 

 

HyundaiMaker.java

package site.levinni.ioc;

public class HyundaiMaker {
	public Car sell(Money money) {
		Car car = new Car("소나타");
		System.out.println(money.getAmount() + "받고 차를 팔았음 :: " + car.getName());
		return car;
	}
}

 

 

OrderManager.java

package site.levinni.ioc;

public class OrderManager { // 서비스 역할
	private HyundaiMaker maker = new HyundaiMaker();
	
	public void order(){
		maker.sell(new Money(1000));
	}
	// 결합도가 높다. OrderManager와 HyundaiMaker
}

 

 

OrderManagerApp.java

package site.levinni.ioc;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class OrderManagerApp {
	public static void main(String[] args) {
//		OrderManager manager = new OrderManager();
//		manager.order();
//		manager.order();
		// DL : Dependency Lookup 방식으로 객체 생성
		ApplicationContext ctx = new ClassPathXmlApplicationContext("ioc1.xml");
		OrderManager manager = ctx.getBean("orderManager", OrderManager.class);
		OrderManager manager2 = ctx.getBean("orderManager", OrderManager.class);
		OrderManager manager3 = ctx.getBean("orderManager", OrderManager.class);
//		manager.order();
		
		System.out.println(manager);
		System.out.println(manager2);
		System.out.println(manager3); // 같은 곳을 참조 > 싱글턴
		// ioc1.xml에서 scope를 prototype으로 하면 주소값이 다름.
	}
}
context에서 Lookup으로 찾는 것.
"orderManager"라는 이름을 가진 것을 OrderManager.class 타입으로 가져 와라.
싱글턴 : 한 객체를 가지고 돌려 쓰는 것.

 

 

ioc1.xml (src/main/resources) - Spring Bean Configuration File

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean class="site.levinni.ioc.OrderManager" id="orderManager" scope="prototype"/>
</beans>

- 클래스명 쓰고 자동완성 이용

 


결합도를 낮추는 일반적인 기법

구현을 인퍼테이스 뒤로 숨기기
-> 클라이언트 클래스에 영향을 주지 않고도 실제 구현 클래스가 교체될 수 있도록 하는 것.

 

인터페이스 CarMaker.java

package site.levinni.ioc2;

public interface CarMaker {
	Car sell(Money money);
}

- 메서드의 시그니처만 존재

 

 

HyundaiMaker.java

package site.levinni.ioc2;

public class HyundaiMaker implements CarMaker{
	public Car sell(Money money) {
		Car car = new Car("소나타");
		System.out.println(money.getAmount() + "받고 차를 팔았음 :: " + car.getName());
		return car;
	}
}

 

- HyundaiMaker가 CarMaker 인터페이스를 구현

 

 

OrderManager.java

package site.levinni.ioc2;

public class OrderManager {
	private CarMaker maker;

	public void setMaker(CarMaker maker) {
		this.maker = maker;
	}

	public void order(){
		maker.sell(new Money(1000));
	}
}

- OrderManager가 인터페이스를 사용하도록 수정

현재 maker는 null이기 때문에 값 주입이 필요.
주입 방법: 객체를 생성하는 시점에 필드의 값을 주는 생성자를 이용하거나 빈 객체를 생성한 후 세터를 이용. (메소드를 이용하는 것은 잘 안 씀.)
현재 setter 이용.

 

 

OrderManagerApp.java

package site.levinni.ioc2;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class OrderManagerApp {
	public static void main(String[] args) {
    
		// DL : Dependency Lookup 방식으로 객체 생성
		ApplicationContext ctx = new ClassPathXmlApplicationContext("ioc2.xml");
		OrderManager manager = ctx.getBean("orderManager", OrderManager.class);
		OrderManager manager2 = ctx.getBean("orderManager", OrderManager.class);
		OrderManager manager3 = ctx.getBean("orderManager", OrderManager.class);
		manager.order();
	}
}

 

 

ioc2.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean class="site.levinni.ioc2.OrderManager" id="orderManager" scope="prototype">
	<property name="maker" ref="kiaMaker"/>
	</bean>
	<bean class="site.levinni.ioc2.KiaMaker" id="kiaMaker"/>
	<bean class="site.levinni.ioc2.HyundaiMaker" id="hyundaiMaker"/>
</beans>

 

property name , ref - 의존성 주입!!
전체가 다 기아가 됨.

 

 

대우자동차 대신 기아 씀.

어노테이션 기반으로 소스 변경

 

Money.java와 Car.java 

클래스 명 위에
@Component("money")와
@Component("car") 추가

 

 

KiaMaker.java

package site.levinni.ioc3;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("kia") // 빈네임
public class KiaMaker implements CarMaker{
	@Autowired
	private Car car;

	public void setCar(Car car) {
		this.car = car;
	}

	@Override
	public Car sell(Money money) {
		System.out.println(money.getAmount() + "받고 차를 팔았음 :: " + car.getName());
		return car;
	}
}

- HyundaiMaker.java에도 @Service와 @Autowired 해주기

 

 

OrderManager.java

package site.levinni.ioc3;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class OrderManager { // 서비스 역할
	@Autowired @Qualifier("kia")
	private CarMaker maker;

	public void setMaker(CarMaker maker) {
		this.maker = maker;
	}

	public void order(){
		maker.sell(new Money(1000));
	}
}
@Service에 빈네임을 안 쓰면 자동으로 클래스명이 소문자로 변환돼서 빈네임이 됨. @Component도 마찬가지.
@Qualifier는 maker에 객체를 자동 주입 할 건데 어떤 것을 쓸지 명시해 놓은 것.

 

 

OrderManagerApp.java

package site.levinni.ioc3;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;

@Service
public class OrderManagerApp {
	public static void main(String[] args) {
		// DL : Dependency Lookup 방식으로 객체 생성
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("ioc3.xml");
		OrderManager manager = ctx.getBean("orderManager", OrderManager.class);
		manager.order();
	}
}

OrderManagerApp.java

 

ioc3.xml

 

namespace  탭에서 context 체크

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

	<context:component-scan base-package="site.levinni.ioc3"/>
</beans>

 

 

'스프링 Spring' 카테고리의 다른 글

21. 04. 01.  (0) 2021.04.01
Spring JDBC 21. 03. 31.  (0) 2021.03.31
AOP 끝 21. 03. 31.  (0) 2021.03.31
AOP 21. 03. 30.  (0) 2021.03.30
IoC 21. 03. 29.  (0) 2021.03.29