기록/BACKEND

[WEB] IoC

5월._. 2022. 4. 19.
728x90

IoC (Inversion of Control, 제어의 역행)

객체 제어 방식

- 기존 : 필요한 위치에서 개발자가 필요한 객체 생성 로직을 구현했다.

- IoC : 객체 생성을 Container에게 위임해 처리한다. 객체지향 언어에서 Object 간의 연결 관계를 런타임에 결정한다.

IoC 사용에 따른 장점

- 객체 간의 결합도를 떨어뜨릴 수 있다. 객체 간 결합도가 높으면 해당 클래스가 유지보수될 때 그 클래스와 결합된 다른 클래스도 같이 유지보수돼야할 가능성이 높아진다.

 

IoC 유형

1.  DL : Dependency Lookup -> JNDL Lookup

2.  DI : Dependency Injection -> 1) Setter Injection, 2) Constructor Injection, 3) Method Injection

     * Spring에서는 주로 3)방법을 사용한다.

Dependency Lookup

- 컨테이너가 lookup context를 통해서 필요한 Resource나 Object를 얻는 방식

- JNDI 이외의 방법을 사용한다면 JNDI 관련 코드를 오브젝트 내에서 일일이 변경해줘야 한다.

- Lookup한 Object를 필요한 타입으로 캐스팅해야한다.

- Naming Exception을 처리하기 위한 로직이 필요하다.

- 주로 Connection Pool을 얻어올 때 사용한다. (밑의 예시 참고)

//FactoryDao.java
public Connection getConnection() throws SQLException {
	try {
		Context context = new InitialContext();
		Context rootContext = (Context) context.lookup("java:comp/env");
		DataSource dataSource = (DataSource) rootContext.lookup("jdbc/____");
		return dataSource.getConnection();
	} catch (NamingException e) {
		e.printStackTrace();
	}
	return null;
}
<!-- META-INF/context.xml -->
<Context>
	<Resource name="jdbc/____" auth="Container" type="javax.sql.DataSource" 
			maxTotal="100" maxIdle="30" maxWaitMillis="10000" 
			username="_____" password="____" driverClassName="com.mysql.cj.jdbc.Driver" 	
			url="jdbc:mysql://localhost:3306/_____?serverTimezone=UTC&amp;useUniCode=yes&amp;characterEncoding=UTF-8"/> 
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>

JNDI

- 필요한 자원을 미리 key-value 쌍으로 저장한 후 필요할 때 키를 이용해 값을 얻는 방법이다.

 

Dependency Injection

- Object에 lookup코드를 사용하지 않고 컨테이너가 직접 의존구조를 Object에 설정할 수 있도록 지정하는 방식

- Object가 컨테이너의 존재여부를 알 필요 없다.

- Lookup 관련된 코드들이 Object 내에서 사라진다.

- Spring에서의 DI글은 [이 글]에 정리했다.

 

IoC Container

- 오브젝트의 생성과 관계설정, 사용, 제거 등의 작업을 애플리케이션 코드 대신 독립된 컨테이너가 담당한다.

- 컨테이너가 코드 대신 오브젝트에 대한 제어권을 가지고 있어 IoC라고 부른다.

- 그래서 스프링 컨테이너를 IoC컨테이너라고 부르기도 한다.

- 스프링에서 IoC를 담당하는 컨테이너에는 BeanFactory, ApplicationContext가 있다.

 

Spring DI Container

- Spring DI Container가 관리하는 객체를 Bean이라고 하고, 이 빈들의 라이프사이클을 관리하는 의미로 BeanFactory라고 한다.

- BeanFactory에 여러 가지 컨테이너 기능을 추가하여 ApplicationContext라고 한다.

 

더보기

Container

- 객체의 생성, 사용, 소멸에 해당하는 라이프사이클을 담당

- 라이프사이클을 기본으로 애플리케이션 사용에 필요한 주요 기능을 제공

Container 기능

- 라이프사이클 관리

- Dependency 객체 제공

- Thread 관리

- 기타 애플리케이션 실행에 필요한 환경

Container 필요성

- 비즈니스 로직 외에 부가적인 기능에 대해서 독립적으로 관리되도록 한다.

- 서비스 look up이나 Configuration에 대한 일관성을 갖기 위한다.

- 서비스 객체를 사용하기 위해 각각 Factory 또는 Singleton 패턴을 직접 구현하지 않아도 된다.

 

객체 간 결합도를 낮추는 단계

1. 강한 결합

클래스 호출 방식. 클래스 내에 선언과 구현이 모두 되어있기 때문에 다양한 형태로 변화가 불가능하다. 

public class HomeController{
	private KorServiceImpl korService = new KorServiceImpl();
	private EngServiceImpl engService = new EngServiceImpl();
}

2. 다형성 이용

인터페이스 호출 방식. 구현 클래스 교체가 용이해 다양한 형태로 변화 가능하다.

하지만 인터페이스 교체 시 호출 클래스도 수정해야한다.

public class HomeController{
	private CommonService korService = new KorServiceImpl();
	private CommonService engService = new EngServiceImpl();
}

3. Factory 이용

팩토리 호출 방식. 팩토리가 구현 클래스를 생성하므로 클래스는 팩토리를 호출한다.

인터페이스 변경 시 팩토리만 수정하면 되므로 호출 클래스에는 영향을 미치지 않는다.

하지만 클래스에 팩토리를 호출하는 소스가 들어가야한다. 그것 자체가 팩토리에 의존함을 의미한다.

public class HomeController{
	private CommonService korService = ServiceFactory.getKorServiceImpl();
	private CommonService engService = ServiceFactory.getEngServiceImpl();
}

4. Assembler 이용

IoC 호출 방식. 팩토리 패턴의 장점을 더하여 어떤 것에도 의존하지 않는 상태가 된다.

실행시점에 클래스 간의 관계가 형성된다.

<!-- context.xml -->
<bean id="korService" class="com.___.___.service.KorServiceImpl"/>
<bean id="engService" class="com.___.___.service.EngServiceImpl"/>
public class HomeController{
	ApplicationContext context = new ClassPathXmlApplicationContext("context.xml주소");
	private CommonService korService = context.getBean("korService", KorService.class);
	private CommonService engService = context.getBean("engService", EngService.class);
}

'기록 > BACKEND' 카테고리의 다른 글

[Spring] DI  (0) 2022.04.20
[Spring] JNDI 설정하기  (0) 2022.04.19
[Spring] DI 주입하기 - java  (0) 2022.04.16
[Spring] DI 주입하기 - xml  (0) 2022.04.15
[WEB] 파라미터와 어트리뷰트  (0) 2022.04.04

댓글