2013/10/30 - [Web/Spring] - 스프링(Spring) DI(Dependency Injection) - #1


1. 빈 객체 범위

- 스프링은 기본적으로 하나의 빈 설정에 대해 한 개의 객체만을 생성

- 스프링 컨테이너 내에서 빈 객체는 싱글톤(클래스 차원에서의 싱글톤의 의미는 아님)

- 빈 객체의 범위를 지정해서 객체 생성 여부 지정




1.1. 빈 범위 설정

- <bean> 태그의 scope 속성을 이용해서 빈의 범위를 설정

- singleton : 스프링 컨테이너에 한 개의 빈 객체만 존재 (기본값)

- prototype : 빈을 사용할 때 마다 객체를 생성

- request : HTTP 요청 마다 빈 객체를 생성 (WebApplicationContext 에서만 적용 가능)

- session : HTTP 세션 마다 빈 객체를 생성 (WebApplicationContext 에서만 적용 가능)

- global-session : 글로벌 HTTP 세션에 대해 빈 객체를 생성 (포틀릿을 지원하는 컨텍스트에 대해서만 적용 가능)

// ScopeTest.java

package com.tistory.gangzzang.scope;

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

public class ScopeTest {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("com/tistory/gangzzang/scope/beans.xml");
		
		MemberDTO memberDTO_1 = (MemberDTO) context.getBean("memberDTO");
		MemberDTO memberDTO_2 = (MemberDTO) context.getBean("memberDTO");
		
		if (memberDTO_1 == memberDTO_2)
			System.out.println("같은 객체");
		else
			System.out.println("다른 객체");
		
		MemberDTO memberDTO1_1 = (MemberDTO) context.getBean("memberDTO1");
		MemberDTO memberDTO1_2 = (MemberDTO) context.getBean("memberDTO1");
		
		if (memberDTO1_1 == memberDTO1_2)
			System.out.println("같은 객체");
		else
			System.out.println("다른 객체");
		
		MemberDTO memberDTO2_1 = (MemberDTO) context.getBean("memberDTO2");
		MemberDTO memberDTO2_2 = (MemberDTO) context.getBean("memberDTO2");
		
		if (memberDTO2_1 == memberDTO2_2)
			System.out.println("같은 객체");
		else
			System.out.println("다른 객체");
	} // main
} // ScopeTest

/*
 * 실행결과
 * 
 * 같은 객체
 * 같은 객체
 * 다른 객체
 */ 




	

	
	
	

1.2. 서로 다른 범위 빈에 대한 의존 처리

- 생명주기가 더 긴 객체의 의존 객체로 설정되는 경우<aop:scoped-proxy> 태그를 사용하여 범위를 적용

<aop:scoped-proxy> 태그 : 해당 객체에 접근 할 때 마다 새로운 객체를 생성

- <aop:scoped-proxy> 태그 사용 준비 : CGLIB 라이브러리 추가, aop 네임스페이스 및 스키마 위치 지정

// ScopeTest2.java

package com.tistory.gangzzang.scope2;

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

public class ScopeTest2 {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("com/tistory/gangzzang/scope2/beans.xml");
		
		Play play = (Play) context.getBean("play");
		play.execute();
		play.execute();
		play.execute();
		
		System.out.println("\n----------------------------------------------------------------------------\n");
		
		Soccer soccer = (Soccer) context.getBean("soccer");
		soccer.play();
		soccer.play();
		soccer.play();
		
		System.out.println("\n----------------------------------------------------------------------------\n");
		
		Baseball baseball = (Baseball) context.getBean("baseball");
		baseball.play();
		baseball.play();
		baseball.play();
	} // main
} // ScopeTest2

/*
 * 실행결과
 * 
 * 축구 : com.tistory.gangzzang.scope2.Soccer@9dec900
 * 야구 : com.tistory.gangzzang.scope2.Baseball@2520fb16
 * 축구 : com.tistory.gangzzang.scope2.Soccer@9dec900
 * 야구 : com.tistory.gangzzang.scope2.Baseball@18447465
 * 축구 : com.tistory.gangzzang.scope2.Soccer@9dec900
 * 야구 : com.tistory.gangzzang.scope2.Baseball@36359f55
 * 
 * ----------------------------------------------------------------------------
 * 
 * 축구 : com.tistory.gangzzang.scope2.Soccer@7a6fa140
 * 축구 : com.tistory.gangzzang.scope2.Soccer@7a6fa140
 * 축구 : com.tistory.gangzzang.scope2.Soccer@7a6fa140
 * 
 * ----------------------------------------------------------------------------
 * 
 * 야구 : com.tistory.gangzzang.scope2.Baseball@36c3af8c
 * 야구 : com.tistory.gangzzang.scope2.Baseball@693a2c6a
 * 야구 : com.tistory.gangzzang.scope2.Baseball@6a3a191e
 */



	
	
	
		
	
	
	
		
		
	


