모델1 방식 예) 그누보드
문제점
- 프레젠테이션 로직과 비지니스 로직의 혼재로 JSP 복잡성 증가
- 비즈니스 로직과 화면 로직은 분리되어야 함.
- JSP의 목적은 VIEW에 있는데 너무 많은 일을 함
- 유지보수의 어려움
Spring IoC 및 DI
전통적으로 각 객체는 협업할 객체의 참조를 취득해야 하는 책임이 있음. 이것이 의존성.
(예. BoardServiceImpl은 BoardDao가 없으면 혼자 일을 못 함.)
이는 결합도가 높으며 테스트하기 어려운 코드를 만들어 냄.
빌더
만든 소스파일들을 컴파일 할 때, 의존한 외부 jar 파일들도 포함해야 하는데 이 것을 자동화하는 도구.
어플리케이션을 빌드하는 자동화 도구.
종류 : 아파치 앤트(최근엔 사용 少), gradle, 메이븐
스프링의 기본 빌더는 Maven, 안드로이드의 기본 빌더는 Gradle
레거시에 있는 pom.xml 열었을 때 pom.xml탭에서 뭔가를 추가하고 저장했을 때 레거시에 빨간 느낌표가 뜨면 (빌더에 문제가 생기면)
> 해당 태그 버전을 1 낮춰보거나
여길 수정해야 함.
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();
}
}
ioc3.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"
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 |