context 네임스페이스 설정

어노테이션 설정을 하려면 스프링 설정파일의 루트 엘리먼트인 <beans>에 Context 관련 네임스페이스와 스키마 문서의 위치를 등록해야 한다.

 

xmlns:context="http://www.springframework.org/schema/context" 

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd"

<?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"
	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-4.2.xsd">
	
</beans>

 

컴포넌트 스캔(component-scan) 설정

스프링 설정파일에 사용할 객체들을 <bean> 등록하지 않고 자동으로 생성하려면 <context:component-scan/> 엘리먼트를 사용해야 한다.

이 설정을 추가하면 스프링 컨테이너는 클래스 path에 있는 클래스들을 스캔하여 @Component가 설정된 클래스들을 자동으로 객체 생성한다.

<?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"
	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-4.2.xsd">
	
	<!-- Context nameSpace 추가, 해당 Package class에 @Component 선언해야함! -->
	<context:component-scan base-package="polymorphism"></context:component-scan>
</bean>

 

@Component

스프링 설정파일에 <context:component-scan> 설정을 했다면. 사용할 객체의 클래스 선언부 위에 @Component 를 설정하면 된다.

package polymorphism;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class LgTV implements TV {
	public LgTV() {
		System.out.println("===> LgTV 객체 생성");
	}
}

 

그러나 위에 코드는 클라이언트 프로그램에서 LgTV 객체를 요청할 수는 없다.

클라이언트가 스프링 컨테이너가 생성한 객체를 요청하려면, 요청할 때 사용할 아이디나 이름이 반드시 설정되야함!

→ @Component("tv")

public class TVUser {

	public static void main(String[] args) {
		// 1. Spring 컨테이너를 구동한다.
		AbstractApplicationContext factory = new GenericXmlApplicationContext("root-context.xml");

		// 2. Spring 컨테이너로부터 필요한 객체를 요청(Lookup)한다.
		TV tv = (TV) factory.getBean("tv");
    }
}
package polymorphism;

import javax.annotation.Resource;
import org.springframework.stereotype.Component;

@Component("tv")
public class LgTV implements TV {
	public LgTV() {
		System.out.println("===> LgTV 객체 생성");
	}
}

 

@Autowired

@Autowired 는 생성자나 메소드, 멤버변수 위에 모두 사용할 수 있음

주로 멤버변수 위에 선언하여 사용함

스프링 컨테이너는 멤버 변수 위에 붙은 @Autowired 를 확인하는 순간 해당 변수의 타입을 체크한다. 그리고 그 타입의 객체가 메모리에 존재하는지를 확인한 후에, 그 객체를 변수에 주입한다.

 

만약 @Autowired 가 붙은 객체가 메모리에 없다면 스프링 컨테이너는 NoSuchBeanDefinitionException을 발생시킨다.

package polymorphism;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("tv")
public class LgTV implements TV {
	@Autowired
	private Speaker speaker;
	
	public LgTV() {
		System.out.println("===> LgTV 객체 생성");
	}

	public void powerOn() {
		System.out.println("LgTV---전원 켠다.");
	}

	public void powerOff() {
		System.out.println("LgTV---전원 끈다.");
	}
	
	public void volumeUp() {
		speaker.volumeUp();
	}

	public void volumeDown() {
		speaker.volumeDown();
	}
}
package polymorphism;

public interface Speaker {
	void volumeUp();
	void volumeDown();
}
package polymorphism;

import org.springframework.stereotype.Component;

@Component("sony")
public class SonySpeaker implements Speaker{
	public SonySpeaker() {
		System.out.println("===> SonySpeaker 객체 생성");
	}

	public void volumeUp() {
		System.out.println("SonySpeaker---소리 올린다.");
	}

	public void volumeDown() {
		System.out.println("SonySpeaker---소리 내린다.");
	}
}

 

@Qualifier

문제는 의존성 주입 대상이 되는 Speaker 타입의 객체가 두개 이상일 때 발생한다.

만약 SonySpeaker와 AppleSpeaker 객체가 모두 메로리에 생성되어 있는 상황이라면, 스프링 컨테이너는 어떤 객체를 할당할지 스스로 판단할 수 없어서 에러를 발생시킨다.

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: (생략~)
expected single matching bean but found 2 : apple, sony

위와 같은 상황일 때, @Qualifier 어노테이션을 이용하면 의존성 주입될 객체의 아이디나 이름을 지정할 수 있는데, 이때 Speaker 객체의 이름(sony, apple) 중 사용할 하나를 지정한다.

 

package polymorphism;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("tv")
public class LgTV implements TV {
    @Autowired
    @Qualifier("sony")
    private Speaker speaker;
	
	public LgTV() {
		System.out.println("===> LgTV 객체 생성");
	}

	public void powerOn() {
		System.out.println("LgTV---전원 켠다.");
	}

	public void powerOff() {
		System.out.println("LgTV---전원 끈다.");
	}
	
	public void volumeUp() {
		speaker.volumeUp();
	}

	public void volumeDown() {
		speaker.volumeDown();
	}
}

 

어노테이션과 XML 설정 병행하여 사용하기

변경되지 않는 객체는 어노테이션으로 설정하고, 변경될 가능성이 있는 객체는 XML 설정으로 사용한다.

 - 변경되지 않는 객체 : LgTv.java

 - 변경될 가능성이 있는 객체 : SonySpeaker.java, AppleSpeaker.java

