본문 바로가기
Programming/Spring

[Spring] Spring IoC (스프링)

by HoonSikE 2022. 4. 15.
반응형
SMALL
IoC (Inversion of Control, 제어의 역행)
 - IoC/DI
 - 객체지향 언어에서 Object 간의 연결 관계를 런타임에 결정
 - 객체 간의 관계가 느슨하게 연결됨 (결합도가 낮아짐, loose coupling)
 - IoC의 구현 방법 중 하나가 DI (Dependency Injection)


IoC 유형

Dependency Lookup 
 - JNDI (Java Name Directory Interface)
 - 컨테이너가 lookup context를 통해서 필요한 Resource나 Object를 얻는 방식 
 - JNDI 이외의 방법을 사용한다면 JNDI관련 코드를 오브젝트 내에서 일일이 변경해 주어야 함. 
 - Lookup 한 Object를 필요한 타입으로 Casting 해 주어야 함. 
 - Naming Exception을 처리하기 위한 로직이 필요.​​

Dependency Injection
 - ​Object에 lookup 코드를 사용하지 않고 컨테이너가 직접 의존 구조를 Object에 설정할 수 있도록 지정해주는 방식
 - Object가 컨테이너의 존재 여부를 알 필요가 없음
 - Lookup 관련된 코드들이 Object 내에서 사라짐
 - Setter Injection과 Constructor Inject

IoC 개념
객체 제어 방식
  - 기존 : 필요한 위치에서 개발자가 필요한 객체 생성 로직 구현
  - IoC : 객체 생성을 Container에게 위임하여 처리

IoC 사용에 따른 장점
  - 객체 간의 결합도를 떨어뜨릴 수 있음 (loose coupling)

객체 간 결합도가 높으면?
  - 해당 클래스가 유지보수될 때 그 클래스와 결합된 다른 클래스도 같이 유지보수되어야 할 가능성이 높다.

객체간 강한 결합
  - 클래스 호출 방식
  - 클래스 내에 선언과 구현이 모두 되어있기 때문에 다양한 형태로 변화가 불가능

  - sample1
    * HelloSpring 구현체를 MessageBean에서 직접 생성하여 사용한다.
    * HelloSpring이 교체되거나 내부 코드가 변경되면 MessageBean까지 수정해야 할 가능성이 있다.

MessageBean.java

package sample1;

public class MessageBean {
	public void sayHello(String name) {
		//System.out.println("헬로우" + name);
		System.out.println("Hello" + name);
	}
}​

HelloSpring.java

package sample1;

//결합도가 높은 프로그램
public class HelloSpring {
	public static void main(String[] args) {
		MessageBean bean=new MessageBean();
		//bean.sayHello(" 스프링!!");
		bean.sayHello(" Spring!!");
	}
}

 결과



● 객체 간의 강한 결합을 다형성을 통해 결합도를 낮춘다.

   - 인터페이스 호출 방식
   - 구현 클래스 교체가 용이하여 다양한 형태로 변화 가능하다.
   - 하지만 인터페이스 교체 시 호출 클래스도 수정해야 한다.
  - sample2
   * MessageBeanEn와 MessageBeanKr는 MessageBean를 상속
   * HelloSpring에서 각 서비스를 이용 시 MessageBeanEn와 MessageBeanKr는 MessageBean 타입으로 사용 가능

MessageBean.java

package sample2;

public interface MessageBean {
	public void sayHello(String name);
}​

MessageBeanKr.java

package sample2;

public class MessageBeanKr implements MessageBean{
	@Override
	public void sayHello(String name) {
		System.out.println("헬로우," + name);		
	}
}

MessageBeanEn.java

package sample2;

public class MessageBeanEn implements MessageBean{
	@Override
	public void sayHello(String name) {
		System.out.println("Hello," + name);
	}
}

 HelloSpring.java

package sample2;

//의존 관계를 약하게 설정하는 프로그램(결합도를 낮춤)
public class HelloSpring {
	public static void main(String[] args) {
		MessageBean bean=new MessageBeanEn();
		//bean.sayHello(" 스프링!!");
		bean.sayHello(" Spring!!");
	}
}

 결과