// Play.java

package com.tistory.gangzzang.scope2;

public class Play {
	private Soccer soccer;
	private Baseball baseball;

	public void setSoccer(Soccer soccer) {
		this.soccer = soccer;
	}

	public void setBaseball(Baseball baseball) {
		this.baseball = baseball;
	}

	public void execute() {
		soccer.play();
		baseball.play();
	}
} // Play
// Baseball.java

package com.tistory.gangzzang.scope2;

public class Baseball {
	public void play() {
		System.out.println("야구 : " + toString());
	}
} // Baseball
// Soccer.java

package com.tistory.gangzzang.scope2;

public class Soccer {
	public void play() {
		System.out.println("축구 : " + toString());
	}
} // Soccer




2. 라이프 사이클

- 스프링은 빈 객체의 생성, 초기화 및 소멸 처리 라이프 사이클을 갖게 되며 추가적인 단계를 제공




2.1. 빈 객체의 라이프 사이클

- 빈 객체의 라이프 사이클은 빈 클래스가 구현한 인터페이스에 따라 달라짐

- 라이프 사이클과 관련된 인터페이스가 다수 존재

모두 사용되지는 않음, 직접적으로 구현하는 경우도 드뭄

- 객체를 초기화하고 검증하는 과정에서 스프링 제공 라이프 사이클을 이용하는 것이 편리





* BeanFactory 빈 라이프 사이클


- 배경색이 표시된 단계는 빈 클래스가 아닌 특수 빈을 통해 처리

- [인터페이스.메서드명] 단계는 빈 클래스가 지정한 인터페이스를 구현했을 경우 메서드 호출 의미


- 1. 빈 객체 생성 : 인스턴스화 > 프로퍼티 값 할당

- 2. BeanNameAware : setBeanName() 메서드 호출, 빈 객체 이름 설정

- 3. BeanFactoryAware : setBeanFactory() 메서드 호출, 빈 객체 팩토리 설정(XmlBeanFactory)

- 4. 초기화 전처리 : 초기화 전의 빈에 대한 처리

- 5. init-method : 초기화 메서드 실행

- 6. InitializingBean : afterPropertiesSet() 메서드 호출, 프로퍼티 설정 완료

- 7. 초기화 후처리 : 초기화 후의 빈에 대한 처리

- 8. 빈 객체 사용 : BeanFactory.getBean() 메서드를 호출하여 사용

- 9. destroy() : XMlBeanFactory 클래스는 빈 객체 제거를 위한 destorySingleton(beanName), destoryBean(beanName, BeanInstance) 등의 메서드를 제공, 이들 메서드를 호출하면 빈객체 사용 이후 단계 수행

- 10. destroy-method : 종료 메서드 실행



* ApplicationContext 빈 라이프 사이클


- BeanFactory 라이프 사이클에서 자원 및 메시지 처리, 이벤트 처리 등 추가적인 기능 제공 단계 추가


2.2. BeanFactory 라이프사이클 제거 단계 처리

- BeanFactory : XmlBeanFactory는 빈 객체를 컨테이너에서 제거할 때 DisposableBean.destroy()와 커스텀destroy 메서드를 실행

- XmlBeanFactory.removeBeanDefinition(String beanName) : 이름이 beanName인 빈 객체를 컨테이너에서 제거할 때 사용되는 메서드(제거 단계의 라이프 사이클 메서드를 실행)


2.3. ApplicationContext 라이프사이클 제거 단계 처리

- AbstractApplicationContext 클래스를 상속받는데, XmlBeanFactory 클래스와 달리 개별 빈을 제거하는 기능을 제공하지 않음, 대신 컨테이너를 종료시켜주는 close() 메서드를 제공

- AbstractApplicationContext .close() : 컨테이너에 등록된 모든 빈 객체의 제거 처리 메서드가 실행

AbstractApplicationContext .registerShutdownHook() : JVM이 종료될 때 ApplicationContext를 종료하는 작업을 수행


2.4. BeanNameAware 인터페이스


public interface BeanNameAware {
	void setBeanName(String beanName);
}


- 설정파일에서 id 속성이나 name 속성을 통해 식별값을 지정한 이름은 스프링 컨테이너가 내부적으로 빈 객체를 식별하는데 사용

org.springframework.beans.factory.BeanNameAware : 빈 객체가 자기 자신의 이름을 알아야 하는 경우에 사용

- BeanNameAware 인터페이스를 구현할 경우 setBeanName() 메서드를 호출하여 빈객체의 이름을 전달