package polymorphism;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("tv")
public class LgTV implements TV {
    @Autowired
    private Speaker speaker;
	
	public LgTV() {
		System.out.println("===> LgTV 객체 생성");
	}

	public void powerOn() {
		System.out.println("LgTV---전원 켠다.");
	}

	public void powerOff() {
		System.out.println("LgTV---전원 끈다.");
	}
	
	public void volumeUp() {
		speaker.volumeUp();
	}

	public void volumeDown() {
		speaker.volumeDown();
	}
}
package polymorphism;

public class SonySpeaker implements Speaker{
	public SonySpeaker() {
		System.out.println("===> SonySpeaker 객체 생성");
	}

	public void volumeUp() {
		System.out.println("SonySpeaker---소리 올린다.");
	}

	public void volumeDown() {
		System.out.println("SonySpeaker---소리 내린다.");
	}
}
package polymorphism;

public class AppleSpeaker implements Speaker {
	public AppleSpeaker() {
		System.out.println("===> AppleSpeaker 객체 생성");
	}

	public void volumeUp() {
		System.out.println("AppleSpeaker---소리 올린다.");
	}

	public void volumeDown() {
		System.out.println("AppleSpeaker---소리 내린다.");
	}
}
<?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"
	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-4.2.xsd">
	
	<!-- LgTv는 어노테이션으로, Speaker는 <bean> xml 설정으로 SonySpeaker 주입 -->
	<context:component-scan base-package="polymorphism"></context:component-scan>
	<bean id="sony" class="polymorphism.SonySpeaker"></bean>
 </beans>

 

어노테이션, <bean>설정 주의사항

직접 개발한 클래스는 어노테이션을 사용할 수도 있고, <bean>를 등록하여 XML 설정을 할 수도 있다.

하지만 라이브러리 형태로 제공되는 클래스는 반드시 XML 설정을 통해서만 사용할 수 있음!

 

예를들어 commons-dbcp-1.4.jar 라이브러리를 이용하여 DB연결을 할 때 XML 설정을 통해 사용해야 한다.

 

정의

스프링 설정파일에 class를 등록하려면 <bean> 엘리먼트를 사용한다.

이때 id와 class 속성을 사용하는데, id는 생략 가능하다.

 

<bean> 엘리먼트 속성

id 속성 : 자바의 식별자 작성 규칙을 따름(CamelCase)

name 속성 : 자바의 식별자 작성 규칙이 아닌, 특수기호가 포함된 아이디를 <bean>으로 지정할 때 사용함

 

init-method : 스프링 컨테이너는 스프링 설정파일에 등록된 클래스를 객체 생성할 때 디폴트 생성자를 호출한다.

객체를 생성한 후에 멤버변수 초기화 작업이 필요할 때, init-method 속성을 class파일에 사용한다.

즉 <bean>에 등록된 객체가 생성된 후 init-method로 지정된 "initMethod()"를 호출한다. 

// root-context.xml (스프링 설정파일)
<bean id="tv" class="polymorphism.SamsungTV" init-method="initMethod"></bean>
package polymorphism;

public class SamsungTV implements TV {
	public void initMethod(){
    	System.out.println("객체 초기화 작업");
    }
}

 

destroy-method : 스프링 컨테이너가 객체를 삭제하기 직전에 호출될 메소드를 지정할 수 있다.

// root-context.xml (스프링 설정파일)
<bean id="tv" class="polymorphism.SamsungTV" destroy-method="destroyMethod"></bean>
package polymorphism;

public class SamsungTV implements TV {
	public void destroyMethod(){
    	System.out.println("객체 삭제 전에 처리할 로직 처리");
    }
}

 

lazy-init : 스프링 컨테이너가 구동되면, 구동되는 시점에 스프링 설정 파일에 등록된 <bean>들을 생성하는 즉시 로딩 방식으로 동작한다.

자주 사용되지 않으면서 메모리를 많이 차지하여 시스템에 부담을 주는 경우가 있기 때문에, 해당 <bean>이 사용되는 시점에 객체를 생성하도록 lazy-init 속성을 사용한다.

즉 클라이언트가 요청하는 시점에 생성한다.

// root-context.xml (스프링 설정파일)
<bean id="tv" class="polymorphism.SamsungTV" lazy-init="true"></bean>

 

scope="singleton" : 클래스를 하나만 생성하여 유지하고 싶을때 싱글톤 패턴을 사용하는데, 스프링 컨테이너도 이러한 기능을 scope 속성을 통하여 제공한다.

scope 속성값은 기본이 싱글톤이다. (=값을 생략하면 싱글톤으로 적용됨)

// root-context.xml (스프링 설정파일)
<bean id="tv" class="polymorphism.SamsungTV" scope="singleton"></bean>

 

scope="prototype" : 반대로 스프링 컨테이너가 해당 <bean>을 요청될 때마다 매번 새로운 객체를 생성하여 반환할 땐 아래와 같이 사용함.

// root-context.xml (스프링 설정파일)
<bean id="tv" class="polymorphism.SamsungTV" scope="prototype"></bean>

 

에러 내용

Error occured processing XML 'Are you using a JRE with an outdated version of '. See Error Log for more details

 

발생 원인

Spring root-context.xml 파일을 생성하자 위와 같은 오류가 발생하였다.

 

해결 방법

아래 사진과 같이 프로젝트에서 마우스 오른쪽 클릭 - Spring - Remove Spring Project Nature 클릭하면 해결된다.

+ Recent posts