● 객체 간의 강한 결합을 Factory를 통해 결합도를 낮춘다.

   - 팩토리 호출 방식
   - 팩토리 방식은 팩토리가 구현 클래스를 생성하므로 클래스는 팩토리를 호출한다.
   - 인터페이스 변경 시 팩토리만 수정하면 된다. 호출 클래스에는 영향을 미치지 않는다.
   - 하지만 클래스에 팩토리를 호출하는 소스가 들어가야 한다. 그것 자체가 팩토리에 의존함을 의미한다.

  - sample2.factory
   * 각 Bean을 생성하여 반환하는 Factory 사용
   * Bean을 이용하는 쪽에서는 Interface만 알고 있으면 어떤 구현체가 어떻게 생성되는지에 대해서는 알 필요가 없다.
   * 이 Factory 패턴이 적용된 것이 Container의 기능이며 이 Container의 기능을 제공해 주고자 하는 것이 IoC모듈

MessageBean.java

package sample2.factory;

public interface MessageBean {
	String sayHello(String name);
}​

MessageBeanKr.java

package sample2.factory;

public class MessageBeanKr implements MessageBean{
	@Override
	public String sayHello(String name) {
		return "헬로우," + name;		
	}
}

MessageBeanEn.java

package sample2.factory;

public class MessageBeanEn implements MessageBean{
	@Override
	public String sayHello(String name) {
		return "Hello," + name;
	}
}

MessageBeanFactory.java

package sample2.factory;

public class MessageBeanFactory {
	public static MessageBean getMessageBean(String lang) {
		if("kor".equals(lang)) {
			return new MessageBeanKr();
		} else if("eng".equals(lang)) {
			return new MessageBeanEn();
		} else {
			return null;
		}
	}
}

 HelloSpring.java

package sample2.factory;

// 객체 간의 강한 결합을 Factory를 통해 결합도를 낮춘다.
public class HelloSpring {
	public static void main(String[] args) {
		//MessageBean bean= MessageBeanFactory.getMessageBean("kor");
		MessageBean bean= MessageBeanFactory.getMessageBean("eng");
		//System.out.println(bean.sayHello(" 스프링!!"));
		System.out.println(bean.sayHello(" Spring!!"));
	}
}

 결과



● 객체 간의 강한 결합을 Assembler를 통해 결합도를 낮춘다.

   - IoC 호출 방식
   - 팩토리 패턴의 장점을 더하여 어떠한 것에도 의존하지 않는 형태가 됨.
   - 실행 시점(Runtime)에 클래스 간의 관계가 형성이 됨.

  - sample3
   * 각 Bean의 LifeCycle을 관리하는 Assembler를 사용한다.
   * Spring Container가 외부 조립기(Assembler) 역할을 한다.

▶ MessageBean.java
package sample3;

public interface MessageBean {
	public void sayHello(String name);
}

▶ MessageBeanKr.java
package sample3;

public class MessageBeanKr implements MessageBean{
	@Override
	public void sayHello(String name) {
		System.out.println("헬로우," + name);		
	}
}

▶ MessageBeanEn.java
package sample3;

public class MessageBeanEn implements MessageBean{
	@Override
	public void sayHello(String name) {
		System.out.println("Hello," + name);
	}
}

▶ bean.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 id="msgBean1" class="sample3.MessageBeanEn"/>
<bean id="msgBean2" class="sample3.MessageBeanKr"/>

</beans>
   * bean은 기본적으로 scope="singleton"가 적용되어 있다. 싱글톤 패턴을 사용하지 않으려면 scope="prototype"를 입력해준다.

▶ HelloSpring.java
package sample3;

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

//스프링을 이용해서 접근
public class HelloSpring {
	public static void main(String[] args) {
		ApplicationContext factory=new ClassPathXmlApplicationContext("sample3/bean.xml");
		
		MessageBean bean=(MessageBean)factory.getBean("msgBean2");
		bean.sayHello(" 스프링");
		
		((ClassPathXmlApplicationContext)factory).close();
	}
}

 결과


Spring List
 

Spring List

Start Spring!! ● Spring Tip!! ●   기회는 준비된 자에게 찾아온다.

han-hoon.tistory.com


  

기회는 준비된 자에게 찾아온다.

 


 

반응형
LIST

댓글