2.5. BeanFactoryAware 인터페이스, ApplicationContextAware 인터페이스


public interface BeanFactoryAware {
	public void setBeanFactory(BeanFactory factory) throws BeansException;
}

public interface ApplicationContextAware {
	public void setApplicationContext(ApplicationContext context) throws BeansException;
}


- 빈 객체가 필요한 객체를 스프링 컨테이너로부터 직접 검색해야하는 경우 사용

- 빈 객체에서 ApplicationContext가 제공하는 자원 및 메시지 관련 기능을 사용하고 싶은 경우 사용

- org.springframework.beans.factory.BeanFactoryAware : BeanFactory를 빈에 전달할 때 사용

- org.springframework.context.ApplicationContextAware : ApplicationContext를 빈에 전달할 때 사용


2.6. InitializingBean 인터페이스


public interface InitializingBean {
	public void afterPropertiesSet() throws Exception;
}


- org.springframework.beans.factory.InitializingBean : 객체 생성, 프로퍼티 초기화, 컨테이너 관련 설정 완료 후에 호출되는 메서드를 정의

- afterPropertiesSet() 메서드 : 빈 객체의 프로퍼티가 모두 올바르게 설정 되었는지의 여부를 검사


2.7. DisposableBean 인터페이스


public interface DisposableBean {
	public void destroy() throws Exception;
}


- org.springframework.beans.factory.DisposableBean : 빈 객체를 컨테이너에서 제거하기 전에 인터페이스에 정의 된 메서드를 호출하여 빈 객체가 자원을 반납


2.8. 커스텀 초기화 및 소멸 메서드

- <bean> 태그의 init-method 속성과 destroy-method 속성을 통해 빈 객체를 초기화하고 제거할 때 호출될 메서드를 지정

// Init_DestoryTest.java

package com.tistory.gangzzang.custom_init_destroy;

import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

public class Init_DestoryTest {
	public static void main(String[] args) {
		
		Resource resource = new ClassPathResource("com/tistory/gangzzang/custom_init_destroy/beans.xml");
		XmlBeanFactory beanFactory = new XmlBeanFactory(resource);
		Init_Destory init_Destory1 = (Init_Destory) beanFactory.getBean("init_Destory");
		init_Destory1.mainMethod();
		beanFactory.removeBeanDefinition("init_Destory");
		
		AbstractApplicationContext context = new ClassPathXmlApplicationContext("com/tistory/gangzzang/custom_init_destroy/beans.xml");
		Init_Destory init_Destory2 = (Init_Destory) context.getBean("init_Destory");
		init_Destory2.mainMethod();
		context.close();
	} // main
} // Init_DestoryTest

/*
 * 실행결과
 * 
 * 시작 
 * 메인 
 * 끝 
 * 
 * 시작
 * 메인
 * 끝
 */




	

// Init_Destory.java

package com.tistory.gangzzang.custom_init_destroy;

public class Init_Destory {
	public void start() {
		System.out.println(" 시작 ");
	}
	
	public void mainMethod() {
		System.out.println(" 메인 ");
	}
	
	public void stop() {
		System.out.println(" 끝 ");
	}
} // Init_Destory




3. 외부 설정 프로퍼티

- PropertyPlaceholderConfigurer 클래스를 빈으로 등록하면 외부의 프로퍼티 파일에 저장된 정보를 스프링 설정 파일에서 사용가능

두개 이상의 Property PlaceholderConfigurer 빈을 설정할 수 없음 (이 경우 첫번째 설정이 적용 됨)

- 한개 이상의 프로퍼티 파일을 지정하려면 <list> 태그를 이용하여 지정

// PropertyTest.java

package com.tistory.gangzzang.property;

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

public class PropertyTest {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("com/tistory/gangzzang/property/beans.xml");
		MemberDTO memberDTO = (MemberDTO) context.getBean("memberDTO");
		
		System.out.println(memberDTO.getName());
		System.out.println(memberDTO.getPwd());
	} // main
} // PropertyTest

/*
 * 실행결과
 * 
 * Gz
 * 1234
 */



	
	
		
	

	
		
		
	



3.1. <context:property-placholder> 태그를 사용한 외부 설정 프로퍼티 사용

- context 접두어에 대한 네임스페이스와 XML 스키마 경로 지정

- 여러개의 프로퍼티 파일을 사용하려면 각 프로퍼티 파일을 콤마로 구분





	
	
	
		
		
	



4. 컨테이너 간 계층

- 컨테이너 간 자식-부모 계층 구조를 가질 수 있음

- 자식 컨테이너는 부모 컨테이너에 정의된 빈 객체에 접근 가능

- 부모 컨테이너는 자식 컨테이너에 정의된 빈 객체에 접근 불가

+ Recent posts