728x90
728x90

8. Setter Injection vs Constructor Injection

 

생성자 주입은 컴포넌트를 사용하기 전에 의존 해야하는 클래스의 인스턴스를 가지고 있어야 할 때 유용하며 세터주입은 부모 컴포넌트의 새 인스턴스를 생성하지 않고 동적으로 각기 다른 구현을 사용해 의존성을 대체할 수 있다. 즉 의존성을 인터페이스로 선언할 수 있다는 점이 장점이며 덜 강압적인 주입이라 할 수 있다.

 

기본 생성자만 있는 클래스에 생성자 주입을 정의하면 비 IoC 환경에서 해당 클래스를 사용하는 모든 클래스에 영향을 주게 된다. 하지만 세터 주입의 경우 다른 클래스가 이 클래스와 상호작용 하는데 있어 영향을 덜 주게 된다. 

 

일반적으로 세터 주입을 이용하는 것이 좋다.

이 방식은 비 IoC 설정에서 코드를 사용하는데 최소한의 영향만을 주기 때문이다. 생성자 주입은 컴포넌트로 항상 의존성이 전달되게 할 때 적합하다.

 

9. DI(Dependency Injection)

1. Setter Injection(XML 기반)

Emp

package ioc.ioc5;

interface Emp {
	public void gotoOffice();
	public void getofWork();
}

Programmer

package ioc.ioc5;

public class Programmer implements Emp{
	public void gotoOffice() {
		System.out.println("프로그래머 출근합니다.");
	}
	
	public void getofWork() {
		System.out.println("프로그래머 퇴근합니다.");
	}
}

Designer

package ioc.ioc5;


public class Designer implements Emp{
	public void gotoOffice() {
		System.out.println("디자이너 출근합니다.");
	}
	public void getofWork() {
		System.out.println("디자이너 퇴근합니다.");
	}
}

Develope

package ioc.ioc5;

import org.springframework.stereotype.Service;
@Service
public class Develope {

	private Emp emp;

	public void setEmp(Emp emp) {
		this.emp = emp;
	}


	void coding() {
		emp.gotoOffice();
		System.out.println("업무합니다....");
		emp.getofWork();
	}
}

ioc.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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<bean class="ioc.ioc5.Programmer" id="programmer" />
	<bean class="ioc.ioc5.Designer" id="designer" />
	<bean class="ioc.ioc5.Develope" id="develope" p:emp-ref="programmer" />

</beans>

TestMain

package ioc.ioc5;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestMain {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("ioc5.xml");
		Develope dev = (Develop)context.getBean("develope");
		dev.coding();
	}
}

 

 

2. Constructor Injection(XML 기반)

Emp

package ioc.ioc6;

public interface Emp {
	public void gotoOffice();
	public void getofWork();
}

Programmer

package ioc.ioc6;

public class Programmer implements Emp{
	public void gotoOffice() {
		System.out.println("프로그래머 출근합니다.");
	}
	
	public void getofWork() {
		System.out.println("프로그래머 퇴근합니다.");
	}
}

Designer

package ioc.ioc6;

public class Designer implements Emp{
	public void gotoOffice() {
		System.out.println("디자이너 출근합니다.");
	}
	public void getofWork() {
		System.out.println("디자이너 퇴근합니다.");
	}
}

Develope

package ioc.ioc6;


public class Develope {

	private Emp emp;
	private Emp emp2;
	
	public Develope(Emp emp, Emp emp2) {
		this.emp = emp;
		this.emp2 = emp2;
	}


	void coding() {
		emp.gotoOffice();
		System.out.println("업무합니다....");
		emp.getofWork();
		emp2.gotoOffice();
		System.out.println("emp2 업무합니다....");
		emp2.getofWork();
	}
}

 

 

3. Method Injection

Method 정의 전체에 Bean을 주입하는 것

 Method Replace(메소드 대체)

기존 메소드를 런타임 중에 새로운 구현으로 대체

 

Magictian

package magic;

import lombok.Data;

@Data
public class Magician {
	private MagicBox magicBox;
	
	public void magic() {
		System.out.println("마술시작");
		System.out.println(magicBox.getContent());
		System.out.println("짜잔");
	}
}

MagicBox

package magic;

public interface MagicBox {
	String getContent();
}

MagicBoxImpl

package magic;

public class MagicBoxImpl implements MagicBox{

	@Override
	public String getContent() {
		return "비둘기"; 
	}
}

Tiger

package magic;

import java.lang.reflect.Method;

import org.springframework.beans.factory.support.MethodReplacer;

public class Tiger implements MethodReplacer{

	@Override
	public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
		// invoke
		// obj : 메서드 수행 객체
		// method 메서드 자신
		// args 파라미터
		// return 반환값
		
		return "호랑이";
	}
	
}

maginc.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">

	<!-- magicBox -->
	<bean class="magic.MagicBoxImpl" id="magicBox" >
		<replaced-method name="getContent" replacer="tiger" />
	</bean>
	
	<!-- magician -->
	<bean class="magic.Magician" id="magician">
		<property name="magicBox" ref="magicBox"></property>		
	</bean>
	
	<!-- method replacer -->
	<bean class="magic.Tiger" id="tiger" />
</beans>

 

 Getter Injection(게터 주입)

기존 메소드를 런 타임중에 spring Context로 부터 특정한 빈을 반환하는 새로운 구현으로 대체. Method 주입의 특별한 경우로 Method가 특정 타입의 빈을 반환하도록 선언해 두고(보통 abstract) 런타임 중 실제 반환되는 빈은 Spring Context에서 오도록 하는 방법

 

Emp

 

package emp;

public abstract class Emp {
	public Emp getEmp() {
		return this;
	}
	public void work() {
		getEmp().work(); // 주입된 getEmp() 메소드를 사용
	};
    // getEmp를 주입, Emp가 주입된다.
    // Run-Time 중에 xml 파일로부터 빈을 주입받는다.
}

Programmer

package emp;

public class Programmer extends Emp{

	@Override
	public Emp getEmp() {
		return this;
	}

	@Override
	public void work() {
		System.out.println("프로그래머의 개발");
	}
	
}

Designer

package emp;

public class Designer extends Emp{

	@Override
	public Emp getEmp() {
		return this;
	}

	@Override
	public void work() {
		System.out.println("디자이너의 디자인");
	}
	
}

emp.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="emp.Programmer" id="programmer"></bean>
	<bean class="emp.Designer" id="designer"></bean>
	
	<!-- 아래 lookup-method는 메소드를 런타임 중에 새로운 구현으로 대체 getter 주입은 setter Injection의 역으로 생각
		getEmp()를 호출할 때마다 다른 myemp가 반환, 그러나 setter Injection은 단 한번만 주입, 주입되는 메소드 명이
		반드시 getXXX 로 시작할 필요는 없다.
	  -->
	<bean class="emp.Emp" id="emp">
		<lookup-method name="getEmp" bean="programmer"/>
	</bean>
</beans>

EmpMain

package emp;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class EmpMain {
	public static void main(String[] args) {
//		Emp emp = new Programmer();
//		emp.work();
		
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("emp.xml");
		Emp emp = (Emp)ctx.getBean("emp");
		Emp emp1 = (Emp)ctx.getBean("programmer");
		emp.work(); // 추상클래스를 통한 객체 생성
		emp1.work(); // 구상 클래스를 통한 객체 생성
		ctx.close();
	}
}
728x90
300x250